Deploy ConfigMaps and Secrets in Red Hat OpenShift Kubernetes Cluster
Jasper Rodda
Posted on January 17, 2024
Applications are often written to connect to a database to read and write information. Hardcoding database connection details, port, username and password is the most insecure way and hard to manage at scale. So, Kubernetes solves this problem via ConfigMaps
and Secrets
.
Two ways to store data
-
ConfigMap: Used to store insensitive data such as
db-port
via anEnvironment variable
or aFile
orVolume Mounts
. -
Secret: Used to store and encrypt sensitive data at rest such as
database username
ordatabase password
etcd is a
data store
in Kubernetes which is used to store all created resources as objects. Resources such aPod
,Deployment
,Service
,Ingress
,ConfigMap
are stored inectcd
as plain objects. however, withsecrets
,etcd
stored the information andencrypts
the data at rest inbase64
encoded.
1. Deploying ConfigMap in Kubernetes
- 1.a) ConfigMap via Env Variable
- 1.b) ConfigMap via File - Volume Mount
1.a) Deploy ConfigMap via Env Variable
- create
configmap.yml
file as below
apiVersion: v1
kind: ConfigMap
metadata:
name: py-app-configmap
data:
db-port: "3306"
- Login to OpenShift Kubernetes cluster
oc login --token=sha256~asf9879SDAF987sd987sdf --server=https://api.sandbox-m3.1530.p1.openshiftapps.com:6443
- Deploy
Configmap
$ kubectl apply -f configmap.yml
configmap/py-app-configmap created
- verify
ConfigMap
-$ kubectl get cm
|kubectl get configmap
$ kubectl get configmap
NAME DATA AGE
config-service-cabundle 1 2d15h
config-trusted-cabundle 1 2d15h
kube-root-ca.crt 1 2d15h
openshift-service-ca.crt 1 2d15h
py-app-configmap 1 37s
- Kubectl Describe ConfigMap -
$kubectl describe cm py-app-configmap
$kubectl describe cm py-app-configmap
Name: py-app-configmap
Namespace: jasper475-dev
Labels: <none>
Annotations: <none>
Data
====
db-port:
----
3306
BinaryData
====
Events: <none>
- Deploy
Pods
and appendingconfigMap
usingdeployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-python-deployment
labels:
app: sample-python-app
spec:
replicas: 5
selector:
matchLabels:
app: sample-python-app
template:
metadata:
labels:
app: sample-python-app
spec:
containers:
- name: python-app
image: jasper475/d37-k8s-services-py-django-app:v2
env:
- name: DB-PORT
valueFrom:
configMapKeyRef:
name: py-app-configmap
key: db-port
ports:
- containerPort: 8000
- deployed Pods
kubectl apply -f deploy.yaml
deployment.apps/sample-python-deployment created
- get Pods and ssh into it to get env variable
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
sample-python-deployment-5787bd6b9f-5n779 1/1 Running 0 69s
sample-python-deployment-5787bd6b9f-h6th2 1/1 Running 0 69s
sample-python-deployment-5787bd6b9f-sft22 1/1 Running 0 69s
sample-python-deployment-5787bd6b9f-w7s56 1/1 Running 0 69s
sample-python-deployment-5787bd6b9f-xncfd 1/1 Running 0 69s
- SSH into a pod
- Command:
kubectl exec -it sample-python-deployment-5787bd6b9f-5n779 -- /bin/bash
and Search(grep) for Env variableDB-PORT
- Dev inside python app can retrieve via:
OS.env("DB-PORT")
$ kubectl exec -it sample-python-deployment-c57769684-749ct -- /bin/bash
groups: cannot find name for group ID 1011150000
1011150000@sample-python-deployment-c57769684-749ct:/app$ ls
db.sqlite3 demo devops manage.py requirements.txt
1011150000@sample-python-deployment-c57769684-749ct:/app$ env | grep DB
DB-PORT=3306
NSS_SDB_USE_CACHE=no
- Edit DB-PORT via configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: py-app-configmap
data:
db-port: "3307"
- Apply changes
kubectl apply -f configmap.yml
$ kubectl apply -f configmap.yml
configmap/py-app-configmap configured
- Notice config map Port changed to 3307
- SSH into the POD to get Environment variable value. Notice it is still having OLD Value.
DB-PORT=3306
1011150000@sample-python-deployment-c57769684-749ct:/app$ env | grep DB
DB-PORT=3306
NSS_SDB_USE_CACHE=no
1011150000@sample-python-deployment-c57769684-749ct:/app$
We cannot afford to restart pod in production - to Fix this issue we use Volume Mounts and persist config values and decouple it from pod application restarts and config changes.
1.b) Deploy ConfigMap via File - Volume Mount
deploy_volume_Mount.yaml
filecreate volume under
container
spec:
containers:
|
|
volumes:
- name: db-connection
configMap:
name: py-app-configmap
- Mount volume: provide
volume name
andvolume path
spec:
containers:
- name: python-app
image: jasper475/d37-k8s-services-py-django-app:v2
volumeMounts:
- name: db-connection
mountPath: /opt
- apply deployment changes
$ kubectl apply -f deploy_volume_mount.yaml
deployment.apps/sample-python-deployment configured
- Get Pods
kubectl get pods
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
sample-python-deployment-7b67d95fdc-56p4g 1/1 Running 0 37s
sample-python-deployment-7b67d95fdc-5sdcx 1/1 Running 0 37s
sample-python-deployment-7b67d95fdc-5v2r8 1/1 Running 0 35s
sample-python-deployment-7b67d95fdc-74sb8 1/1 Running 0 35s
sample-python-deployment-7b67d95fdc-cs9px 1/1 Running 0 37s
- SSH into pod as see ENV variable:
- Notice: There is no environment variable - because
deploy_volume_mount.yaml
file, since we removed it.
$ kubectl exec -it sample-python-deployment-7b67d95fdc-56p4g -- /bin/bash
1011150000@sample-python-deployment-7b67d95fdc-56p4g:/app$ env | grep DB
NSS_SDB_USE_CACHE=no
1011150000@sample-python-deployment-7b67d95fdc-56p4g:/app$
- Notice : volume is mounted on
/opt
path andport: 3307
1011150000@sample-python-deployment-7b67d95fdc-56p4g:/app$ ls /opt
db-port
1011150000@sample-python-deployment-7b67d95fdc-56p4g:/app$ cat /opt/db-port | more
3307
- Change Port to
3308
inconfigmap.yml
and apply
apiVersion: v1
kind: ConfigMap
metadata:
name: py-app-configmap
data:
db-port: "3308"
- apply changes:
Kubectl apply -f configmap.yml
- describe configmap :
$ kubectl describe cm py-app-configmap
$ kubectl describe cm py-app-configmap
Name: py-app-configmap
Namespace: jasper475-dev
Labels: <none>
Annotations: <none>
Data
====
db-port:
----
3308
BinaryData
====
Events: <none>
- SSH into POD and get Port info -
kubectl exec -it sample-python-deployment-7b67d95fdc-56p4g -- /bin/bash
$ kubectl exec -it sample-python-deployment-7b67d95fdc-56p4g -- /bin/bash
groups: cannot find name for group ID 1011150000
1011150000@sample-python-deployment-7b67d95fdc-56p4g:/app$ env | grep DB
NSS_SDB_USE_CACHE=no
1011150000@sample-python-deployment-7b67d95fdc-56p4g:/app$ ls /opt
db-port
1011150000@sample-python-deployment-7b67d95fdc-56p4g:/app$ cat /opt/db-port | more
3308
2. Deploying ConfigMap in Kubernetes
- create a
Secret
via CLI command kubectl create secret generic - to store passwords
-
kubectl create secret tls - to store certificates
$ kubectl create secret generic empty-secret
secret/empty-secret created
$ kubectl get secret empty-secret
NAME TYPE DATA AGE
empty-secret Opaque 0 19s
or
$ kubectl create secret genericmy-db-secret --from-literal=db-port="3308"
or
- Create secret via
basic_secret.yaml
file
apiVersion: v1
kind: Secret
metadata:
name: secret-basic-auth
type: kubernetes.io/basic-auth
stringData:
username: admin # required field for kubernetes.io/basic-auth
password: t0p-Secret # required field for kubernetes.io/basic-auth
- apply :
kubectl apply -f basicsecret.yaml
$ kubectl apply -f basic_secret.yaml
secret/secret-basic-auth created
$ kubectl get secret secret-basic-auth
NAME TYPE DATA AGE
secret-basic-auth kubernetes.io/basic-auth 2 17s
PS C:\Users\Jasper\OneDrive\Documents\CodeRepo\kubernetes\d41_ConfigMaps_Secrets>
- Verify Secrets
- Describe
Secret
kubectl describe secret secret-basic-auth
Name: secret-basic-auth
Namespace: jasper475-dev
Labels: <none>
Annotations: <none>
Type: kubernetes.io/basic-auth
Data
====
password: 10 bytes
username: 5 bytes
- Edit secret:
kubectl edit secret secret-basic-auth
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
password: dDBwLVNlY3JldA==
username: YWRtaW4=
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"secret-basic-auth","namespace":"jasper475-dev"},"stringData":{"password":"t0p-Secret","username":"admin"},"type":"kubernetes.io/basic-auth"}
creationTimestamp: "2024-01-17T20:02:39Z"
name: secret-basic-auth
namespace: jasper475-dev
resourceVersion: "1769551165"
uid: 46bf94fa-c060-4f6b-83d6-9e08a4637b25
type: kubernetes.io/basic-auth
- Verify Secrets: By default, they are encoded
Base64
Jasper@JASPERS-PC MINGW64 ~/OneDrive/Documents/CodeRepo/kubernetes/d41_ConfigMaps_Secrets
$ echo dDBwLVNlY3JldA== | base64 --decode
t0p-Secret
Jasper@JASPERS-PC MINGW64 ~/OneDrive/Documents/CodeRepo/kubernetes/d41_ConfigMaps_Secrets
$ echo YWRtaW4= | base64 --decode
admin
Credits:-
Thanks to Abhishek Veeramalla
Posted on January 17, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.