Kubernetes – Secrets
February 25, 2019Secret, Secret, I’ve got a secret! OK, enough of the Styx lyrics, this is serious business. In the previous post we used ConfigMaps to store a database connection string. That is probably not the best idea for something with a sensitive password in it. Luckily Kubernetes provides a way to store sensitive configuration items and its called a “secret”.
Secrets – The Theory
The short answer to understanding secrets would be to think of a ConfigMap, which we have discussed in a previous post in this series, but with non-clear text.
ConfigMaps would be good to store configuration data that is not sensitive. If it is sensitive information that not everyone should see, then a “secret” should be chosen over a ConfigMap. Password, keys, or private information should be stored as a secret instead of a ConfigMap.
One thing to note is that secrets can be stored a either “data” or “stringData” maps. Data would be used to store a secret in base64 format which you would provide. You can also use stringData which you’d provide an unencoded string but it would be stored as a base64 string when the secret is create. This is a valuable tool when your deployment creates a secret as part of the build process.
Secrets – In Action
Since a secret is just a more secured version of a ConfigMap, the demo will be the same as the last post, with the exception that we’ll use a secret over a ConfigMap to store our connection string. This is a better way to store a connection string over a ConfigMap because it does have a password in it which should be protected.
First, we’ll deploy the database container and service. The database container has already been configured with new database with the appropriate username and password. The manifest file to deploy the DB and service is listed below.
apiVersion: apps/v1
kind: Deployment
metadata:
name: hollowdb
labels:
app: hollowdb
spec:
replicas: 1
selector:
matchLabels:
app: hollowdb
template:
metadata:
labels:
app: hollowdb
spec:
containers:
- name: mysql
image: theithollow/hollowapp-blog:dbv1
imagePullPolicy: Always
ports:
- containerPort: 3306
---
apiVersion: v1
kind: Service
metadata:
name: hollowdb
spec:
ports:
- name: mysql
port: 3306
targetPort: 3306
protocol: TCP
selector:
app: hollowdb
We’ll deploy a new secret from a manifest after we take our connection string and convert it to base64. I took the following connection string:
mysql+pymysql://hollowapp:Password123@hollowdb:3306/hollowapp
Code language: JavaScript (javascript)
then ran it through a bash command of:
echo -n 'mysql+pymysql://hollowapp:Password123@hollowdb:3306/hollowapp' | base64
Code language: PHP (php)
I took the result of that command and placed int in the Secret manifest under the db.string map.
apiVersion: v1
kind: Secret
metadata:
name: hollow-secret
data:
db.string: bXlzcWwrcHlteXNxbDovL2hvbGxvd2FwcDpQYXNzd29yZDEyM0Bob2xsb3dkYjozMzA2L2hvbGxvd2FwcA==
Deploy the secret via a familiar command we’ve used for deploying our manifests.
kubectl apply -f [manifest file].yml
Code language: CSS (css)
Now that the secret is deployed, we can deploy our application pods which will connect to the backend database just as we did with a ConfigMap in a previous post. The important difference between the Deployment manifest using a ConfigMap and the Deployment manifest using a secret is this section.
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: hollow-secret
key: db.string
Code language: CSS (css)
The full deployment file that will read from the secret and use that secret is listed below.
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: hollowapp
name: hollowapp
spec:
replicas: 3
selector:
matchLabels:
app: hollowapp
strategy:
type: Recreate
template:
metadata:
labels:
app: hollowapp
spec:
containers:
- name: hollowapp
image: theithollow/hollowapp-blog:allin1
imagePullPolicy: Always
ports:
- containerPort: 5000
env:
- name: SECRET_KEY
value: "my-secret-key"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: hollow-secret
key: db.string
---
apiVersion: v1
kind: Service
metadata:
name: hollowapp
labels:
app: hollowapp
spec:
type: ClusterIP
ports:
- port: 5000
protocol: TCP
targetPort: 5000
selector:
app: hollowapp
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hollowapp
labels:
app: hollowapp
spec:
rules:
- host: hollowapp.hollow.local
http:
paths:
- path: /
backend:
serviceName: hollowapp
servicePort: 5000
Code language: PHP (php)
Deploy the manifest using:
kubectl apply -f [manifest file].yml
Code language: CSS (css)
The result is that the app reads from the secret file, and uses that string as part of the connection to the backend database.
Summary
Sometimes you’ll want to store non-sensitive data and a ConfigMap is the easy way to store that data. In other cases, the data shouldn’t be available to everyone, like in the case of a password or a connection string. When those situations occur, a secret may be your method to store this data.
[…] authentication through the container runtime, we use the docker config file to create a Kubernetes secret. Run the command below replacing the path to your config file. NOTE: this requires your KUBECONFIG […]
[…] 12. Secrets […]