Kubernetes – Secrets

Kubernetes – Secrets

February 25, 2019 2 By Eric Shanks

Secret, Secret, I’ve got a secret! OK, enough of the Styx lyrics, this is serious business. In the previous post we used ConfigMaps to store a database connection string. That is probably not the best idea for something with a sensitive password in it. Luckily Kubernetes provides a way to store sensitive configuration items and its called a “secret”.

Secrets – The Theory

The short answer to understanding secrets would be to think of a ConfigMap, which we have discussed in a previous post in this series, but with non-clear text.

ConfigMaps would be good to store configuration data that is not sensitive. If it is sensitive information that not everyone should see, then a “secret” should be chosen over a ConfigMap. Password, keys, or private information should be stored as a secret instead of a ConfigMap.

One thing to note is that secrets can be stored a either “data” or “stringData” maps. Data would be used to store a secret in base64 format which you would provide. You can also use stringData which you’d provide an unencoded string but it would be stored as a base64 string when the secret is create. This is a valuable tool when your deployment creates a secret as part of the build process.

Secrets – In Action

Since a secret is just a more secured version of a ConfigMap, the demo will be the same as the last post, with the exception that we’ll use a secret over a ConfigMap to store our connection string. This is a better way to store a connection string over a ConfigMap because it does have a password in it which should be protected.

First, we’ll deploy the database container and service. The database container has already been configured with new database with the appropriate username and password. The manifest file to deploy the DB and service is listed below.

apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: hollowdb 
  labels: 
    app: hollowdb
spec: 
  replicas: 1 
  selector: 
    matchLabels:
      app: hollowdb 
  template: 
    metadata:
      labels: 
        app: hollowdb
    spec:
      containers:
      - name: mysql 
        image: theithollow/hollowapp-blog:dbv1 
        imagePullPolicy: Always
        ports:
        - containerPort: 3306 
---
apiVersion: v1 
kind: Service 
metadata: 
  name: hollowdb 
spec: 
  ports: 
  - name: mysql
    port: 3306
    targetPort: 3306
    protocol: TCP
  selector: 
    app: hollowdb

We’ll deploy a new secret from a manifest after we take our connection string and convert it to base64. I took the following connection string:

mysql+pymysql://hollowapp:Password123@hollowdb:3306/hollowappCode language: JavaScript (javascript)

then ran it through a bash command of:

echo -n 'mysql+pymysql://hollowapp:Password123@hollowdb:3306/hollowapp' | base64Code language: PHP (php)

I took the result of that command and placed int in the Secret manifest under the db.string map.

apiVersion: v1
kind: Secret
metadata:
  name: hollow-secret
data:
  db.string: bXlzcWwrcHlteXNxbDovL2hvbGxvd2FwcDpQYXNzd29yZDEyM0Bob2xsb3dkYjozMzA2L2hvbGxvd2FwcA==

Deploy the secret via a familiar command we’ve used for deploying our manifests.

kubectl apply -f [manifest file].ymlCode language: CSS (css)

Now that the secret is deployed, we can deploy our application pods which will connect to the backend database just as we did with a ConfigMap in a previous post. The important difference between the Deployment manifest using a ConfigMap and the Deployment manifest using a secret is this section.

        - name: DATABASE_URL
          valueFrom: 
            secretKeyRef:
              name: hollow-secret
              key: db.stringCode language: CSS (css)

The full deployment file that will read from the secret and use that secret is listed below.

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
      app: hollowapp
  name: hollowapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hollowapp
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: hollowapp
    spec:
      containers:
      - name: hollowapp
        image: theithollow/hollowapp-blog:allin1
        imagePullPolicy: Always
        ports:
        - containerPort: 5000
        env:
        - name: SECRET_KEY
          value: "my-secret-key"
        - name: DATABASE_URL
          valueFrom: 
            secretKeyRef:
              name: hollow-secret
              key: db.string
---
apiVersion: v1
kind: Service
metadata:
  name: hollowapp
  labels:
    app: hollowapp
spec:
  type: ClusterIP
  ports:
  - port: 5000
    protocol: TCP
    targetPort: 5000
  selector:
    app: hollowapp
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hollowapp
  labels:
    app: hollowapp
spec:
  rules:
  - host: hollowapp.hollow.local
    http:
      paths:
      - path: /
        backend:
          serviceName: hollowapp
          servicePort: 5000Code language: PHP (php)

Deploy the manifest using:

kubectl apply -f [manifest file].ymlCode language: CSS (css)

The result is that the app reads from the secret file, and uses that string as part of the connection to the backend database.

Summary

Sometimes you’ll want to store non-sensitive data and a ConfigMap is the easy way to store that data. In other cases, the data shouldn’t be available to everyone, like in the case of a password or a connection string. When those situations occur, a secret may be your method to store this data.