Kubernetes Secrets and Pod Restarts

Read Time 10 mins | Written by: Caleb Mabry

If you’re deploying apps into a Kubernetes cluster, chances are you’re already drowning in YAML wonderland and wondering why the pods aren’t just reading the new secret like you told them to. This article will teach you how to successfully restart a pod in several different ways.

It’s important to remember that secrets are the way to hand over sensitive info like database passwords, API keys, or “definitely-not-12345” credentials to your containers. While Kubernetes has built in secret support, it’s not so great at telling your pods “Hey, you, your password changed.” 

 

Regular Kubernetes Secrets

Creating a Basic Secret

The most straightforward way to manage secrets is to define them directly in your cluster. These are base64-encoded which are kind of like writing your password in invisible ink. While it’s hidden from casual glances, anyone who knows how to read base64 can still see you’ve been lazy.

apiVersion: v1
kind: Secret
metadata:
  name: app-credentials
  namespace: default
type: Opaque
data:
  username: YWRtaW4=        # base64 encoded "admin"
  password: cGFzc3dvcmQx    # base64 encoded "password1"

Using the Secret in a Deployment

Once you’ve created your secret, you can inject it into your deployments as environment variables. However, once the pod starts, it reads the secrets… and then never asks again. You can change the secret all you want, but unless you give the pod a firm reboot, it’ll keep using the old values like nothing happened.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: app
        image: nginx:1.21
        env:
        - name: DB_USERNAME
          valueFrom:
            secretKeyRef:
              name: app-credentials
              key: username
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: app-credentials
              key: password

External Secrets

Managing secrets inside Kubernetes works until your setup gets more complex. Most production environments store secrets in external systems like AWS Secrets Manager or HashiCorp Vault. These tools handle rotation, versioning, and access control better than Kubernetes alone.

Installing External Secrets Operator

The External Secrets Operator, or ESO, connects Kubernetes to those systems. It pulls secret values and creates regular Kubernetes Secrets automatically. Your app still reads the secrets as if nothing changed. Once set up, ESO keeps everything in sync. If the secret changes in AWS, Kubernetes gets the update without you needing to do anything. It's simple, reliable, and lets you focus on building, not babysitting credentials.

helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets -n external-secrets-system --create-namespace

ExternalSecret Example (AWS Secrets Manager)

apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: vault-secret
  namespace: default
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: SecretStore
  target:
    name: app-credentials-external
    creationPolicy: Owner
  data:
  - secretKey: username
    remoteRef:
      key: prod/myapp/credentials
      property: username
  - secretKey: password
    remoteRef:
      key: prod/myapp/credentials
      property: password

SecretStore Configuration

apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
  name: aws-secrets-manager
  namespace: default
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-east-1
      auth:
        secretRef:
          accessKeyID:
            name: aws-credentials
            key: access-key-id
          secretAccessKey:
            name: aws-credentials
          key: secret-access-key

Using ExternalSecret in Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-secret-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: external-secret-app
  template:
    metadata:
      labels:
        app: external-secret-app
    spec:
      containers:
      - name: app
        image: nginx:1.21
        env:
        - name: DB_USERNAME
          valueFrom:
            secretKeyRef:
              name: app-credentials-external  # Created by ExternalSecret
              key: username
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: app-credentials-external
              key: password

Restarting Pods When Secrets Change

Method 1: Manual Restart

This is the simplest way. Just restart the deployment and your pods will reload the new secrets. It works fine for occasional changes but can be a pain if you rotate secrets often.

# Restart deployment when secret is updated
kubectl rollout restart deployment/web-app
kubectl rollout restart deployment/external-secret-app

Method 2: Using Stakater Reloader

If you want Kubernetes to do the heavy lifting, you can use Stakater Reloader. It watches for changes to secrets and automatically restarts pods that use them. Just install it once and add an annotation to your deployments. After that, it handles restarts for you.

Install Reloader:

kubectl apply -f 
https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml

Add annotation to the deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: auto-restart-app
  annotations:
    reloader.stakater.com/auto: "true"
spec:
  replicas: 2
  selector:
    matchLabels:
      app: auto-restart-app
  template:
    metadata:
      labels:
        app: auto-restart-app
    spec:
      containers:
      - name: app
        image: nginx:1.21
        env:
        - name: SECRET_VAL
          valueFrom:
            secretKeyRef:
              name: app-credentials
              key: password

Method 3: Annotation-Based Restart Trigger

Another trick is to update an annotation on your pod template. Kubernetes sees that as a change and rolls out new pods. It’s manual but cleaner than restarting the whole deployment. You can even script it if you want a DIY automation setup.

Update deployment with changing annotation:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: manual-trigger-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: manual-trigger-app
  template:
    metadata:
      labels:
        app: manual-trigger-app
      annotations:
        # Change this value to trigger restart
        restart-trigger: "v1"
    spec:
      containers:
      - name: app
        image: nginx:1.21
        env:
        - name: SECRET_VAL
          valueFrom:
            secretKeyRef:
              name: app-credentials
              key: password

 

Conclusion

Secrets are just one of those things that you don’t think about until everything breaks. You could be hardcoding bas64 in YAML or pulling secrets with ExternalSecrets. At the end of the day, the goal is to make sure you keep sensitive stuff safe and make sure your apps can use it.

If you are looking for a simple and reliable solution, you can just use Stakater Reloader. It’s easy to install, works out of the box, and can keep your apps in sync without needing any manual steps. One annotation and your pods are successfully restarting when a secret changes.

 

 

Caleb Mabry

Software Engineer@ASCENDING