Skip to content

Secret Management

Whilst secrets inside Safespring On-demand Kubernetes are encrypted at rest the ecosystem of secret management inside a Kubernetes cluster is diverse with solutions each with various features:

SOPS Operator with Age Key

This guide walks you through setting up the SOPS operator in Kubernetes to automatically decrypt secrets encrypted with SOPS using Age encryption.

An alternative implementation of SOPS is presented by Sops Operator which focuses on complex scenario most of which valid in a multi-tenant environment.

For following this guide it is required:

  • kubeconf-demo is obtained for that specific cluster and active in current shell via KUBECONFIG environment variable or specified via --kubeconfig flag for helm and kubectl command line tools.
  • age CLI tool installed locally
  • sops CLI tool installed locally

Install SOPS Operator

Install the SOPS operator using Helm:

# Add the SOPS operator Helm repository
helm repo add sops https://isindir.github.io/sops-secrets-operator/
helm repo update

# Create a namespace for the operator
kubectl create namespace sops-operator

# Install the operator
helm install sops-operator sops/sops-secrets-operator \
  --namespace sops-operator \
  --set replicaCount=1

Verify the installation:

kubectl get pods -n sops-operator

Generate an Age Key

First, generate an Age key pair that will be used for encryption/decryption:

AGE_KEY_FILE=$(mktemp)
echo "========================"
echo "Public Age key"
age-keygen > "$AGE_KEY_FILE"
echo "========================"

# we will use this when we create the sops-encryption for the cluster
public_age_key=$(grep -oP "public key: \K(.*)" "${AGE_KEY_FILE}")

Save the public key (starts with age1...) for encrypting secrets and the private key (starts with AGE-SECRET-KEY-1...) for the operator to decrypt.

Create a Kubernetes Secret with the Age Key

Create a secret containing your Age private key:

kubectl create secret generic age-key -n sops-operator \
     --from-file=keys.txt="${AGE_KEY_FILE}" \
     --dry-run=client -o yaml | kubectl apply -f -

Example Usage

Configure SOPS to Use Age Key

Create a .sops.yaml configuration file in your project directory:

creation_rules:
  - age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Replace the public key with your actual Age public key.

Encrypt a Secret with SOPS

Create a sample Kubernetes secret file:

# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
  namespace: default
type: Opaque
stringData:
  username: admin
  password: supersecret123

Encrypt it with SOPS:

sops --encrypt --age age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
  --encrypted-regex '^(data|stringData)$' \
  secret.yaml > secret.enc.yaml

Create a SopsSecret Resource

The SOPS operator uses custom SopsSecret resources. Convert your encrypted secret:

# sops-secret.yaml
apiVersion: isindir.github.com/v1alpha3
kind: SopsSecret
metadata:
  name: my-sops-secret
  namespace: default
spec:
  secretTemplates:
    - name: my-secret
      stringData:
        username: ENC[AES256_GCM,data:xxxxx,type:str]
        password: ENC[AES256_GCM,data:xxxxx,type:str]

Or simply point to your encrypted file and apply it directly if it's in the correct format.

Configure the Operator for SopsSecret

Create a configuration to tell the operator where to find the Age key:

# sops-secret-with-age.yaml
apiVersion: isindir.github.com/v1alpha3
kind: SopsSecret
metadata:
  name: my-sops-secret
  namespace: default
  annotations:
    # Tell the operator to use the Age key from the secret
    sops.secrets-operator/age-key-secret: sops-age-key
    sops.secrets-operator/age-key-namespace: sops-operator
spec:
  secretTemplates:
    - name: my-decrypted-secret
      stringData:
        username: ENC[AES256_GCM,data:xxxxx,type:str]
        password: ENC[AES256_GCM,data:xxxxx,type:str]

Apply the resource:

kubectl apply -f sops-secret-with-age.yaml

Alternative: Global Age Key Configuration

Instead of annotating each SopsSecret, you can configure the operator to use the Age key globally by updating the Helm values:

helm upgrade sops-operator sops/sops-secrets-operator \
  --namespace sops-operator \
  --set secrets.ageKey.secret=sops-age-key \
  --set secrets.ageKey.key=age-key.txt