Previously we created an application and hard-coded the password for accessing the database (bad). In this tutorial, we will learn about Kubernetes Secrets and how to use them to store sensitive information in a safer way.
Series
This is Part 7 of the 9-part series:
- Kubernetes Part 1: Core Concepts and Installation (Minikube)
- Kubernetes Part 2: Python Flask Application Deployment
- Kubernetes Part 3: MySQL Database Deployment
- Kubernetes Part 4: Application Deployments (The Smart Way - YAML Files)
- Kubernetes Part 5: Linking Application with Database (Discovery)
- Kubernetes Part 6: Rolling Updates
- Kubernetes Part 7: Secrets
- Kubernetes Part 8: Persistent Volumes
- Kubernetes Part 9: ConfigMaps
Secrets
Secrets are a nice feature of Kubernetes that enable secure storage and use of sensitive information within a cluster. First, have a look at the Secrets within Kubernetes, which include some default tokens for access:
As with many of the Kubernetes objects, there are multiple ways to create secrets, both command-line based as well as YAML configuration file-based. Given we have learned and are using YAML configuration files for our application, we will create a YAML configuration file for the database user password Secret. There is one extra step involved in creating a Secret configuration file which is to base64-encode the sensitive values prior to placing them into the YAML configuration file:
Next, we will take the base64-encoded value and place it into our Secret YAML file, named secret.yml
:
apiVersion: v1
kind: Secret
metadata:
name: mysql-password
type: Opaque
data:
mysql_password: UGFzc3cwcmQ=
Save the file above and then run the kubectl
command to create the secret:
Now that we have a secret created within the cluster, let’s use it in the application. Again, there are
multiple ways you can present a secret to a Pod - either using a file mount or via environment variables.
To keep things clean, we will explore the environment variable option. To do this, we will edit the
Deployment YAML configuration file to replace the clear-text password with a reference to the Secret we
just created. Edit the app-deployment.yml
file and add the following to the
.spec.template.spec.containers[0].env
section, right after the MYSQL_DB_HOST
parameter:
...
- name: MYSQL_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-password
key: mysql_password
...
We will now update our application to use the environment variable to connect to the database. Update
the app/__init__.py
file to utilize the env var and specify version 5 to ensure we can validate that
the application was deployed easily:
import os
from flask import Flask
import socket
import mysql.connector
app = Flask(__name__)
@app.route('/')
def hello():
# construct HTML output
html = "<h3>Hello World from {hostname}!</h3>"
html += "<h3>Your random word is: {random_word}</h3>"
html += "<h3>The version of this app is: {version}</h3>"
# yes, this is a terrible way to do this, but it works/is simple
db = mysql.connector.connect(
host=os.getenv("MYSQL_SERVICE_HOST"),
port=os.getenv("MYSQL_SERVICE_PORT"),
user="root",
passwd=os.getenv("MYSQL_DB_PASSWORD"),
database="randomizer",
auth_plugin="mysql_native_password"
)
cursor = db.cursor()
cursor.execute("select word from random_words order by rand() limit 1;")
res = cursor.fetchall()
return html.format(random_word=res[0][0], version="5.0", hostname=socket.gethostname())
We will now make the update to our app-deployment.yml
file to prepare for the rolling update. First, create the
new version of the Docker image. Then, edit the YAML configuration file to use the new image version and perform
the rolling update:
You’ll note we added yet another way to perform a rolling update via the kubectl apply
command - this is probably
one of the more useful ways to perform this activity due to this method maintaining configuration state in the local
files and not having to remember which configurations have made their way into the cluster yet.
You can first check that the environment variables are present in the Pods via connecting to a shell for one of the
deployed Pods and then using the printenv
command:
Next, refresh your web page - you should see the new version of the application and a random word indicating that the application successfully loaded and used the MySQL root password from the environment variable loaded via the Kubernetes Secret!
Next Steps
We now have a way to store sensitive information - in the next post we’ll explore how to create storage for persisting information so when Pods/Containers are cycled the data can persist. Additionally, the volumes can be used for shared state information across a horizontally-scaled application.
Credit
The above tutorial was pieced together with some information from the following sites/resources: