Deploying datastores for IoT & Big Data: mongoDB on K8s. Part 3

🎬 Introduction

This blog post series is intended to give an overview of how datastores capable of supporting high volumes of data from IoT devices and Big Data services can be deployed on Kubernetes. In the first part of this series, the StatefulSet primitive has been used to set up and deploy a mongoDB Replica Set (cluster). In the second part it has been demonstrated how other Kubernetes primitives such as Secret can be applied to secure our initial, dummy deployment. This article of the series explains how to further secure (by enabling client and member mutual TLS authentication based on x509 certificates) and to shard our mongoDB Cluster.

Prerequisites

It is assumed that you already have an up and running K8s environment, such as minikube. All the examples have been developed using minikube on macOS Catalina with VirtualBox.

First of all, a new, clean namespace named shard has to be created to develop this part.

kubectl create namespace shard

đź“ś Enabling client and member authentication based on x509 certificates

Our objective at this stage is to deploy a mongoDB Replica Set with client and member authentication based on x509 certificates (additional details about this architecture can be found here). This Replica Set will be later part of our final mongoDB shard.

After completing successfully these steps, it will only be possible to get access to the mongoDB cluster by presenting the proper client certificates and associated secret keys (i.e. no insecure user/pass anymore) packaged as “keycert” files.

Certificate Generation

First of all the following certificates have to be generated:

  • One certificate for cluster server TLS. Already generated in part 2 of this series.
  • For each member of the Replica Set, one certificate for internal member authentication.
  • One certificate for client authentication. It will be needed as much certificates as clients our database is going to have.

For generating our certificates the steps already explained here have to be followed:

  • Generate a private key
  • Generate a certificate signing request. At this step the most important point is the x509 DN (Distinguished Name) that will be the certificate’s subject. For instance, the DNs that have been used for my deployment are:

    • CN=mongo-db-statefulset-sh1-0.mongo-db-replica-sh1.sharding,OU=Software,O=CanteraFonseca,C=ES for the first member of the Replica Set.
    • CN=mongo-db-statefulset-sh1-1.mongo-db-replica-sh1.sharding,OU=Software,O=CanteraFonseca,C=ES for the second member of the Replica Set.
    • CN=mongo-db-statefulset-sh1-2.mongo-db-replica-sh1.sharding,OU=Software,O=CanteraFonseca,C=ES for the third member of the Replica Set.

    • CN=App1,OU=Applications,O=CanteraFonseca,C=ES for the database client to be used for testing.
  • As the Kubernetes cluster CA is being used to sign our certificates, for each certificate a new certificate signing request K8s manifest has to be generated and approved as explained here. Each certificate has to be retrieved, saved (in PEM format) and finally concatenated with its corresponding private key to create a “keycert” file.

Thus, in the end we will have:

  • 3 “keycert” files (one for each Replica Set member):

    • mongo.cluster.0.keycert
    • mongo.cluster.1.keycert
    • mongo.cluster.2.keycert
  • 1 “keycert” file corresponding to our database testing client:

    • client.keycert
  • the “keycert” file we already generated in part 2 corresponding to the server TLS certificate of the whole cluster:

    • mongo.ext.keycert

Bootstrapping the mongoDB statefulset

Unfortunately, when it comes to certificate-based authentication, mongoDB does not provide any deployment mechanism in one step. Thus, it is needed to perform a two step process. In the first step, bootstrapping step, a mongoDB cluster with no authentication will be run (as we explained in part 1). After configuring the cluster, in the second step, our K8s manifest will be reapplied to set up the final configuration with certificate-based authentication enabled.

For bootstrapping the following steps have to be taken as explained in part 1:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongo-db-statefulset-sh1
  labels:
    mongoDB-replica: "true"
    mongoDB-secured: "false"
    mongoDB-sharding: "true"
  annotations: 
    author: JMCF
  namespace: sharding
spec: 
  selector: 
    matchLabels:
      app: mongoDB-replica-sh1
  serviceName: mongo-db-replica-sh1
  replicas: 3
  template:
    metadata: 
      labels: 
        app: mongoDB-replica-sh1
    spec: 
      terminationGracePeriodSeconds: 10
      containers: 
        - name: mongo-db
          image: mongo:4.2.6
          ports: 
            - containerPort: 27017
              protocol: TCP
          volumeMounts: 
            - mountPath: /data/db
              name: mongo-volume-for-replica                  
          args: 
            - --replSet
            - $(REPLICA_SET_NAME)
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          imagePullPolicy: IfNotPresent
          envFrom: 
            - configMapRef:
                name: mongo-config-sh1
  volumeClaimTemplates: 
    - metadata: 
        name: mongo-volume-for-replica
      spec: 
        accessModes: 
          - ReadWriteOnce
        resources: 
          requests: 
            storage: 100Mi

After the successful deployment of the statefulset above, the next step is to set up the replica set using this script. Once the Replica Set has been set up, the cluster users as per the DNs already defined when certificates were generated have to be created (from the mongo client console) as follows:

db.getSiblingDB("$external").runCommand(
  {
    createUser: "CN=App1,OU=Applications,O=CanteraFonseca,C=ES",
    roles: [
      { role: "readWrite", db: 'test' },
      { role: "userAdminAnyDatabase", db: "admin" },
      { role: "clusterAdmin", db: "admin" }
    ],
    writeConcern: { w: "majority", wtimeout: 5000 }
  }
);

db.getSiblingDB("$external").runCommand(
  {
    createUser: "CN=mongo-db-statefulset-sh1-0.mongo-db-replica-sh1.sharding,OU=Software,O=CanteraFonseca,C=ES",
    roles: [
      { role: "__system", db: "admin" }
    ],
    writeConcern: { w: "majority", wtimeout: 5000 }
  }
);

db.getSiblingDB("$external").runCommand(
  {
    createUser: "CN=mongo-db-statefulset-sh1-1.mongo-db-replica-sh1.sharding,OU=Software,O=CanteraFonseca,C=ES",
    roles: [
      { role: "__system", db: "admin" }
    ],
    writeConcern: { w: "majority", wtimeout: 5000 }
  }
);

db.getSiblingDB("$external").runCommand(
  {
    createUser: "CN=mongo-db-statefulset-sh1-2.mongo-db-replica-sh1.sharding,OU=Software,O=CanteraFonseca,C=ES",
    roles: [
      { role: "__system", db: "admin" }
    ],
    writeConcern: { w: "majority", wtimeout: 5000 }
  }
);

db.getSiblingDB("$external").runCommand(
  {
    createUser: "CN=mongos.sharding,OU=Software,O=CanteraFonseca,C=ES",
    roles: [
      { role: "__system", db: "admin" }
    ],
    writeConcern: { w: "majority", wtimeout: 5000 }
  }
);


db.getSiblingDB("$external").runCommand(
  {
    createUser: "CN=mongo-db-statefulset-sh2-0.mongo-db-replica-sh2.sharding,OU=Software,O=CanteraFonseca,C=ES",
    roles: [
      { role: "__system", db: "admin" }
    ],
    writeConcern: { w: "majority", wtimeout: 5000 }
  }
);

db.getSiblingDB("$external").runCommand(
  {
    createUser: "CN=mongo-db-statefulset-sh2-1.mongo-db-replica-sh2.sharding,OU=Software,O=CanteraFonseca,C=ES",
    roles: [
      { role: "__system", db: "admin" }
    ],
    writeConcern: { w: "majority", wtimeout: 5000 }
  }
);

db.getSiblingDB("$external").runCommand(
  {
    createUser: "CN=mongo-db-statefulset-sh2-2.mongo-db-replica-sh2.sharding,OU=Software,O=CanteraFonseca,C=ES",
    roles: [
      { role: "__system", db: "admin" }
    ],
    writeConcern: { w: "majority", wtimeout: 5000 }
  }
);

db.getSiblingDB("$external").runCommand(
  {
    createUser: "CN=mongos.sharding,OU=Software,O=CanteraFonseca,C=ES",
    roles: [
      { role: "__system", db: "admin" }
    ],
    writeConcern: { w: "majority", wtimeout: 5000 }
  }
);

📌  The command above has to issued against the mongoDB Replica Set member marked as PRIMARY.

In this case we are creating 4 users under the $external database:

  • The user corresponding to our initial testing client which is assigned some admin roles and it is granted explicitly permissions over the test database.
  • One user for each of the Replica Set members. These users are granted a system role.

Now everything is ready to switch our initial bootstrap to a fully authenticated cluster.

Running our final statefulset

After performing the initial bootstrapping we can switch to an authenticated set up as follows:

First of all, we need to create a new K8s Secret that will contain the member certificates (“keycert” files) for authentication:

apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret-sh1
  namespace: sharding
type: Opaque
data:
  tls.keycert: "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBMnd0bzJRdzRZSVlZZFgzaU8wbElnaTJUL0tzVG5nSml6ZHFBdFY4R0V2eFI2OHQzCkhxZkpUYVlUUTduL2tScXZ0a2xzY2RyL1VvSXJJcXBXZ0hzRzcvU2pmQUNEZGMrbm5PQUM4enlDbUFsRnE0b04Kanhya2tZQWsyd0ZkcGtyOER3RzBNN0xXWmtsZDdFb1lJSFN4U2pWQkl0dGJFNXAwWHk5NFZDdE9qSS9oUElZegp3OGhRWDcvYzRPdFJZUlhBZUc3MjhmaC9laWtZY2ZUdWFBNGNOVy9nZzZOeDRWWXBrMHYrRDFWUmFTMVdOdUtzClJTOWQ5MUhOUmI0ZWhwWEN4NmZEUDc5N0E5QmdZM0pHSzJOWUpoaVVja3JKTkdDa1EwRjg5ckpHSHpEaWliTCsKU29mbTFTakkxWWdnQUc2YVZWMDhlTUxVZjdhT1dEWFlmdlFBaVFJREFRQUJBb0lCQURna0EzcGx2R2xZMVJuLwo2cVRoVW5reTcxUDZFT3dWbG5kR1FtaTU4eGVZbmZKK1VvaUQzbjlOU25DNFVqMUJocm1FdGd1MFltNG1PS0lJCjRHVExvMnFLMi8vakxjNWJLNDEwaUswSTNEdlZYSXJydGkvd1o1YTNManNIYlpZNmI4SDA0TmZEUlZvd0FhZVgKRWZuM2pwMERheTlnNDBYeDkxT1NHaGdRaFhCVzBxbFh1VkZaMzFWb29OZHlVOUx1czBvc0EwNCt1SElLOXJGaAoyT1FEbnhIcENtczkwUDBleHlNQUgySDRBOFJUbTZWNGUyZ1FIUCs4UjVKRE5Sd2kvSzJaSTB3VFJ3eTYyWjM0Cml0WVl2d0xtdnRxTlN6NW1KMGRlbEd3MGEvNTd3MlBDbklYaTdOR0d2QytqSWdrZGt1M3Z2MFRHbitKWUNXc3gKQWg5ZEtaRUNnWUVBOHc2cFFIZCtQYnFiMVhRdlo1T1JzM2djYmhNNmxNOWdtUm9Ic2tVOCtDbVhCRU16SHRYcwpxaHFRZHh1NERPZlVhejBIamo0QWplMXNyNjdTcWpidWdGMHZOakdTanpEMndVN0RsWkNEVWZSaEZLUXRWdkk4CjdLb05uZ2Q5aUFWMzhaZXBhbjFJdW5LWC9UVXgxQ3FpOElCWjNRR2RodlZ3bENQMUdHcUUxblVDZ1lFQTVyVm8KdHI2K3R6SW1QQy96ZWlqc0dMRml0bzdoTEdPZUdmeWNXUVQ3blowNlFtZ1hmMVhhRUF5a0JSMGI2RmErV0k1bgovWE03ZWhGSVZDRE9pVzMvRUluOTRSY0pjRXYwaENORDhqVDdPamRycWllaktEa2dTdndDMEZaRVRPaUxSREswClJTcXlWbVdtcTUxcjFpUktyZ0FTeXlKQmlMaC8vTTZMWVRzRkIwVUNnWUFLMXkyUFZZVUk1Y2pMaFdvVDJZNFgKRGhWZWgzY0dhaFZwM3JKWExpVmhBQ0hmSzh3YzVQZXdRbzBNOHV5TGpzOTNsUHBBU3QybGR1QnhHWUFGM1h0WAp1RkJCdjRaRTRxOHV3ZitSTFNmZVFPTVBrNTcrRU1ITTRHekpEcFozdVo2MjVNZkdteDNpU3ZnaWIvdnY5WkxjCjNTeWs0Y3lQMTJTVkJ1R0luRCtlZlFLQmdRQ1MzYmtqWEpvY0ZSaXlCL1IvTjczVW1sZTB6NUFZcWZIanFTUCsKcDJWbUdNa1ZyUjRJT2FidndKeEpoUlpXK2FHQ3ptVDB1MzZKWHFja3B4M1Q3dW9JcFUreEV2RTNRNk1NMjBaTgowZHg4V3Z0Mi9uU25EbmE0UldXbEtzV2dFQWxZQ004cG1OeWVrMmRlcUlBVmVsVHdINnZYRkorVFlhQllWMFB6ClNaY1I0UUtCZ0VYZmhTVHV3cEgwbEgyQXNWMlAxUExTZU1rRVI3Rm9IZndpWmhPT1h6VGdNT2lVdjd4UjQxTmMKeG9WcWJiQnNyVitkcjQzSW1sYWFuQzBEeWZua2g0Zlp2Uld4OUJLTG05SGhDbHZSd2ptZzYxaHpzTDZGNERaVgpXSGFHZktRY1RKQnNWaHl3UFRMQmZZM1gybWZjTHdsbW90a3ludWIreDlqTE12WUt3UmZyCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlEN1RDQ0F0V2dBd0lCQWdJUVAwRDFQeVNZbDZQTWp2eExGUTl1aURBTkJna3Foa2lHOXcwQkFRc0ZBREFWCk1STXdFUVlEVlFRREV3cHRhVzVwYTNWaVpVTkJNQjRYRFRJd01USXlOREV5TVRJd01Gb1hEVEl4TVRJeU5ERXkKTVRJd01Gb3dPREVMTUFrR0ExVUVCaE1DUlZNeEZ6QVZCZ05WQkFzVERrTmhiblJsY21GR2IyNXpaV05oTVJBdwpEZ1lEVlFRREV3ZHRiMjVuYjBSQ01JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBCjJ3dG8yUXc0WUlZWWRYM2lPMGxJZ2kyVC9Lc1RuZ0ppemRxQXRWOEdFdnhSNjh0M0hxZkpUYVlUUTduL2tScXYKdGtsc2Nkci9Vb0lySXFwV2dIc0c3L1NqZkFDRGRjK25uT0FDOHp5Q21BbEZxNG9Oanhya2tZQWsyd0ZkcGtyOApEd0cwTTdMV1prbGQ3RW9ZSUhTeFNqVkJJdHRiRTVwMFh5OTRWQ3RPakkvaFBJWXp3OGhRWDcvYzRPdFJZUlhBCmVHNzI4ZmgvZWlrWWNmVHVhQTRjTlcvZ2c2Tng0VllwazB2K0QxVlJhUzFXTnVLc1JTOWQ5MUhOUmI0ZWhwWEMKeDZmRFA3OTdBOUJnWTNKR0syTllKaGlVY2tySk5HQ2tRMEY4OXJKR0h6RGlpYkwrU29mbTFTakkxWWdnQUc2YQpWVjA4ZU1MVWY3YU9XRFhZZnZRQWlRSURBUUFCbzRJQkZEQ0NBUkF3RGdZRFZSMFBBUUgvQkFRREFnV2dNQXdHCkExVWRFd0VCL3dRQ01BQXdnZThHQTFVZEVRU0I1ekNCNUlKS2JXOXVaMjh0WkdJdGMzUmhkR1ZtZFd4elpYUXQKYzJneExUQXViVzl1WjI4dFpHSXRjbVZ3YkdsallTMXphREV1YzJoaGNtUnBibWN1YzNaakxtTnNkWE4wWlhJdQpiRzlqWVd5Q1NtMXZibWR2TFdSaUxYTjBZWFJsWm5Wc2MyVjBMWE5vTVMweExtMXZibWR2TFdSaUxYSmxjR3hwClkyRXRjMmd4TG5Ob1lYSmthVzVuTG5OMll5NWpiSFZ6ZEdWeUxteHZZMkZzZ2twdGIyNW5ieTFrWWkxemRHRjAKWldaMWJITmxkQzF6YURFdE1pNXRiMjVuYnkxa1lpMXlaWEJzYVdOaExYTm9NUzV6YUdGeVpHbHVaeTV6ZG1NdQpZMngxYzNSbGNpNXNiMk5oYkRBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQWVCVWdSTnltQ0dSRmR3VllDVk9OClVCd2ZtOGgxazJGYnZnV2ZBT0d3K0NsYTdMWE5kK011alR6MEhpcTg1T3ArY1J0TzM3bjFRcWUzQUJmaFdPV0oKdkNPV1Ixb21PZWx6NUEzK2hqNERuSmQyWEFQZnFkNjBubnZsL0MxUlhZeXp6ZHc5VFRua0hLTGVmWWZUMHJtVwpNeTkvanNBODBhNnhOekNLOFkwS09yY210OCt3N1Z4OUZyMGxybnl5TVBqMURnQU1EK1ZXenRuVFV1MGRPSllOCktBUTJ4ZXkybkRpY3FOTGRYbkQwQk10ZGlXZE1YS0NGeFQ2RVhhOStiSjlYRkd6dHp0dW9qcnI3ZnlsdkRZOUcKcDljQWpJYnUvMzJEUXBRcC9HNXMzMlhia2JFN1BQd2xSaHpnVXk3K3g1Vi9ueFE5Yk9LaWgrTmh5YkdSVVlMUgpJdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
  tls.cluster.0.keycert: "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBNEc4L0IyTm5Xd3pNaVZQbzFzWGluWXVwcVVSZ296VkNobk1BSHNjc1hUN1pwWkE5Ck1FNjBwRG1FNFVIMnN5aDJKOUF2REhXc3lnRXRqZkpxbUlVZUVlMUZKWlAxdUVrS2dOUUMxMTZNOWcrTUdrYlUKeWljOHhFZy9UZGY2ZGV0Z05IRVFkUXUrY2U2ZTIzY3Y1dWFqOVQwT2h0QjR3N2Qyc0ZPSTFheGZiUWFzY0F4OApQZ3JJMkxVZERTWHdUWjJnWjl5RysyR3NjZ3YyWHRGZ3VUaWJUb3NidmZNdVlIcVVvQ0F3Y0NESVVOeVFNdG50Cm9kUmhES2dUUi95UUNQVkFIZlpKQm13eEQzWGk2by9CcklML0NPVE1EcGcvVlpaL3FqenlUZ1d6ejgyMk90cUYKdkt2MWpqalF0QjZNQ2NUcFJhWGVHbEFpMnJ6SnFUSHpjaWpwMXdJREFRQUJBb0lCQVFDVXRFRC94VFl6RnN6aQo1TXp1bVJqb3FDUVcraTVKbFQxcDFnS3JZZTZjTGN1SnJvTk1ZYW5BOGplQUJQUFBpeXlXZnBMZDM0NUlIZld3CkNvSGtZcmNreTZBNElNdjdlYkhTNENhdHlvRDlmQm1wUTJzME1rRktFRkNaWkZRWUU0ZWYxNVkrNXpRZFN5ekkKWHpWRytXU0RWaHdzNlM1TEIyRkZ2V041cUFkbU5YcWZIUHBPeW54K2pQa2t5UG5PK3llaVhMODZXWDhhT3FBVApOOEVxWGRnNi9hNFh2b1dNREZnTjlITXRWRWJXcnkrNzBVWHlRc0kzQndMTjRQdFIxdll2Yk0vQlhOWnA0amxOCmhENHFJYUxLNWFpa3pKMDN4Rnl5WHF6eTRSd2ZCalJ4cGpSbkdSUzlwNHdvM05sTVV2RFBZOXFxdTJMQUZSeWMKdStyZzhrVFpBb0dCQVAydU4yRENnenZ5S2IzV3pzdXBHTG54MUhGV091ZjRCY0FyWFJ3WDF1Z2NQOHkvTXl3WQpWOG9XNUg2TVhPbytWb3dxd3hRSmNRcXZXS3pXaTkyd0FIWnBVU1BERUxXbitVUlVyQWZyNFBCbU1mRE9VNW9CCnpYNXpXZHJiNHUrVVJvZVltdW8yRmRBcmFPRTg4STZqVk5XMVlpdUJGb3hERU1Pb3U2N1JRaEpGQW9HQkFPSjgKa3haT3dxVW5oeFp6bG9Xbk96VjJxUCtoZXV4STNvY0JhNDFpem91Q1MrcFNPSC9SS2wzRE1GVmZmejR4VlV4Lwp2UDRGTnZXTXlvZE9KU21WdXk3U3B6YThnQmFtNDVuUlRSWDVOUlhYczg3dXd1MWJManZJSk5rWkJPbG9vZTdpCi9TdkFWSHVrL2t4MWFUUUcyazU0SjJNY3JxNkRmSktLRzFtZUJodHJBb0dCQU8wUEw4cnBHbkFiZGF4a255MHMKb09HcXZtY0hPTmJyTEp5UEtWeUdYcHJiUXplWGVUOThwQlZDM1ZYdzN5YzdCKy9HU2pSZ09sWE0xR1gzdkE1MwpXWWRPRmJnQW9vM1BJWjRjTGdMZEI0QS9UKzRETVpiYWxtalRiS1djRSs3a3RpQWltS25EenhDUWNGc0RjcDBvCnZxOVM2Q0ZWYVhlN2VHQVBQd3czbXJHdEFvR0FJRjRaVHpqV1RIQUh1RWV3blUwM0F2OEFTL2d4N3c3QzdweGYKV0lka2FUK254Y2NXVi8zMmhndmRIblpWWXZmOTdyN2FyWnJsTGRaL0l6TWgwSDJia0tkK1NpNUtSL0oxMkllMgo4b3I0OFRRd2VFUmJDenphc0tSN3o2THB0c25EU3JhWjQrVEtyaGo0VnNqNHpmeWt1azRsb3Q1NGdHdytJMXNsCmFYdFIrQjBDZ1lFQTBiclBYVGJ3bE9KNU9WVklzbUtkQzU2RzNCYmRhZUZrdzZ1NTNjcm9LMjYrY2RPank5NTcKeTloSVhuWlF5SVRxRW0rKzBsUjJldnVKY3cwK2hBRVYxRjJKY3E4akZkejAyeXhQeHhtb0lTWFd3QnlnME04dgp2SVFzbXRCUk1SV1pMVnhKQk5RZWFMa2RMcGtlQVo1NG51aXNWejlHa1c2YmpWY3E1L0JodnlBPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRE96Q0NBaU9nQXdJQkFnSVFQcm02cHowOXRicW9Wbmw2Y1dyV21qQU5CZ2txaGtpRzl3MEJBUXNGQURBVgpNUk13RVFZRFZRUURFd3B0YVc1cGEzVmlaVU5CTUI0WERUSXdNVEl5TkRFNE1EYzFPVm9YRFRJeE1USXlOREU0Ck1EYzFPVm93ZkRFTE1Ba0dBMVVFQmhNQ1JWTXhGekFWQmdOVkJBb1REa05oYm5SbGNtRkdiMjV6WldOaE1SRXcKRHdZRFZRUUxFd2hUYjJaMGQyRnlaVEZCTUQ4R0ExVUVBeE00Ylc5dVoyOHRaR0l0YzNSaGRHVm1kV3h6WlhRdApjMmd4TFRBdWJXOXVaMjh0WkdJdGNtVndiR2xqWVMxemFERXVjMmhoY21ScGJtY3dnZ0VpTUEwR0NTcUdTSWIzCkRRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRGdiejhIWTJkYkRNeUpVK2pXeGVLZGk2bXBSR0NqTlVLR2N3QWUKeHl4ZFB0bWxrRDB3VHJTa09ZVGhRZmF6S0hZbjBDOE1kYXpLQVMyTjhtcVloUjRSN1VVbGsvVzRTUXFBMUFMWApYb3oyRDR3YVJ0VEtKenpFU0Q5TjEvcDE2MkEwY1JCMUM3NXg3cDdiZHkvbTVxUDFQUTZHMEhqRHQzYXdVNGpWCnJGOXRCcXh3REh3K0Nzall0UjBOSmZCTm5hQm4zSWI3WWF4eUMvWmUwV0M1T0p0T2l4dTk4eTVnZXBTZ0lEQncKSU1oUTNKQXkyZTJoMUdFTXFCTkgvSkFJOVVBZDlra0diREVQZGVMcWo4R3NndjhJNU13T21EOVZsbitxUFBKTwpCYlBQemJZNjJvVzhxL1dPT05DMEhvd0p4T2xGcGQ0YVVDTGF2TW1wTWZOeUtPblhBZ01CQUFHaklEQWVNQTRHCkExVWREd0VCL3dRRUF3SUZvREFNQmdOVkhSTUJBZjhFQWpBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQXgKU2JINmdiQkUwQ2xXQy9XSlEzUkRWM2RyOEkxcmdIcmg5UjJnT2F6KzUzclZvaHliMDV2NWJkb056dk1Rbmp1eQpuQ0xSU29uZ2RVOVhkb0djQnVudkZpZ3NrcVE2VG8xWUlMaVF4dW5uOHlCakNFcDA3ZUR1aGlrOU9XYlVHa20yCjgyWjAxa2wrNE5VSmgybnV5VG5ycFVtTHprb0Y4NnpVdlA1aHRFMFZCYWUyNFZQN09xWDNDUGE1WGU5bHcrUEQKZUJBT3YxUzRMYlRjZTFGbXVsK3d2ZjdTT3o4NHU4SHFwd0ZNMFRSQ2p6YWVNTEJGNVF6elpsT2w5ZFpRdURWVAorY05uUmhnQW9PUUFzRkE2UFhnMmVjM0VIV3RxSk4yOW1Ua0ZocjZuZXhBcEJnd0VHRnZPclNaZ3FwZmpNcEVZCmM1MmRSUWxaSEFzQk1ua0EzUzhmCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
  tls.cluster.1.keycert: "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBdHFGRDNKV0k5MlIyTU51WWR1dms3YzFHRUtBMXdkSmJMbFJkYUJxYWNSS05uMmZTCk9EQzFhZ1RVL1BkUFpkVjF5ZHZpaHA0TEpHZThYLzNQWmtSS1IvYXhaWTl2eVZuc1h4dUt6bjMxUVMyYnJ2MWIKOG1ZVEM5eXhXUVhqaURiUXJQeVdxS282UVFQZlVCRnpLRzZ6NjFYZEt4aUx3ajZoZjNjTnBHcUxrUU53R1VLZApGUzA3a3M4YUZYUTdOcEhqSkpxeUMxL05qMzN0V2pDMmJiSDBKZ2JONkg1YTNEVmpnR2FGZGNWQjQwUWhRU0dpCk1Ob1BiSElVUERjOExiVHI5Z0lqd2FORGx6dEs2TVIzeDduclNaL05kOGY0UTBscXNjNGVFanZHclhtbEtUREkKRWVKbjBEMDVBODVyWjVZTmorMy9qWWlTMGJqT0cxSEljVzNMVHdJREFRQUJBb0lCQVFDYnJLdGtCRE5VYmxZeApIMzYvSUNWc2IyWWlGZTY4NE1ySW16Rmo1QWx5Q1JhZm9xZ1hMYTMyU1Zna3Fjc01Td0MwcUxKWGZiQ1J2N3RiCk44YnFyWnVEN0UwYS9VR1VxUXBMcC9hU1Bkd3BTdTlDSXNXVndseko1NzFrM1JndXJFc0VxZXJpcXZndEkxZmYKc0lBeEh1eE8xa3BJeWd1WDhEdEpvL29GQkswalZoQWJrZnJSYlpUdGt5d0ZmQ3ZDdFMzTjJMR3Z5eEF1Umd5NgpYTE8xdnhBN3hYMUJOS1lnekJrUUdGY0dZaEZ3WWViaWttL2Z6NjdqUU1vSDNFbUU5d2F4eXVKcUorYVEyalFFCml6akFsaWgvUU1RMXRTcnJnbjRZVlpWN3FrNWxGditxT1N6ai9SYUJoNlVjUEJmYkJBTWE2eVRCZlN6TWVKVUUKRUFmMzd2aEJBb0dCQVBEUEt4SkNLc2ZyOXA5L3BUNHo3bmtKMWdIa1pvUjZWQzFhbnpUZzE3a2tLb1RpUFdFbApZL2dwUTUzSldtNTljS2E0dFhmUDdDblJucmJIenUvZ05zSlZ4YnpMbTZGNzlmT0tLOTlIc1dSZjNDYjNjemZoCjcyckNheXRzaWhGQWtrcC9HSTMrSCtqblVTMHRCdGxzdUZuN1M3TWdaejZZMlhFL2I3MU9NbityQW9HQkFNSW0KanZQcUI4L05Pb25MMkY0aEJvckJVdHdJVnl4TVR2dTNZSndlS1cwbFVsUEZuTm1BVkpUM3FvUWNDeHNxN3grOQp1SVNnV3Buak1lTmZWZG45V2IzelRTTUJrVGQxTWdrYTdLSkZZYTRtMWJWSVRyeDl2UlhySGZaOXFYTmRzNXE5Cnh3Y3JOcC9wSFNRTnc4YUV1bkZYRFd3Qm9nUGEyYlhRQkw0VDFzN3RBb0dBVW45bXpoYUUrWURKT05OT0ZRVk4KaVlIcEl6VFFPa3ArVkJ0YnQ0M2YyYm1lSjNBcWZ3R0VRaHhBNGVsOVphVHIxdklvbVNkT1RQVlhYbDhOY2ZocQpTaUdBWUxHUVc3NVFBR014cklpdktTZitFQXR1R1pMNXBxVjhlWi94blA5MkhyZHovaEUxZFdEcDJvUTJlSDVhCm1ka1JrZ2hqMW5vZTVFRkxVcHRiaVlrQ2dZRUFzQTJPNjVkNFpmTFA5a3dtYzVTMi9mTzRVMVlzMWpxTUZLMkEKcVpDZ09Cenp2b3NmWkF0K3AyYTk5UFlKRENXdW1MWE5NRmJJVVdzM3ZkcWhXdjdsOWQwK1FWUVdmcGVETzhaeQpkZU04WkZOS3p3dzJlYTM3WEhqTHZzek1iNVMwWE1saVJSbm1lck5FZllFTjJtSlpQcFdWMGk3WTMyNEFwV0Z3CkszeUorVEVDZ1lFQW1tRkR6bHF0OXZsTmIwSCtwcjdhbzRsMkR1S2FlSWRESWxvM1d2NDZsMlB5MnFLcVpMaFYKT3RvSXJta2p1OE1aUjI5NWtja2xRdHVhWWZvTXBlZ1BiYjIrdEdjcFBHN1dvRkFrZENQbTBGczc2MHkrdGo4awo3eG55RXAvVk1nenByc3VFSmV0b3dYbEQvRC83blZOSCtGOXo3U2E3QzhXeC9WdmNDY1RJSjhrPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRFBEQ0NBaVNnQXdJQkFnSVJBTncxTDZycE9xajh0TVgxejFHd2xtSXdEUVlKS29aSWh2Y05BUUVMQlFBdwpGVEVUTUJFR0ExVUVBeE1LYldsdWFXdDFZbVZEUVRBZUZ3MHlNREV5TWpReE9ERTFNelZhRncweU1URXlNalF4Ck9ERTFNelZhTUh3eEN6QUpCZ05WQkFZVEFrVlRNUmN3RlFZRFZRUUtFdzVEWVc1MFpYSmhSbTl1YzJWallURVIKTUE4R0ExVUVDeE1JVTI5bWRIZGhjbVV4UVRBL0JnTlZCQU1UT0cxdmJtZHZMV1JpTFhOMFlYUmxablZzYzJWMApMWE5vTVMweExtMXZibWR2TFdSaUxYSmxjR3hwWTJFdGMyZ3hMbk5vWVhKa2FXNW5NSUlCSWpBTkJna3Foa2lHCjl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF0cUZEM0pXSTkyUjJNTnVZZHV2azdjMUdFS0Exd2RKYkxsUmQKYUJxYWNSS05uMmZTT0RDMWFnVFUvUGRQWmRWMXlkdmlocDRMSkdlOFgvM1Baa1JLUi9heFpZOXZ5Vm5zWHh1Swp6bjMxUVMyYnJ2MWI4bVlUQzl5eFdRWGppRGJRclB5V3FLbzZRUVBmVUJGektHNno2MVhkS3hpTHdqNmhmM2NOCnBHcUxrUU53R1VLZEZTMDdrczhhRlhRN05wSGpKSnF5QzEvTmozM3RXakMyYmJIMEpnYk42SDVhM0RWamdHYUYKZGNWQjQwUWhRU0dpTU5vUGJISVVQRGM4TGJUcjlnSWp3YU5EbHp0SzZNUjN4N25yU1ovTmQ4ZjRRMGxxc2M0ZQpFanZHclhtbEtURElFZUpuMEQwNUE4NXJaNVlOaiszL2pZaVMwYmpPRzFISWNXM0xUd0lEQVFBQm95QXdIakFPCkJnTlZIUThCQWY4RUJBTUNCYUF3REFZRFZSMFRBUUgvQkFJd0FEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUEKWXNjTEprWThJTWJrRk14TEJJcGt4RTFhdzlDaHNDM0hPRXpCUlhhb2dFTXZUd2xzRFB3Q0Zhc3l6aTZzeDFnZApZVmdBMXp6WEhabWhpdkJGZ2x0MXZYZlZFNTdaRmFJaVNOQXp2NUV5a2lKVHhFd2t6SmNQWVFJYTE3b3UxYkRMCitPSG1TVHlOZXJFMjhVY2J3YkcwN1hNeXd3S2JTZCtTU1I4dzMrZXYwMWhzRDZZZm5FU0hjZzlscEt2ekFseWkKL0ljVEZHQzBNeEtoUWVmUWo3UE8vWVpVZkpSalZHK1dXeEZzSWI3L0JCSFgzaWwwMVBEQzY1bmdPaUlHQktKdApxWUpLREVKL1lwalc0ZHpIWTV6VXRqNVh5TkQrMFY3UVBBUWQwQW4zUzNLbURsZkRzZ2xjeEZDdDJHZEdRM05sCm16TnZqazNJSU1UeWxwMFNCV0lPcFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
  tls.cluster.2.keycert: "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBempCbkpzdlZSYTlQRVNKRWVjSnBENDdEU1hyenplME1oZjk0cW5ITTNzM0IzekdTCjJBVUk5U2RiOVF0ajBTY2lnOFJ0NWsrUk5OanFtTDIwN2RqbUhMRytDS01aUnRmeVdXZkZGN1NINkk3cE9MVFYKN3d0ZkpWMlJmWDNBSWhBZ0V5bEdDVFU4K3E0NjN3Z1hBOVVVWDBxdUd6ZEVnaVNCdnVVUzV2a2JMdlFyZjY4aApEMkZsc3NkQlhHRW5zY0YzbHBlZDBZYTgrZksxenllSTEzTWNrRkFnbitKaVp4Mlcva1VBcTQ2MkxWTkl4bll4ClpPWmZiL3ZyWnRSR0J6QTl6T0o2S2FZWi92L3hZWGhKd2htRUQ4VWprNnR3VzBPdFFFT1hCT1grK0I3V0NGWDQKV1NqMzhZR1FqbnVvZmZ3S2VvQjQxUzBWNndTQjRLeGtwR1MwUndJREFRQUJBb0lCQUY2d2lkNmVRMDVpU1F4VQpVV0FkY1FRdEN2QW0zK3BWRDZoRi81TSsrZGZrWkVGczBjUVU0OTA1K3hnWTUvazRZTGhrc0JmUnVKeXRkV2M1CnorcGU3cWFFMWdHL2JTOUVvczUrUWx3MWt5aXc0TmdpN0JDQWgyeHdnUTFCZjhmazRlWUswVmdQTS9ibnBxK2cKVm5sekZJMENqZHgvMEIxNFNJRnpUKy8wdkpBZHpEUnlZeFBHU2YrMjZKU3A0VTJWMmwyK3pabFQrRThicC9CRQpQTXJsLyt0NkFiNjE3K0l3MlpFcHNFMW9SMmZpNHBxSllqelAzNGpvdC9xMW9jUjNKb0RRUFZva2dmRzdteDduCkdVbmFsVkNXM1hadDU4QlA4dTh6ckVFTzhlSXdlRWE0UGVQcWs0M3VTRjBCemtEOCtiODR3VU1uWVVkdmJ3bVoKZmNRbUFUa0NnWUVBK3lWTVpMUjVKZHBzeldjUGxwU2lxSEcyQXdhaGlEbXRGc3VITW12MFFRS1VVd1p0aXBBSgpRbGNMb09Hb0RjY01xOHc4Nml1K0RvVGpVN1hWcjRIYTJLZWlJVUd3TG5Qd203OFZSWVJzRVB0Wm84TWZYOEw5CnJQdEFsVFFUM2NUbHA5MEZtMTJlU0tUVldLZGR6YmFBY3lhREZWN2tEM0FRckdHcmxiSlVDSk1DZ1lFQTBpeW4KUHVzUnh0dXdPMVNBNHBRaDhyNlFMT2VVcG9Iajl4NUQzSmI0ZWIyMUJhZS91VEZMWmtUSXNZZGx3T2RGMWNJLwpPY2hLN0dHYkRDUWRueWRHMitEem8rcHY0RDdUY2pvQ2hsaTF6UUtzMjQ1WDFtVms1R0xjcnpmR0VhUkwvL0puCnp3QjgrQ2Y0c1JtVWpSOXNNSGNqMzVBYWZxYjQvQWI1RG5RQ3VmMENnWUVBNXVDckVnazNOaTFPeUtWdUZ5Z2QKUUcwSXZrOWlRREdGaGVjbEtwMUR0bUFBcXpMRmtSUkk3c3ZHek9lbDdzU0dTWWxBbHFZUDJwa2Z3dHp1ektHNwo1bUIxRTgybmdZemtMTW5GYkZzSVhiUXorL0JzNzBQNm9RTjVvN0IwY3ZPSGpJSUxuWUM2K2wxT0pHbjRPaDBFCmlOZG11a2E1c2RkNy9IenRtSGlQK0RFQ2dZRUFsRnc4K3VjSXQyMGdxK0RzMGdSckttVm1kS3hNZkhVNExKcksKb0k1WmUrWjBRRGUzMk14NVF3bk8rYkp3RzRtbC9FeVFRUU9vRDlDZW1DVnVXNGhvTnBKR3FqQzFKSUIwMWk4bwoxUmtOekZmVkdXOFRoaDR3NkI3NVZSNXp6TVJEZWJydG1HdnB5MnE3M0pnSUNzNWhtcHlmVUJMekFQQncxY2MrClMvdU1hU2tDZ1lFQXVOSEJzMHRFWTJXaTE2akM4ZWxPbVdPQ3hBRTdFV1p3cHZBZTJyZzRBcFNnWU0rZUo2UnIKcG4wWFptbEJCVnFpQjM4aFVYc2FFRm5YT1pNWEtYcEoyNUthakFMNDF6WGEySTF6UG1JUjBvU2JvYjhPekVwSwp5VDFFTW5ld3o0eldWOUhGbmZBSW1XeW1hcW1hNVdwSEdQNGRnS3VLQ2RXUmxmemRiVE93cGNFPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRE96Q0NBaU9nQXdJQkFnSVFPMnZheGhCZjA4c3oxM1FsTC9QM2ZUQU5CZ2txaGtpRzl3MEJBUXNGQURBVgpNUk13RVFZRFZRUURFd3B0YVc1cGEzVmlaVU5CTUI0WERUSXdNVEl5TkRFNE1UZ3pPRm9YRFRJeE1USXlOREU0Ck1UZ3pPRm93ZkRFTE1Ba0dBMVVFQmhNQ1JWTXhGekFWQmdOVkJBb1REa05oYm5SbGNtRkdiMjV6WldOaE1SRXcKRHdZRFZRUUxFd2hUYjJaMGQyRnlaVEZCTUQ4R0ExVUVBeE00Ylc5dVoyOHRaR0l0YzNSaGRHVm1kV3h6WlhRdApjMmd4TFRJdWJXOXVaMjh0WkdJdGNtVndiR2xqWVMxemFERXVjMmhoY21ScGJtY3dnZ0VpTUEwR0NTcUdTSWIzCkRRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRE9NR2NteTlWRnIwOFJJa1I1d21rUGpzTkpldlBON1F5Ri8zaXEKY2N6ZXpjSGZNWkxZQlFqMUoxdjFDMlBSSnlLRHhHM21UNUUwMk9xWXZiVHQyT1ljc2I0SW94bEcxL0paWjhVWAp0SWZvanVrNHROWHZDMThsWFpGOWZjQWlFQ0FUS1VZSk5UejZyanJmQ0JjRDFSUmZTcTRiTjBTQ0pJRys1UkxtCitSc3U5Q3QvcnlFUFlXV3l4MEZjWVNleHdYZVdsNTNSaHJ6NThyWFBKNGpYY3h5UVVDQ2Y0bUpuSFpiK1JRQ3IKanJZdFUwakdkakZrNWw5disrdG0xRVlITUQzTTRub3BwaG4rLy9GaGVFbkNHWVFQeFNPVHEzQmJRNjFBUTVjRQo1Zjc0SHRZSVZmaFpLUGZ4Z1pDT2U2aDkvQXA2Z0hqVkxSWHJCSUhnckdTa1pMUkhBZ01CQUFHaklEQWVNQTRHCkExVWREd0VCL3dRRUF3SUZvREFNQmdOVkhSTUJBZjhFQWpBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQ0cKMWNXYmlhV3pMT2orRDRZQ1FHMnRMR1Z6YWtRbUhwaHpFaTU4QW9jUFBqK2lIRjRNWS9GTWFrd3pUM1o4RUd4UApCd21wWUZRYW9iMzgyUVJpczBuQ1ZobFpicVZ3N2ZnL2dRb01TbVBMRUJteVNqY0ZoWS9mWGpZSHpHQm9XU056CjR3Tm9vMGM4RkRSU0s2cU9MWVRjOUZ5VDZVeTd6NGl4c3QwMk83MEpTTzdkYmJPZFNBQ2pGZGtzMmJMQm1Ya0wKcytsRnBrdGM5WjNtMzhrVDhDWG9aZ0l4bFo0TG9yUmYvMGh0WjlZVklxd0czWFF6eUJ6dXpCY25GNnk0YzFCZApMOFpXSzFSZm9lTE9LNVBYYW5UQU9LYjMvNGROTEt5VENUZ1pmbXRCb2grYkRXK2dhSy9tTC9sUGlQK29GbVdpClp6ZGVUd3h4M3VQN0JuZzQvN1Q1Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"

📌  The content of the secrets under the data block have to be encoded in base64 format.

Now, everything is ready to apply our final K8s statefulset that will mutate our cluster into an authenticated cluster. With respect to part 2 of this series, the manifest has been tweaked a bit to copy to each member of the Replica Set its corresponding “keycert” file. It can be observed that new parameters have been added to convey the options related to the member authentication based on x509. In addition the parameter --tlsAllowConnectionsWithoutCertificates no longer appears, as connections without certificates are not allowed.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongo-db-statefulset-sh1
  labels:
    mongoDB-replica: "true"
    mongoDB-secured: "true"
    mongoDB-sharding: "true"
  annotations: 
    author: JMCF
  namespace: sharding
spec: 
  selector: 
    matchLabels:
      app: mongoDB-replica-sh1
  serviceName: mongo-db-replica-sh1
  replicas: 3
  template:
    metadata: 
      labels: 
        app: mongoDB-replica-sh1
    spec: 
      terminationGracePeriodSeconds: 10
      volumes: 
        - name: initial-secret-volume
          secret:
            secretName: mongo-secret-sh1
        - name: secret-volume
          emptyDir: {}
      initContainers:
        - name: set-file-permissions
          image: busybox
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
          command:
            - sh
            - -c
          args:
            - >- 
                 cp /var/init-secrets/tls.keycert /var/secrets/tls.keycert && 
                 chmod 400 /var/secrets/tls.keycert &&
                 chown 999:999 /var/secrets/tls.keycert;
                 export POD_NUMBER=${POD_NAME##*-} && 
                 cp /var/init-secrets/tls.cluster.$POD_NUMBER.keycert /var/secrets/tls.cluster.keycert && 
                 chmod 400 /var/secrets/tls.cluster.keycert &&
                 chown 999:999 /var/secrets/tls.cluster.keycert;
          volumeMounts:
            - mountPath: /var/init-secrets
              name: initial-secret-volume
              readOnly: true
            - mountPath: /var/secrets
              name: secret-volume
              readOnly: false
      containers: 
        - name: mongo-db
          image: mongo:4.2.6
          ports: 
            - containerPort: 27017
              protocol: TCP
          volumeMounts: 
            - mountPath: /data/db
              name: mongo-volume-for-replica
            - mountPath: /var/secrets
              name: secret-volume
              readOnly: true
          args: 
            - --replSet
            - $(REPLICA_SET_NAME)
            - --tlsMode
            - requireTLS
            - --clusterAuthMode 
            - x509
            - --tlsClusterFile
            - /var/secrets/tls.cluster.keycert
            - --tlsCertificateKeyFile
            - /var/secrets/tls.keycert
            - --tlsCAFile
            - /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          imagePullPolicy: IfNotPresent
          envFrom: 
            - configMapRef:
                name: mongo-config-sh1
  volumeClaimTemplates: 
    - metadata: 
        name: mongo-volume-for-replica
      spec: 
        accessModes: 
          - ReadWriteOnce
        resources: 
          requests: 
            storage: 100Mi

If everything is fine, after applying the manifest above, the Pods associated to the statefulset should restart and finally be up and running waiting for new connections.

Testing our mongoDB Cluster

At this point in time, our mongoDB cluster can only be accessed by presenting a proper “keycert” file. In order to test, our initial client.keycert is going to be used (corresponding to the user’s DN CN=App1,OU=Applications,O=CanteraFonseca,C=ES). For convenience reasons, a new K8s secret is created as follows:

apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret-client
  namespace: sharding
type: Opaque
data:
  tls.client.keycert: "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcGdJQkFBS0NBUUVBNlMyUkwwSnFVRDRONmhmWTVkMEtMelBnRnBXQkgrbUl3UVRkcjY0TUpqbnVGSXpsCmFBNFhwOWE0YytQTWRnQmhnWTl1ZGZXdy9RVlF4OVMwaDZYM0xiTGpYUi8wbG1sOW9BZzVFTDZqKzJIVEp3MDAKUEt3WXhDVzN4c1haRk5YL2hTYnR6WUtQaDhkUFJXc3d6SFBWeFhjYlR2NVFJNzJXWVRnRUh3cmNPWWVOQkRqSQovaTdnTTVUSCtvdUd0OGx0bm5nKzlqZEdCaEI1ZHFtSm00NzFOYmJuUDRkLzkzeS91aFFsQmE3U1lJcEZ3NENuCmlCT0tXaENUa0tHV1daVEpYR3hoWnFUeFBKZW8vY1pkQ21HOUNMMVQ5QWNuT050VEx4ck5MQmZ2RGRqWGd1R3MKeXNXR3BwbXI1ZW9ON0xZZTIzZXlRS0g4MEVCbHBENmZDU0VPdlFJREFRQUJBb0lCQVFDVXM0eDgrUHZYaEZ0WApTREg0RlFoanBjOW9WNXRyQUlGSHBwVEJibHN0SFpCbzVwbDl6RTdscUJjbFFNYXBFZ0Vjb0oydStDb1FrWTA4CmdyZEdNbDc1YzdWdk0rdkU2QzFIR3pkWktGcG0rN0d1bThzT1RpblZITUNnTUpnSm81YzZFT05pUmJyR3VpSWgKZ1FRenZrTTdsSU9EMHNiRXBDajhncjZPRlZ6d0NmdmhPd010dG90ZEZkTnBsRWFLN3NmZjBkSGorN0FaVWIvbAp3dGZDUXQ1Tmt0Y2s5ZFFWc3B5WVppYlNsa1FOTFpuMTF2QjNNMk4xQk9rbzBNTTdyb09rc2tLTzVvcUtjOW1lCnVldGo1YStWQW1UUWRJZkNwL1dpUDYyNE9NdXVyMDdQQUwyblNvY28xS3lPT0Z0UmxnTER6ekMwS2RvWGZ1SHgKTVRxbWNSUzVBb0dCQVAwWTBIeHJUTDdnU3FNZlF1TlRvd3JkZzdtQ1l1c3Z2QkxHQ0sxQkMxWW5hVGpZdVhWdgpCWEJYMmt2UXRkRkJvM3RaNytsUzUwWTZGcHN1SS9YR3VqcXcrNzB2dk9wTzJTRmc2T2JjK2U4QXRVNDlMcDAvCk9uaTV2eC9oOHo2Q29RR1RBN3dMcnlGRWsrbVVBN3dZUVNQWnREL0xxbDFGWEZHQlRkTDhZR24zQW9HQkFPdmEKUTI5R2NRYkJrdnVXakRsT1lvVFJvVXJ4NmpXVzMybStTNkx6OHRjNDFKUitMRWMvOEQ3djc1Y2ZkRHFYYkxnVwp4VVdEcWNUaldKM3o1OGN2U0dBZlZMYjVxTGcyZGhFMUlWRVlsYzhSZzIrQlFPL2JFNy9sM3hua055bi93NDV6Cit0SytudkFpL284Nnh2eEwvV05yWm55WGtsdkd4QVc2dDhpdTFEL3JBb0dCQUpRM011aVp3WkRLTW90Q1pGNVIKL1ZvQWpRSlhLK3lFd01QUnV3VVM0VHVyeXIvaWt3RUZhZzczTTd4UVZobGNNZ3VyaUlaLzZUWkVFRGNDRjBiNApBTmtjQ2VBcGs1MDNYWXBoZ1NLcFo2Z2lKd3JSWTNuc3JDWkV5SHM0UzhWZ3BEOFN4QTRjWFl2QzZFZlNTVG1lCmpvOGJENmFJYzVVNWFDM0c1amRYV25MVEFvR0JBTHl6bGU2cTZuV2dYUXhFU0k3MUl5Zm5YV2hNSTdxYXFzZTkKQkdFdFUyZFZSZWhGQndJK3F1YUFMQzY2Y05FTUpHVXBlczZDYUV0cUpwWEI5dmpMNE5sZlYvVkp6TzhPUytxNgptcHg2MGltcGRvSzVaSTVEdHdwN1RjUTJidGlBbFNNZHNsbjVQOHNjQkpYdVRoVEFhOHltdW9vRzc0ZlVnVE9nClQ3a1dBQ1hmQW9HQkFNUXM0eUtKM0ZXYmFtc0NINllOUENuTVNnM3lRSEhYSldjcklIa3RMcFIxRm5kL29uczcKSmNha0tDSTRMZmhSL09VR0ZubUdVa1hrbzl3T3BndlZQb1JlblB3Uko0eVBXODl3aE5BZ3B1TGlJQ3pYVHZjUgpRZzJXSVAwRDJLOFdERmQwN1RNZ1FpbHNWeG8wcHlNVVZ5N3ZFanhFMDhKM21PaDM2Y3duYjV6RgotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJREREQ0NBZlNnQXdJQkFnSVJBTzh5SStPb1JxWERCTWxkT2pJazcrUXdEUVlKS29aSWh2Y05BUUVMQlFBdwpGVEVUTUJFR0ExVUVBeE1LYldsdWFXdDFZbVZEUVRBZUZ3MHlNREV5TWpVeE5qRTRNVFJhRncweU1URXlNalV4Ck5qRTRNVFJhTUV3eEN6QUpCZ05WQkFZVEFrVlRNUmN3RlFZRFZRUUtFdzVEWVc1MFpYSmhSbTl1YzJWallURVYKTUJNR0ExVUVDeE1NUVhCd2JHbGpZWFJwYjI1ek1RMHdDd1lEVlFRREV3UkJjSEF4TUlJQklqQU5CZ2txaGtpRwo5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBNlMyUkwwSnFVRDRONmhmWTVkMEtMelBnRnBXQkgrbUl3UVRkCnI2NE1Kam51Rkl6bGFBNFhwOWE0YytQTWRnQmhnWTl1ZGZXdy9RVlF4OVMwaDZYM0xiTGpYUi8wbG1sOW9BZzUKRUw2aisySFRKdzAwUEt3WXhDVzN4c1haRk5YL2hTYnR6WUtQaDhkUFJXc3d6SFBWeFhjYlR2NVFJNzJXWVRnRQpId3JjT1llTkJEakkvaTdnTTVUSCtvdUd0OGx0bm5nKzlqZEdCaEI1ZHFtSm00NzFOYmJuUDRkLzkzeS91aFFsCkJhN1NZSXBGdzRDbmlCT0tXaENUa0tHV1daVEpYR3hoWnFUeFBKZW8vY1pkQ21HOUNMMVQ5QWNuT050VEx4ck4KTEJmdkRkalhndUdzeXNXR3BwbXI1ZW9ON0xZZTIzZXlRS0g4MEVCbHBENmZDU0VPdlFJREFRQUJveUF3SGpBTwpCZ05WSFE4QkFmOEVCQU1DQmFBd0RBWURWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBCktZc3FhdFhna1dETWRLUitkbVBGRTBNOG9zS1VnY1lCNkEvNEUvWnRWSG5Ndk1QTFJ3bmF4SGJNTFcza2E5NzQKeWYyT2F3THZ2aG92MkpiT0k4U0x6Q29PandnblBrdlFqTFJDU25wM3FEYUZtSGdaUjNKMENFM0lpaDV6UldTSAorQXRwOENpRnNsZk9hMTdWckZDcFdPbEVvWWttNFBwbk5xVVZMOWprQ1NRTTc1Rk5XVmZ3eE83RTFmK0JFUjliCmtOWGk0YmZaQUFSWTZsUXAxMU10MVpRT1ZGbTNudUpoa3JhY1NRU2J1T3FVS3p2bml0WWlWVnNNVjAzdC9oQ2YKU2NEUWtoZkZJQ3lmT2o3VHVseUFzTDB1b3pNQUFOUTlPcWYwSnlEQkh4VWFpVTBkSm9hWnVxVkdlcWl2WmgzegpSTFI2dzc1dFViL3pFNW5yR0MrQm13PT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="

It contains the keycert to be presented when connecting to our mongoDB cluster.

As we would like to continue using kubectl and all the K8s facilities, we need to define a K8s Pod manifest fragment as follows:

{
  "apiVersion": "v1",
  "spec": {
    "volumes": [
      {
        "name": "initial-secret-volume",
        "secret": {
          "secretName": "mongo-secret-client"
        }
      }
    ],
    "containers": [
      {
        "name": "tm-mongo-pod-mongos",
        "image": "mongo:4.2.6",
        "stdin": true,
        "tty": true,
        "command": ["mongo"],
        "args": [
          "--verbose",
          "--tls",
          "--tlsCAFile", 
          "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt",
          "--tlsCertificateKeyFile",
          "/var/init-secrets/tls.client.keycert",
          "mongos.sharding.svc.cluster.local"
        ],
        "volumeMounts": [
          {
            "mountPath": "/var/init-secrets",
            "name": "initial-secret-volume",
            "readOnly": true
          }
        ]
      }
    ]
  }
}

It can be observed that a volume with our keycert file secret has been properly mapped to be used when connecting to our cluster by executing:

kubectl run tm-mongo-pod --image=mongo:4.2.6 --rm=true -it --restart=Never --namespace=sharding --overrides="$(cat mongo-client.json)"

After executing the command above, we will be under the mongo shell console prompt but not authenticated yet. In order to authenticate the following Javascript sentence has to be executed (at this time, against the PRIMARY Replica Set member):

db.getSiblingDB("$external").auth(
  {
    mechanism: "MONGODB-X509",
    user: "CN=App1,OU=Applications,O=CanteraFonseca,C=ES"
  }
);

db.getSiblingDB("$external").auth(
  {
    mechanism: "MONGODB-X509",
    user: "CN=mongos.sharding,OU=Software,O=CanteraFonseca,C=ES"
  }
);

📌  We can authenticate as, on the command line, we have already presented a keycert file as a proof of our identity (CN=App1,OU=Applications,O=CanteraFonseca,C=ES).

Once we are authenticated we can create a new database, named test, and insert a document into a collection testCollection as follows:

use test;
db.testCollection.insertOne({ "type": "Building", "name": "Eiffel Tower"});
db.testCollection.find({});

Later, we can check that the data has been propagated to all members of our Replica Set by connecting to a SECONDARY cluster member, authenticating against it (using the procedure describe above), and querying the data on the test database (at this step don’t forget to issue rs.slaveOk() before querying).

🔌 Sharded mongoDB

To be developed.

https://docs.mongodb.com/manual/_images/sharded-cluster-production-architecture.bakedsvg.svg https://docs.mongodb.com/manual/_images/sharded-cluster-mixed.bakedsvg.svg https://docs.mongodb.com/manual/_images/sharded-cluster-production-architecture.bakedsvg.svg

sh.splitAt( “tsharding.col1”, { age: 50 } )

use tsharding;

db.adminCommand( { enableSharding: “tsharding” } );

db.col1.createIndex({ age: 1}) db.adminCommand( { shardCollection: “tsharding.col1”, key: { age: 1 } } );

🖊️ Conclusions

Kubernetes provides powerful primitives to deploy a clustered mongoDB datastore service. Furthermore, we can deploy a secured and sharded mongoDB so that we can give production-grade support to IoT and Big Data Applications which demand higher scalability.

🗒️ Feedback