ConfigMaps and Secrets - Chapter 13
While Deploying an application, we may need to pass runtime paramaters like passwords, config details, or passwords. We can use the ConfigMap for runtime parameters and for sensitive Information we can use the Secret API resource.
- Discuss configuration management for applications in Kubernetes using ConfigMaps.
- Share sensitive data (such as passwords) using Secrets.
ConfigMaps
ConfigMaps allow us to decouple the configuration details from the container image. In the form of environment variables, sets of commands and arguments, or volumes, we can pass configuration data, which then are consumed by Pods. We can create ConfigMaps from literal values, from configuration files, from one or more files or directories.
Create from Literal Values
As with other objects we can create and display ConfigMaps by using the kubectl
CLI.
We are going to create the ConfigMap and display the Details
$ kubectl create configmap my-config --from-literal=key1=value1 --from-literal=key2=value2
configmap/my-config created
$ kubectl get configmaps my-config -o yaml
We can see in the output, in yaml format, our passed values in the data field. The name and other details are part of the metadata field.
Create from Configuration File
We specify the kind, metadata
and data
fields, targeting the v1 endpoint.
apiVersion: v1
kind: COnfigMap
metadata:
name: customer1
data:
TEXT1: Customer1_Company
TEXT2: Welcomes You
COMPANY: Customer1 Company Technology Ltd.
$ kubectl create -f customer1-configmap.yaml
configmap/customer1 created
Create a ConfigMap from a File
We are going to create a file called permission-reset.properties
permission=read-only
allowed="true"
resetCount=3
And create the ConfigMap with kubectl
.
$ kubectl create configmap permission-config --from-file=./permission-reset.properties
configmap/permission-config created
Use ConfigMaps inside Pods
Inside the container, we retrieve key-value data or values as environment variables.
...
containers:
- name: myapp-full-container
image: myapp
envFrom:
- configMapRef:
name: full-config-map
...
This configuration will give the myapp-full-container the values of full-config-map as environment variables.
It is also possible to specify two seperate ConfigMaps from which the container should receive its environment variables.
...
containers:
- name: myapp-specific-container
image: myapp
env:
- name: SPECIFIC_ENV_VAR1
valueFrom:
configMapKeyRef:
name: config-map-1
key: SPECIFIC_DATA
- name: SPECIFIC_ENV_VAR2
valueFrom:
configMapKeyRef:
name: config-map-2
key: SPECIFIC_INFO
...
We will get the SPECIFIC_ENV_VAR1 variable set to SPECIFIC_DATA key of config-map-1, and SPECIFIC_ENV_VAR2 set to SPECIFIC_INFO key from config-map-2.
A Volume can be configured inside a Pod. For each key in the ConfigMap, a file gets created inthe mount path and the content of that file becomes the respective key's value:
...
containers:
- name: myapp-vol-container
image: myapp
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: vol-config-map
...
How to configure pod ConfigMaps can be found here. Also some Hands on examples are given.
Secrets
Secrets are similar to ConfigMaps, but we are able to control how the information in a Secre is used, reducing the risk for accidental exposures. In Deployments or other resources, the Secret object is referenced, wihtout exposing its content.
Caution:
Kubernetes Secrets are, by default, stored as unencrypted base64-encoded strings. By default they can be retrieved - as plain text - by anyone with API access, or anyone with access to Kubernetes' underlying data store, etcd. In order to safely use Secrets, we recommend you (at a minimum):
Enable Encryption at Rest for Secrets.
Enable RBAC rules that restrict reading and writing the Secret. Be aware that secrets can be obtained implicitly by anyone with the permission to create a Pod.
Create a Secret from literal
We can create secrets by using the kubectl
CLI and view the details, although they will not reveal the content of the Secret.
$ kubectl create secret generic my-password --from-literal=password=mysqlpassword
secret/my-password created
$ kubectl get secret my-password
NAME TYPE DATA AGE
my-password Opaque 1 27s
$ kubectl describe secret my-password
Name: my-password
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 13 bytes
Create a Secret Manually
First we encode the password using base64
and then use it in the configuration file.
echo mysqlpassword |base64
bXlzcWxwYXNzd29yZAo=
---
apiVersion: v1
kind: Secret
metadata:
name: my-password
type: Opaque
data:
password: bXlzcWxwYXNzd29yZAo=
Note that any one can decode our encoded string, base64 doesn't mean encryption.
With stringData
maps, there is no need to encode the value of each sensitive information field. The value of the sensitive field will be encoded when the password Secret is created. Using mypass.yaml we can use the kubectl create
command.
apiVersion: v1
kind: Secret
metadata:
name: my-password
type: Opaque
stringData:
password: mysqlpassword
$ kubectl create -f mypass.yaml
secret/my-password created
Create a Secret from File and display its details
We are going to encode our sensitive data and then write encoded data to a Text file.
$ echo mysqlpassword | base64
bXlzcWxwYXNzd29yZAo=
$ echo -n 'bXlzcWxwYXNzd29yZAo=' > password.txt
Create the secret from the password.txt file, get
and describe
it.
$ kubectl create secret generic my-file-password --from-file=password.txt
secret/my-file-password created
$ kubectl get secret my-file-password
NAME TYPE DATA AGE
my-file-password Opaque 1 77s
$ kubectl describe secret my-file-password
Name: my-file-password
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password.txt: 20 bytes
Use Secrets inside pods
Just like ConfigMaps, Secrets are consumed by containers in pods as mounted data volumes or as environment variables.
Using secrets as Environment Variables, we'll assing the password key of the my-password Secret.
...
spec:
containers:
- image: wordpress:4.7.3-apache
name: wordpress
env:
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-password
key: password
...
Using secrets as Files from a Pod, where we mount a Secret as a Volume inside a Pod.
....
spec:
containers:
- image: wordpress:4.7.3-apache
name: wordpress
volumeMounts:
- name: secret-volume
mountPath: "/etc/secret-data"
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: my-password
....
For more details and some examples you can visit Managing Secrets.
Hands On
We are going to alter the index.html file inside an nginx container by providing a ConfigMap, lets assume following web-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: web-config
namespace: default
data:
STRING: Welcome to MY-NGINX!
PATH: /usr/share/nginx/html/index.html
We'll create the object and display the web-config with two data fields.
$ kubectl create -f web-config.yaml
configmap/web-config created
$ kubectl describe cm
Name: web-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
PATH:
----
/usr/share/nginx/html/index.html
STRING:
----
Welcome to MY-NGINX!
Events: <none>
Let's assume a app-config.yaml where we create a Pod with a nginx container, which replaces the content of the given DATA_STRING on the given DATA_PATH.
Both these variables will be passed in as environment Variables via the ConfigMap we just created.
apiVersion: v1
kind: Pod
metadata:
name: app-config
spec:
containers:
- name: nginx
image: nginx
command: ["/bin/sh", "-c", "echo $(DATA_STRING) > $(DATA_PATH); sleep 3600" ]
env:
- name: DATA_STRING
valueFrom:
configMapKeyRef:
name: web-config
key: STRING
optional: true
- name: DATA_PATH
valueFrom:
configMapKeyRef:
name: web-config
key: PATH
optional: true
restartPolicy: Never
$ kubectl create -f app-config.yaml
pod/app-config created
This time we will observe the value inside the container by using the kubectl exec
command. And by cat index.html
we will see the content of the file.
$ kubectl exec app-config -- /bin/sh -c 'cat /usr/share/nginx/html/index.html'
Welcome to MY-NGINX!
As we expected the content of the file will be the value we have passed in by the ConfigMap.
The Secrets part of this Hands On would be almost the same. This is how we consume ConfigMaps in our Pods containers. A good way to provide different values for the same containers, without creating several similar containers.
That's it for today folks! There is much more to read and to configure out here. We only went through a simple example, we also know how to consume environmental values in our containers. Be it php, nodejs, .net and what not. This way we will give simple values as well as sensitive information in our containers.