Skip to content

FluxCD with SOPS Encrypted Secrets

This guide shows how to securely manage Kubernetes secrets using SOPS (Secrets OPerationS) with FluxCD. SOPS allows you to encrypt sensitive data in Git repositories while maintaining GitOps workflows.

Why Use Encrypted Secrets?

Benefits of SOPS with FluxCD:

  • Secrets are encrypted at rest in Git
  • GitOps workflows remain intact
  • Only values are encrypted, keeping YAML structure readable
  • Version control for secret management

Prerequisites

  • FluxCD installed and configured in your Kubernetes cluster
  • kubectl configured to access your cluster
  • Windows machine with PowerShell or Command Prompt
  • Git repository configured with FluxCD

Step 1: Install Required Tools

  1. Install SOPS

    Terminal window
    winget install mozilla.sops
  2. Verify SOPS installation

    Terminal window
    sops -v
  3. Install Age encryption tools

    Terminal window
    winget install FiloSottile.age
  4. Verify Age installation

    Terminal window
    age -version
    age-keygen -version

Step 2: Generate Age Encryption Keys

  1. Create SOPS directory

    Terminal window
    mkdir .sops
  2. Generate Age key pair

    Terminal window
    age-keygen -o .sops/age.agekey

    This command outputs your public key and saves the private key to the file.

  3. Note your public key The command output shows your public key:

    Public key: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  4. Secure your private key

    • Store the .sops/age.agekey file securely (password manager, encrypted backup)
    • Never commit this file to Git
    • Add .sops/ to your .gitignore file

Step 3: Add Age Keys to Kubernetes

  1. Create SOPS secret in Kubernetes

    Terminal window
    kubectl create secret generic sops-age --namespace=flux-system --from-file=age.agekey=.sops\age.agekey
  2. Verify the secret was created

    Terminal window
    kubectl get secret sops-age -n flux-system

Step 4: Configure SOPS

You can encrypt secrets in two ways:

Option A: Using Command Line Parameters

You can encrypt with the public key as argument:

Terminal window
sops --age=YOUR-PUBLIC-KEY --encrypt --encrypted-regex '^(data|stringData)$' --in-place secret.yaml
  1. Create SOPS configuration In your repository, create .sops.yaml:

    creation_rules:
    - path_regex: .*.yaml
    encrypted_regex: ^(data|stringData)$
    age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    Replace the age1... value with your actual public key from Step 2.

  2. Organize directory structure

    fluxcd/
    ├── clusters/
    │ └── peercluster/
    │ ├── .sops.yaml # SOPS configuration (age key)
    │ ├── infrastructure.yaml # Flux Kustomization with SOPS decryption
    │ └── apps.yaml # Flux Kustomization with SOPS decryption
    ├── infrastructure/
    └── apps/
    └── peercluster/
    └── app-with-secret/
    └── some-secret.yaml # secret (stringData)

Step 5: Create and Encrypt Secrets

  1. Create a sample secret file Create some-secret.yaml:

    apiVersion: v1
    kind: Secret
    metadata:
    name: some-secret
    type: Opaque
    stringData:
    this_is_a_secret: SuPeRSeCrEt==?
  2. Navigate to the directory with .sops.yaml

    Terminal window
    cd clusters\Peercluster
  3. Encrypt the secret in place

    Terminal window
    sops --encrypt --in-place ..\..\infrastructure\base\app-with-secret\some-secret.yaml
  4. Verify encryption The file now contains encrypted values:

    apiVersion: v1
    kind: Secret
    metadata:
    name: some-secret
    type: Opaque
    stringData:
    this_is_a_secret: ENC[AES256_GCM,data:8hcMtCIZ2+cVEQz93cs=,iv:A5UFzGNdWFF+qAm5trPtVx7ZJLd4wx3XIFOhbfmHo3A=,tag:/aTuBIjNPri/H9knB1+big==,type:str]
    sops:
    kms: []
    gcp_kms: []
    azure_kv: []
    hc_vault: []
    age:
    - recipient: age10kfmy5p7sf744pdvmsfvebbacsd40k9zexe7l6e3se7rcm9j4fvqcpnmgf
    enc: |
    -----BEGIN AGE ENCRYPTED FILE-----
    YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaYVFaVlcreEJsamgwcy8y
    M05teXE3SVM1V1JRUUszSmVKNFZEWXJXMdRNCjFWcldKdHhmS1JDdHVHMUExUTJF
    WGZyMXg0bHBJTGozcWk0Q2RrSUpPbm8KLS0tIGRHS1JLRk1JWFRoVnovcEZSZ09p
    bFRpRGg3Z01pUGlNaTlrcEpjfHhJTXcKhlKemPKREgI15hPrUKRhSVHbootHqZ1V
    THPgxbgU1eQG03ZoYJcOoHpyZLwoD+y/ehzTE732Ra80D8rnm8tmTg==
    -----END AGE ENCRYPTED FILE-----
    lastmodified: '2025-07-22T14:29:39Z'
    mac: ENC[AES256_GCM,data:u2ejyiM2FH9nu2q6bARdVx2gE220LdB3MxSGYEI1x9GcfnAbOPm6Mvs2Bt3skwgwf0/oEpc88DXX0EdG/dRK+eeEfFoMze3NKyji6xPA3KB7URsWxgmLj1Nu9UtBQ8pEXKvft1VLLFywf4UrZ2E2w0SAKQ/4+kVAeDBPotR9ehF=,iv:qbqovmsIuq6ltAP/pcjEv1YNss99eqeD2A4PzYrFQb8=,tag:ul8BlQP8hDk+mXFhEG/BGQ==,type:str]
    pgp: []
    encrypted_regex: ^(data|stringData)$
    version: 3.7.3

Step 6: Configure FluxCD Kustomization

  1. Create secrets kustomization Create kustomization.yaml in your secrets directory:

    apiVersion: kustomize.config.k8s.io/v1beta1
    kind: Kustomization
    resources:
    - some-secret.yaml
  2. Add decryption to FluxCD Kustomization Update your cluster’s Kustomization to include SOPS decryption:

    apiVersion: kustomize.toolkit.fluxcd.io/v1
    kind: Kustomization
    metadata:
    name: infrastructure
    namespace: flux-system
    spec:
    interval: 10m0s
    path: ./infrastructure/peercluster
    prune: true
    sourceRef:
    kind: GitRepository
    name: flux-system
    decryption:
    provider: sops
    secretRef:
    name: sops-age
    dependsOn:
    - name: flux-system
  3. Commit and push changes

    Terminal window
    git add .
    git commit -m "Add encrypted secrets with SOPS"
    git push origin main

Step 7: Deploy and Verify

  1. Trigger FluxCD reconciliation

    Terminal window
    flux reconcile kustomization secrets
  2. Verify secret deployment

    Terminal window
    kubectl get secret some-secret -n flux-system
  3. Test secret value decryption

    Terminal window
    kubectl get secret some-secret -n flux-system -o jsonpath="{.data.this_is_a_secret}" | ForEach-Object { [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($_)) }

Step 8: Development Workflow Setup (Optional)

  1. Install VS Code SOPS extension Install the SOPS extension for easier secret editing:

    VS Code SOPS Extension

  2. Set up Age key file as vs code setting

    "sops.defaults.ageKeyFile": "C:\\...\\.sops\\age.agekey"
  3. Test the VS Code extension

    • Open any encrypted .yaml file in VS Code
    • The extension automatically creates a temporary .decrypted~ file for editing
    • Edit the decrypted file - changes are automatically encrypted back to the original file
    • The temporary decrypted file is automatically cleaned up
  4. Update .gitignore - just to be sure Add these entries to prevent accidental commits:

    # SOPS
    .sops/
    *.decrypted~*