Docker Certified Associate Exam Course

Kubernetes

Secrets

Welcome to this lesson on Kubernetes Secrets. In this guide, we’ll refactor a simple Python web app that connects to MySQL and demonstrate how to replace hardcoded credentials with Kubernetes Secrets.

Warning

Hardcoding sensitive data like database passwords in your application is insecure. Always store secrets in a dedicated secret store rather than plain text files or code.

1. Application Overview

Here’s the original Flask application with hardcoded credentials:

import mysql.connector
from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def main():
    mysql.connector.connect(
        host="mysql",
        database="mysql",
        user="root",
        password="paswrd"
    )
    return render_template("hello.html", color=fetchcolor())

if __name__ == "__main__":
    app.run(host="0.0.0.0", port="8080")

By externalizing configuration into ConfigMaps and Secrets, we improve security and flexibility.

2. Storing Non-sensitive Configuration

Use a ConfigMap for non-sensitive data such as hostnames and users:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DB_Host: mysql
  DB_User: root

Avoid placing DB_Password here—this belongs in a Secret.

3. Creating Kubernetes Secrets

There are two ways to create Secrets in Kubernetes:

MethodCommand PatternDescription
Imperativekubectl create secret generic <name> --from-literal=<key>=<value>Quick, ad-hoc creation from the CLI
DeclarativeCreate a YAML manifest with base64-encoded values and apply via kubectl apply -f <manifest>.yamlVersion-controlled, repeatable deployment manifests

3.1 Imperative Method

Generate a generic Secret directly:

kubectl create secret generic app-secret \
  --from-literal=DB_Host=mysql \
  --from-literal=DB_User=root \
  --from-literal=DB_Password=paswrd

Or load from files:

kubectl create secret generic app-secret \
  --from-file=DB_Host=./db_host.txt \
  --from-file=DB_User=./db_user.txt \
  --from-file=DB_Password=./db_password.txt

3.2 Declarative Method

  1. Base64-encode each value:

    echo -n 'mysql'    | base64  # bXlzcWw=
    echo -n 'root'     | base64  # cm9vdA==
    echo -n 'paswrd'   | base64  # cGFzd3Jk
    
  2. Create app-secret.yaml:

    apiVersion: v1
    kind: Secret
    metadata:
      name: app-secret
    type: Opaque
    data:
      DB_Host: bXlzcWw=
      DB_User: cm9vdA==
      DB_Password: cGFzd3Jk
    
  3. Apply the manifest:

    kubectl apply -f app-secret.yaml
    

Note

The type: Opaque is the default Secret type for arbitrary user-defined data.
Learn more in the Kubernetes Secrets documentation.

4. Viewing Secrets

  • List all Secrets:
    kubectl get secrets
    
  • Describe a Secret (values are masked):
    kubectl describe secret app-secret
    
  • View encoded data in YAML:
    kubectl get secret app-secret -o yaml
    
  • Decode a specific value:
    echo -n 'bXlzcWw=' | base64 --decode
    # mysql
    

5. Injecting Secrets into Pods

5.1 As Environment Variables

Inject all keys at once:

apiVersion: v1
kind: Pod
metadata:
  name: simple-webapp
spec:
  containers:
    - name: simple-webapp
      image: simple-webapp:latest
      ports:
        - containerPort: 8080
      envFrom:
        - secretRef:
            name: app-secret

Or inject specific keys:

      env:
        - name: DB_Password
          valueFrom:
            secretKeyRef:
              name: app-secret
              key: DB_Password

5.2 As Files in a Volume

Mount the Secret as a read-only volume; each key becomes a file:

apiVersion: v1
kind: Pod
metadata:
  name: simple-webapp
spec:
  containers:
    - name: simple-webapp
      image: simple-webapp:latest
      volumeMounts:
        - name: app-secret-volume
          mountPath: /etc/secrets
          readOnly: true
  volumes:
    - name: app-secret-volume
      secret:
        secretName: app-secret

Inside the container:

ls /etc/secrets
cat /etc/secrets/DB_Password
# paswrd

Watch Video

Watch video content

Previous
ConfigMaps