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
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.