Five Minute Tip: Leveraging configmaps and secrets for environmental variables

Five Minute Tip: Leveraging configmaps and secrets for environmental variables

For me, I’ve have been working with Kubernetes for a while, and I notice that there are only a few issues that stick out when looking at deployment.yaml. That looking deployment YAML files can be pretty lengthy. For example:

cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
  labels:
    app: wordpress-nginx
  name: wordpress-nginx
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: wordpress-nginx
  strategy:
    type: RollingUpdate
  template:
    metadata:
      annotations:
      labels:
        app: wordpress-nginx
    spec:
      affinity:
        podAntiAffinity:                                 
          requiredDuringSchedulingIgnoredDuringExecution:
          - topologyKey: kubernetes.io/hostname
            labelSelector:          
              matchLabels:
                app: wordpress-nginx
      containers:
      - image: gcr.io/bearmoo-cloud-net/wordpress-nginx
        imagePullPolicy: Always
        name: wordpress-nginx
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /wp-login.php
            port: 80
            scheme: HTTP
          initialDelaySeconds: 20
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 5
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /wp-login.php
            port: 80
          initialDelaySeconds: 20
          periodSeconds: 10
          successThreshold: 2
          timeoutSeconds: 5
        resources:
          limits:
            memory: 256Mi
          requests:
            cpu: 20m
            memory: 256Mi
        securityContext:
          allowPrivilegeEscalation: false
          privileged: false
          procMount: Default
          readOnlyRootFilesystem: false
          runAsNonRoot: false
        env:
        - name: PASSWORD
          value: randompassword
        - name: HOSTNAME
          value: www.bearmoo.net
        - name: IPADDRESS
          value: "192.168.0.0/24"
        - name: RUNAS
          value apache

I know that there are times where I want to edit one environmental variable quickly without changing the whole file. Besides, there is another issue as well; The PASSWORD is in plain text! Having to deal with logging programs like Splunk, I know that there is a potential for the passwords to be in the logs, and that’s not good at all. But, I think it can be improved using configmaps and secrets. I can update the deployment to point to another location to import the environmental variables by creating a configmap which is pretty straight forward:

cat sample-configmaps.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: wordpress-nginx-configmap
  labels:
    app: wordpress-nginx
data:
  PASSWORD: randompassword 
  IntIpAddress: "192.168.0.0/24"
  HOSTNAME: www.bearmoo.net
  RUNAS: apache

Under data it’s structure is:

<VARIABLENAME>: <VALUE>

That’s pretty simple, right?

Let’s use kubectl to apply the new configmap to the cluster:

kubectl apply -f sameple-configmaps.yaml

Now, time to check if the newly created configmap exist inside of the cluster:

kubectl get configmaps sample-configmaps -o yaml
apiVersion: v1
data:
  PASSWORD: randompassword 
  IntIpAddress: "192.168.0.0/24"
  HOSTNAME: www.bearmoo.net
  RUNAS: apache
kind: ConfigMap
metadata:
  annotations:
  creationTimestamp: "2020-04-29T18:11:23Z"
  labels:
    app: wordpress-nginx
  name: sample-configmaps
  resourceVersion: "10612459"
  selfLink: /api/v1/namespaces/default/configmaps/sample-configmaps
  uid: 31077265-cbb3-4574-a61c-8a3ba8cce759

Yay! it exists! Now time to update the deployment file to point to the configmap.

cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
  labels:
    app: wordpress-nginx
  name: wordpress-nginx
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: wordpress-nginx
  strategy:
    type: RollingUpdate
  template:
    metadata:
      annotations:
      labels:
        app: wordpress-nginx
    spec:
      affinity:
        podAntiAffinity:                                 
          requiredDuringSchedulingIgnoredDuringExecution:
          - topologyKey: kubernetes.io/hostname
            labelSelector:          
              matchLabels:
                app: wordpress-nginx
      containers:
      - image: gcr.io/bearmoo-cloud-net/wordpress-nginx
        imagePullPolicy: Always
        name: wordpress-nginx
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /wp-login.php
            port: 80
            scheme: HTTP
          initialDelaySeconds: 20
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 5
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /wp-login.php
            port: 80
          initialDelaySeconds: 20
          periodSeconds: 10
          successThreshold: 2
          timeoutSeconds: 5
        resources:
          limits:
            memory: 256Mi
          requests:
            cpu: 20m
            memory: 256Mi
        securityContext:
          allowPrivilegeEscalation: false
          privileged: false
          procMount: Default
          readOnlyRootFilesystem: false
          runAsNonRoot: false
        envFrom:
        - configMapRef:
            name: sample-configmaps

Now, instead of a long list of environmental variables in deployment, where pointing to a configmap to import the variables from:

        envFrom:
        - configMapRef:
            name: sample-configmaps

Hrmm. What about Our PASSWORD? Ahh, yes, like creating a configmap, will create a secret file.


apiVersion: v1
data:
  PASSWORD: randompassword
kind: Secret
metadata:
  annotations:
  labels:
    app: wordpress-nginx
  name: sample-secrets
type: Opaque

There are a few differences; the first one is “kind” statement. Where in kind where telling Kubernetes that this is a secret. All so, the value for PASSWORD needs to be encoded. Though this command, our values can be encoded:


echo -n | base64 && echo ""
cmFuZG9tcGFzc3dvcmQ=

Now that I got the output from the last command, it’s time to update the secret file to this:

apiVersion: v1
data:
  PASSWORD: cmFuZG9tcGFzc3dvcmQ=
kind: Secret
metadata:
  annotations:
  labels:
    app: wordpress-nginx
  name: sample-secrets
type: Opaque

Now time to apply the secret into the cluster:

kubectl apply -f sample-secrets.yaml

Now the changes have been applied. Let’s check to see if it’s there?

kubectl get secrets sample-secrets -o yaml
apiVersion: v1
data:
  PASSWORD: cmFuZG9tcGFzc3dvcmQ=
kind: Secret
metadata:
  annotations:
  labels:
    app: wordpress-nginx
  name: sample-secrets
  resourceVersion: "88538"
  selfLink: /api/v1/namespaces/default/secrets/sample-secrets
  uid: 25ae681a-baa2-4239-9dfc-60ad0c8699fa
type: Opaque

Fantastic! Now it’s time to update the deployment file so that the secrets can be used as well:

cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
  labels:
    app: wordpress-nginx
  name: wordpress-nginx
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: wordpress-nginx
  strategy:
    type: RollingUpdate
  template:
    metadata:
      annotations:
      labels:
        app: wordpress-nginx
    spec:
      affinity:
        podAntiAffinity:                                 
          requiredDuringSchedulingIgnoredDuringExecution:
          - topologyKey: kubernetes.io/hostname
            labelSelector:          
              matchLabels:
                app: wordpress-nginx
      containers:
      - image: gcr.io/bearmoo-cloud-net/wordpress-nginx
        imagePullPolicy: Always
        name: wordpress-nginx
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /wp-login.php
            port: 80
            scheme: HTTP
          initialDelaySeconds: 20
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 5
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /wp-login.php
            port: 80
          initialDelaySeconds: 20
          periodSeconds: 10
          successThreshold: 2
          timeoutSeconds: 5
        resources:
          limits:
            memory: 256Mi
          requests:
            cpu: 20m
            memory: 256Mi
        securityContext:
          allowPrivilegeEscalation: false
          privileged: false
          procMount: Default
          readOnlyRootFilesystem: false
          runAsNonRoot: false
        envFrom:
        - configMapRef:
            name: sample-configmaps
        - secretRef:
            name: wordpress-nginx-secrets

Now doing an apply of the file:


kubectl apply -f deployment.yaml

Apply the modified file, Kubernetes will change the state of the deployment for our app based on what the file describes. Now to check if it’s the variables are there:

kubectl exec -it wordpress-nginx-jj13123klj-gj981 /bin/bash
# env
...
IntIpAddress=10.42.0.0/16
PASSWORD: randompassword 
IntIpAddress: "192.168.0.0/24"
HOSTNAME: www.bearmoo.net
RUNAS: apache
...

Nice! I can see that the variables are inside of the container, and our deployment YAML file is a little simpler to read. All so reducing the possibility of the password getting logged in a logging program such as Splunk.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: