> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Mozilla SOPS Developer

> Guide showing developers how to encrypt Kubernetes Secrets with Mozilla SOPS using PGP and configure Flux to decrypt them before applying to the cluster.

In this walkthrough you'll act as a developer to encrypt and decrypt Kubernetes secrets using a PGP key pair and Mozilla SOPS. The demo covers importing the public key, installing SOPS locally, encrypting a plain Secret YAML, and configuring Flux Kustomization so Flux decrypts the secret before applying it to the cluster.

![A presentation slide or webpage header titled "Demo – Mozilla SOPS: Secrets OPerationS with PGP (Developer)" with a dark navy banner and repeating yellow keywords, above a mostly white area containing a small blue rocket icon. The bottom shows a copyright credit.](https://mintcdn.com/kodekloud-c4ac6d9a/AyhVWHpoMIYCWiei/images/GitOps-with-FluxCD/Secret-Management-Sign-Verification/Demo-Mozilla-SOPS-Developer/mozilla-sops-secrets-pgp-demo-rocket.jpg?fit=max\&auto=format\&n=AyhVWHpoMIYCWiei\&q=85\&s=2d108a0afe156f5f362549a3e9f96f0e)

Prerequisites (assumed)

* You have a Git repository checked out (example: `bb-app-source`) and are on the `infrastructure` branch.
* A SOPS public key file exists in the repository at `sops/sops-gpg.pub`.
* Flux is installed and configured to apply resources from the repository.

Quick overview of the workflow

1. Prepare the Secret YAML in plaintext.
2. Import the SOPS public (PGP) key into your GPG keyring.
3. Install SOPS on your developer machine.
4. Encrypt the secret with SOPS (PGP backend).
5. Push the encrypted manifest and give Flux the SOPS private key so it can decrypt.
6. Reconcile Flux and verify the Secret is applied decrypted in the cluster.

Table: Resources and commands at a glance

| Task | Example command / file |
| - | - |
| Plaintext Secret file | `database/secret-mysql.yaml` |
| Import public key | `gpg --import sops/sops-gpg.pub` |
| Install SOPS (Linux example) | `wget -O sops ... && chmod +x sops && sudo mv sops /usr/local/bin/sops` |
| Encrypt with SOPS (PGP) | `sops --encrypt --encrypted-regex="^(data\|stringData)$" --pgp <FP> --in-place file.yaml` |
| Flux Kustomization decryption | Add `decryption.provider: sops` + `secretRef.name: sops-gpg` in Kustomization |

***

## 1) Plaintext Secret (before encryption)

Create a simple Secret using `stringData` so values are easy to read before encryption:

```yaml theme={null}
apiVersion: v1
kind: Secret
metadata:
  name: secret-mysql
  namespace: database
stringData:
  password: mysql-password-0123456789
```

Suggested file path in the repo: `database/secret-mysql.yaml`.

***

## 2) Import the public PGP key into GPG

On the developer machine, verify and import the public key that ships with the repository:

```bash theme={null}
# Show existing public keys (fresh machine may show none)
gpg --list-public-keys

# Import the public key from the repo
gpg --import sops/sops-gpg.pub
```

Sample import output:

```text theme={null}
gpg: key CE284BB23665E42A: public key "dev.us-e1.k8s (k8s) <admin@bb.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1
```

Check the imported key fingerprint and metadata:

```bash theme={null}
gpg --list-public-keys CE284BB23665E42A
```

Sample listing:

```text theme={null}
pub   rsa3072 2023-04-06 [SCEA]
      65DD426CB98391CDEB33FD4CCE284BB23665E42A
uid           [ unknown] dev.us-e1.k8s (k8s) <admin@bb.com>
sub   rsa3072 2023-04-06 [SEA]
```

Now your local keyring contains the public key; you can encrypt files to that PGP fingerprint.

***

## 3) Install SOPS on your machine

Install the SOPS CLI. Example (Linux binary download for sops v3.7.3):

```bash theme={null}
# Download (example URL)
wget -O sops-v3.7.3.linux.amd64 "https://objects.githubusercontent.com/....sops-v3.7.3.linux.amd64"

# Make executable
chmod +x sops-v3.7.3.linux.amd64

# Move into a directory on PATH
sudo mv sops-v3.7.3.linux.amd64 /usr/local/bin/sops
```

Verify the installation:

```bash theme={null}
sops --version
# Example output: sops 3.7.3
```

SOPS supports multiple backends (PGP, KMS, GCP KMS, Azure Key Vault, HashiCorp Vault, age). This guide uses the PGP backend.

***

## 4) Encrypt the Secret using the developer's public key (SOPS + PGP)

Encrypt only the secret data keys (`data` or `stringData`) so metadata remains human-readable. Use the PGP fingerprint you imported:

```bash theme={null}
sops --encrypt \
  --encrypted-regex="^(data|stringData)$" \
  --pgp CE284BB23665E42A \
  --in-place database/secret-mysql.yaml
```

Notes:

* `--encrypted-regex` controls which keys are encrypted (here: `data` and `stringData`).
* `--in-place` replaces the file with the encrypted version.

Example (abbreviated) of the encrypted YAML:

```yaml theme={null}
apiVersion: v1
kind: Secret
metadata:
  name: secret-mysql
  namespace: database
stringData:
  password: ENC[AES256_GCM,data:nrJt975m...==,iv:...,tag:...,type:str]
sops:
  kms: []
  gcp_kms: []
  azure_kv: []
  hc_vault: []
  age: []
  lastmodified: "2023-04-06T18:35:29Z"
  mac: ENC[AES256_GCM,data:...]
  pgp:
    - created_at: "2023-04-06T18:35:26Z"
      enc: |
        -----BEGIN PGP MESSAGE-----
        ...
        -----END PGP MESSAGE-----
      fp: CE284BB23665E42A
  encrypted_regex: ^(data|stringData)$
  version: 3.7.3
```

Only the fields matched by the regex are encrypted; metadata (name, namespace, keys) remains readable.

Never commit private keys to the public repository. Only the public key (`sops-gpg.pub`) belongs in the repo. The private key must be handled securely (see the next section for how to provide it to Flux).

***

## 5) Commit & push the encrypted file; what Flux will do by default

Commit and push the encrypted secret file to your Git repository. Flux will fetch the manifest and apply it as-is. Without extra configuration Flux will apply the encrypted value literally, so the Secret in Kubernetes will contain the SOPS-encrypted string (not the usable plaintext).

You can confirm the applied Secret content (it will show the encrypted string after decoding from base64):

```bash theme={null}
kubectl -n database get secret secret-mysql -o json | jq -r .data.password | base64 -d
# Output: ENC[AES256_GCM,data:...,iv:...,tag:...,type:str]
```

To have Flux decrypt SOPS-encrypted YAML prior to apply, provide the private key to Flux and configure the Kustomization decryption section.

***

## 6) Provide the SOPS private key to Flux and configure Kustomization decryption

An administrator creates a Kubernetes Secret in the `flux-system` namespace that contains the SOPS/GPG private key. Example command (performed by an admin):

```bash theme={null}
kubectl -n flux-system create secret generic sops-gpg --from-file=sops-gpg.key=path/to/private.key
```

Then update the Kustomization that applies resources under `./database` to include a `decryption` block. Key parts of the Kustomization:

```yaml theme={null}
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
  name: infra-database-kustomize-git-mysql
  namespace: flux-system
spec:
  interval: 10s
  path: ./database
  prune: true
  sourceRef:
    kind: GitRepository
    name: infra-source-git
  decryption:
    provider: sops
    secretRef:
      name: sops-gpg
```

Important:

* The Flux secret `sops-gpg` must exist in the `flux-system` namespace and include the private key file content under the key name expected by Flux (for PGP, this is typically the raw private key file).
* After adding `decryption`, Flux will attempt to decrypt any SOPS-encrypted files in that path before applying them.

Ensure the Flux secret (`sops-gpg`) contains the SOPS/GPG private key and is created in the `flux-system` namespace — Flux requires that private key to decrypt SOPS-encrypted manifests.

***

## 7) Reconcile Flux and verify the Secret is applied decrypted

Trigger a manual reconcile (optional — Flux will reconcile automatically based on `interval`):

```bash theme={null}
# Trigger Kustomization reconciliation
flux reconcile kustomization infra-database-kustomize-git-mysql
```

After a successful reconcile, the Secret in the cluster should contain the decrypted value. Verify by decoding the Kubernetes Secret:

```bash theme={null}
kubectl -n database get secret secret-mysql -o json | jq -r .data.password | base64 -d
# Output: mysql-password-0123456789
```

If you see the original plaintext value, Flux successfully decrypted the SOPS-encrypted manifest before applying it.

***

## Summary, options and best practices

* Mozilla SOPS supports multiple encryption backends: PGP, AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault, age, and others. Use the backend that matches your organizational key management policies.
* In GitOps workflows with Flux, store only encrypted secrets in Git. To let Flux apply decrypted values, configure the Kustomization `decryption` block and provide the decryption key/secret to Flux.
* If you omit the Kustomization decryption configuration, Flux will apply the encrypted Secret object as stored in Git — the cluster will hold the encrypted string.
* Secure the SOPS private key carefully. Prefer storing it in a restricted admin-controlled location and only create the Flux secret in `flux-system` when necessary.

Links and references

* Mozilla SOPS project: [https://github.com/mozilla/sops](https://github.com/mozilla/sops)
* Flux docs — Kustomization decryption: [https://fluxcd.io/docs/components/kustomize/kustomization/#decryption](https://fluxcd.io/docs/components/kustomize/kustomization/#decryption)
* GPG documentation: [https://gnupg.org/documentation/](https://gnupg.org/documentation/)

That's all — you're set to encrypt secrets locally and configure Flux to decrypt them securely before applying to the cluster.

> **[Watch Video](https://learn.kodekloud.com/user/courses/gitops-with-fluxcd/module/c8ad2608-2804-4413-9041-5e8dc9126d53/lesson/6f504936-daab-4ee3-8063-793bc83a9329)**

> **[Practice Lab](https://learn.kodekloud.com/user/courses/gitops-with-fluxcd/module/c8ad2608-2804-4413-9041-5e8dc9126d53/lesson/9ae09784-a5ae-481c-a4f1-cf7d338e2713)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.