Secrets are Kubernetes objects that are very similar to ConfigMaps, except kubectl by default hides the values they contain. This makes them an option for storing things like passwords and API keys that you normally wouldn't want sitting in the text of a ConfigMap.

The things you store in secrets are base64-encoded, but not encrypted. Someone with the capability to run kubectl get secret <secret-name> to your cluster could still see them. To prevent unauthorized access to your secrets, it's recommended that your cluster restricts access via kubeconfigs and Service Accounts.

Giving your app a password to use via a Secret

To add a Secret containing a password, it's recommended that you create a file containing your password, and then run kubectl create secret generic <secret-name> --from-file=<path-to-file>. You could also define a Secret via a manifest file. But doing so may tempt you to lump it in the same version control system (e.g. git) you'll likely use for other manifests, and it's an insecure practice to have passwords hanging around in version control.

The following example will:

  1. Create a Redis environment that needs a password to access
  2. Create a Secret containing that password
  3. Inject that Secret into a microservice's container as a volume

Create the Redis environment by applying the below manifest:

apiVersion: v1
kind: Namespace
metadata:
  name: redis-stage
---
apiVersion: v1
kind: Service
metadata:
  namespace: redis-stage
  name: redis-service
spec:
  ports:
  - port: 6379
  selector:
    component: redis
---
apiVersion: v1
kind: Pod
metadata:
  namespace: redis-stage
  name: redis-pod
  labels:
    component: redis
spec:
  containers:
  - name: redis
    image: bmcase/loaded-redis:example-stage
    ports:
    - containerPort: 6379

(Note that these were created in their own namespace. If you want to check on their status or manage them, remember to use the -n redis-stage option.)

The password this Redis instance needs is y3dHr34T4. The microservice we'll be using will need to consume this password via a properties file, the property inside needs to be called redisprops.password. So, create a file called passwords.properties and give it the below contents:

redisprops.password=y3dHr34T4

(Note: the kind of microservice being used is Java Spring Boot. The container has its own default properties files, but also accepts properties from two other files called override.properties and passwords.properties, which will each override the default. )

Tell the cluster to create the Secret by running kubectl create secret generic passwords --from-file=./passwords.properties. This command will create a Secret named "passwords", and this is how you'll refer to it in subsequent manifests. You can confirm that the secret has been added with kubectl get secrets.

If using Rancher Desktop, now would be another time to remove any previous Ingress you're using. Then add the microservice that'll use the Secret by applying the below manifest:

apiVersion: v1
kind: ConfigMap
metadata:
  name: shopping-cart-configmap-0.0.1
data:
  my-conf: |
    server.port=54321
    redisprops.host=redis-service.redis-stage
    redisprops.port=6379
---
apiVersion: v1
kind: Service
metadata:
  name: shopping-cart-service
spec:
  ports:
  - port: 54321
  selector:
    component: shopping-cart
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: storefront-ingress
spec:
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: shopping-cart-service
            port:
              number: 54321
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: shopping-cart-dep
spec:
  replicas: 1
  selector:
    matchLabels:
      depLabel: shopping-cart
  template:
    metadata:
      name: shoping-cart-pod
      labels:
        depLabel: shopping-cart
        component: shopping-cart
    spec:
      containers:
      - name: shopping-cart-ctr
        image: bmcase/shopping-cart:0.0.1
        ports:
        - containerPort: 54321
        volumeMounts:
        - name: properties-volume
          mountPath: /usr/local/lib/override.properties
          subPath: override.properties
        - name: passwords-volume
          mountPath: /usr/local/lib/passwords.properties
          subPath: passwords.properties
      volumes:
      - name: properties-volume
        configMap:
          name: shopping-cart-configmap-0.0.1
          items:
          - key: my-conf
            path: override.properties
      - name: passwords-volume
        secret:
          secretName: passwords
          items:
          - key: passwords.properties
            path: passwords.properties

You can see that it is mounting two volumes.

  • One is a ConfigMap in the same manner as in previous examples.
  • The other is very much alike, except that it uses the Secret.

This Spring Boot API may take several seconds to be ready upon container creation. We'll discuss how to deal with container startup time in the introduction to probes. But for now just know that the endpoint may fail if you make a request to it immediately after applying, and you'll need to wait a short while.

Once these are deployed, access the microservice's API via localhost/api/v1/shopping-cart. If it returns a JSON having a list of shopping cart items, that means it has successfully connected to Redis and retrieved the records from there.