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.