Skip to content
Back to skills

Sops

BSecurity

Expert agent for Mozilla SOPS (Secrets OPerationS). Covers file encryption (YAML/JSON/ENV/INI), AWS KMS, GCP KMS, Azure Key Vault, age, and PGP backends, partial file encryption, GitOps patterns, and Flux/ArgoCD integration. WHEN: \"SOPS\", \"Mozilla SOPS\", \"sops encrypt\", \"sops decrypt\", \"GitOps secrets\", \"age encryption\", \"SOPS ArgoCD\", \"SOPS Flux\", \"encrypted yaml git\".

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 24, 2026
devopsgoshellbashnodekubernetesawsgcpazuregitapi

Works with

  • api

Security analysis

B84/100
  • mediumUses curl or wget to download content
  • criticalExfiltrates credentials via HTTP — exact pattern from Snyk ToxicSkills study

Pro shows the line behind each finding and how to fix it

Scanned September 24, 2026

npx -y skills add chrishuffman5/domain-expert --skill sops --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Sops?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Sops
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/chrishuffman5-sops/badge)](https://www.skillsdirectory.com/skills/chrishuffman5-sops)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: sops
description: "Expert agent for Mozilla SOPS (Secrets OPerationS). Covers file encryption (YAML/JSON/ENV/INI), AWS KMS, GCP KMS, Azure Key Vault, age, and PGP backends, partial file encryption, GitOps patterns, and Flux/ArgoCD integration. WHEN: \"SOPS\", \"Mozilla SOPS\", \"sops encrypt\", \"sops decrypt\", \"GitOps secrets\", \"age encryption\", \"SOPS ArgoCD\", \"SOPS Flux\", \"encrypted yaml git\"."
license: MIT
---

# Mozilla SOPS

This skill covers Mozilla SOPS (Secrets OPerationS). It has deep knowledge of SOPS file encryption, key provider integrations (AWS KMS, GCP KMS, Azure Key Vault, age, PGP), and GitOps workflows with Flux and ArgoCD.

## How to Approach Tasks

When you receive a request:

1. **Classify** the request:
   - **Key provider setup** — AWS KMS, GCP KMS, AKV, age, PGP configuration
   - **Encrypting files** — SOPS encrypt patterns, partial encryption
   - **Decrypting files** — Decrypt, exec-env, exec-file patterns
   - **GitOps** — Flux SOPS integration, ArgoCD Vault Plugin alternative
   - **CI/CD** — GitHub Actions, GitLab CI, Jenkins usage
   - **.sops.yaml config** — Creation rules, key groups, key rotation
   - **Key rotation** — SOPS `updatekeys` and re-encryption

## What SOPS Does

SOPS encrypts **values** in YAML/JSON/ENV/INI files while leaving **keys** (field names) visible. This allows diffs in version control to show which secrets changed without exposing values.

```yaml
# Plaintext
database:
  host: db.example.com
  password: s3cr3t
  username: app_user

# After SOPS encryption
database:
  host: db.example.com                  # NOT encrypted (not a secret)
  password: ENC[AES256_GCM,data=...,iv=...,tag=...,type=str]
  username: ENC[AES256_GCM,data=...,iv=...,tag=...,type=str]
sops:
  kms:
    - arn: arn:aws:kms:us-east-1:123456789:key/abc123
      created_at: '2025-01-01T00:00:00Z'
      enc: AQICAHh...
  lastmodified: '2025-01-01T00:00:00Z'
  mac: ENC[AES256_GCM,data=...,...]
  version: 3.9.0
```

SOPS uses **envelope encryption**: each file is encrypted with a unique DEK (AES-256-GCM), and the DEK is encrypted with each configured master key.

## Installation

```bash
# macOS
brew install sops

# Linux (download binary)
curl -LO https://github.com/getsops/sops/releases/download/v3.9.0/sops-v3.9.0.linux.amd64
chmod +x sops-v3.9.0.linux.amd64
sudo mv sops-v3.9.0.linux.amd64 /usr/local/bin/sops

# Windows (scoop)
scoop install sops

# Go install
go install github.com/getsops/sops/v3/cmd/sops@latest
```

## Key Providers

### AWS KMS

```bash
# Encrypt with AWS KMS key
sops --kms arn:aws:kms:us-east-1:123456789:key/abc123 -e secrets.yaml > secrets.enc.yaml

# Or set environment variable
export SOPS_KMS_ARN="arn:aws:kms:us-east-1:123456789:key/abc123"
sops -e secrets.yaml

# Use alias
sops --kms arn:aws:kms:us-east-1:123456789:alias/my-sops-key -e secrets.yaml
```

Required IAM permissions:
```json
{
  "Effect": "Allow",
  "Action": ["kms:GenerateDataKey", "kms:Decrypt"],
  "Resource": "arn:aws:kms:us-east-1:123456789:key/abc123"
}
```

### GCP KMS

```bash
# Encrypt with GCP KMS
sops --gcp-kms projects/my-project/locations/global/keyRings/my-ring/cryptoKeys/my-key \
    -e secrets.yaml

# Application Default Credentials must be configured
gcloud auth application-default login
```

### Azure Key Vault

```bash
# Encrypt with Azure Key Vault key
sops --azure-kv https://myvault.vault.azure.net/keys/my-key/version-id \
    -e secrets.yaml

# Uses DefaultAzureCredential (managed identity, az login, env vars)
```

### age (Recommended for Simplicity)

age is a modern, simple encryption tool. No key server required — suitable for personal use, small teams, and CI/CD.

```bash
# Install age
brew install age
# or: go install filippo.io/age/cmd/...@latest

# Generate age key pair
age-keygen -o age.key
# Public key printed to stdout: age1xxxxxxxx...
# Private key in age.key: starts with AGE-SECRET-KEY-1

# Encrypt with age public key
sops --age age1xxxxxxxxxxxxxxxxxxxxxxxxxx -e secrets.yaml

# Decrypt (age.key must be accessible)
export SOPS_AGE_KEY_FILE=/path/to/age.key
sops -d secrets.enc.yaml
```

### PGP

```bash
# Encrypt with PGP fingerprint
sops --pgp FINGERPRINT1,FINGERPRINT2 -e secrets.yaml

# List available keys
gpg --list-keys

# Import a public key
gpg --import pubkey.asc
```

## .sops.yaml Configuration

The `.sops.yaml` file defines encryption rules for your repository so you don't need to pass key arguments every time:

```yaml
# .sops.yaml (place in repository root)
creation_rules:
  # Rule 1: Production secrets
  - path_regex: secrets/production/.*\.yaml$
    kms: arn:aws:kms:us-east-1:123456789:key/prod-key
    age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxx  # backup key
    
  # Rule 2: Staging secrets
  - path_regex: secrets/staging/.*\.yaml$
    kms: arn:aws:kms:us-east-1:123456789:key/staging-key
    
  # Rule 3: Any other secrets file (default)
  - path_regex: .*\.enc\.yaml$
    kms: arn:aws:kms:us-east-1:123456789:key/default-key
    age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxx
    
  # Rule 4: Environment files
  - path_regex: .*\.env$
    kms: arn:aws:kms:us-east-1:123456789:key/default-key
```

With `.sops.yaml`, simply run:
```bash
sops -e secrets/production/db.yaml  # Uses prod-key automatically
sops -d secrets/production/db.yaml
```

### Key Groups

Require multiple keys for decryption (Shamir-like threshold):

```yaml
creation_rules:
  - path_regex: secrets/production/.*\.yaml$
    key_groups:
      - kms:
          - arn: arn:aws:kms:us-east-1:123456789:key/key1
          - arn: arn:aws:kms:us-west-2:123456789:key/key2  # multi-region backup
        age:
          - age1xxxxxxxxxxxxxxxxxxxxxxxxxxx
    # shamir_threshold: 2  # (default: any one key group can decrypt)
```

## Basic Operations

```bash
# Encrypt a file (in-place)
sops -e -i secrets.yaml

# Encrypt to new file
sops -e secrets.yaml > secrets.enc.yaml

# Decrypt (to stdout)
sops -d secrets.enc.yaml

# Decrypt in-place (modifies file)
sops -d -i secrets.enc.yaml

# Edit encrypted file (opens in $EDITOR with decrypted content, re-encrypts on save)
sops secrets.enc.yaml

# Encrypt only specific keys (partial encryption)
sops --encrypted-regex "^(password|apiKey|secret)$" -e secrets.yaml

# Encrypt only a specific file format
sops -e --input-type json --output-type yaml secrets.json > secrets.enc.yaml
```

## Partial Encryption

By default, SOPS encrypts all string values in YAML/JSON. Control this with regexes:

```yaml
# .sops.yaml
creation_rules:
  - path_regex: configs/.*\.yaml$
    encrypted_regex: "^(password|apiKey|secretKey|token|privateKey)$"
    kms: arn:aws:kms:us-east-1:123456789:key/my-key
```

Or pass at command line:
```bash
# Only encrypt fields matching the regex
sops --encrypted-regex "^(password|secret)$" -e config.yaml

# Unencrypted suffix (leave .public fields unencrypted)
sops --unencrypted-suffix "_public" -e config.yaml
```

## Running Commands with Decrypted Secrets

```bash
# exec-env: decrypt and inject as environment variables, then run command
sops exec-env secrets.enc.yaml 'node server.js'

# exec-file: decrypt to temp file, pass filename to command, delete after
sops exec-file secrets.enc.yaml 'app --config {}'
# {} is replaced with the temp file path

# Decrypt to env and run with shell
sops -d --output-type dotenv secrets.enc.yaml | source /dev/stdin && node server.js
```

## GitOps Integration

### Flux SOPS Integration

Flux has native SOPS support. Flux decrypts SOPS-encrypted files at apply time.

```bash
# Create Flux secret with age private key
kubectl create secret generic sops-age \
    --namespace flux-system \
    --from-file=age.agekey=/path/to/age.key

# Add decryption config to Flux Kustomization
```

```yaml
# flux-kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: apps
  namespace: flux-system
spec:
  sourceRef:
    kind: GitRepository
    name: flux-system
  path: ./apps/production
  decryption:
    provider: sops
    secretRef:
      name: sops-age  # Secret containing age.agekey
```

Files in `./apps/production` that are SOPS-encrypted with the corresponding age public key will be automatically decrypted by Flux.

### ArgoCD Integration

ArgoCD does not have native SOPS support, but supports it via:

**ArgoCD Vault Plugin (AVP)**: AVP supports SOPS as a backend — annotate manifests with SOPS references.

**KSOPS (Kustomize + SOPS)**: A Kustomize exec plugin that decrypts SOPS files during Kustomize rendering.

```yaml
# kustomization.yaml with KSOPS
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
generators:
  - ./secrets-generator.yaml
  
---
# secrets-generator.yaml
apiVersion: viaduct.ai/v1
kind: ksops
metadata:
  name: secret-generator
  annotations:
    config.kubernetes.io/function: |
      exec:
        path: ksops
files:
  - ./secrets.enc.yaml
```

## Key Rotation

When a key is compromised or a team member leaves:

```bash
# Update to new key (re-encrypts all DEKs without touching ciphertext)
sops updatekeys secrets.enc.yaml

# Remove old key, add new key in .sops.yaml first, then:
sops rotate secrets.enc.yaml

# Rotate all files matching a pattern
find . -name "*.enc.yaml" -exec sops rotate {} \;
```

`updatekeys` re-reads the current `.sops.yaml` creation rules and re-encrypts the file's DEK with the new set of keys. The actual encrypted data is not changed.

## CI/CD Patterns

### GitHub Actions with AWS OIDC

```yaml
name: Deploy
on: [push]
permissions:
  id-token: write  # OIDC token for AWS auth
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Configure AWS credentials (OIDC)
      uses: aws-actions/configure-aws-credentials@v4
      with:
        role-to-assume: arn:aws:iam::123456789:role/github-actions-role
        aws-region: us-east-1
    
    - name: Install SOPS
      run: |
        curl -LO https://github.com/getsops/sops/releases/latest/download/sops-linux-amd64
        sudo install sops-linux-amd64 /usr/local/bin/sops
    
    - name: Decrypt and deploy
      run: |
        sops exec-env secrets/production/app.enc.yaml './deploy.sh'
```

### GitHub Actions with age

```yaml
- name: Decrypt secrets
  env:
    SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}  # age private key stored in GitHub secrets
  run: |
    echo "$SOPS_AGE_KEY" > /tmp/age.key
    export SOPS_AGE_KEY_FILE=/tmp/age.key
    sops exec-env secrets/production/app.enc.yaml 'node deploy.js'
    rm -f /tmp/age.key
```

## Common Mistakes

| Mistake | Fix |
|---|---|
| Committing unencrypted secrets | Add `*.yaml` to `.gitignore`, only commit `*.enc.yaml` |
| Using PGP with expired keys | Prefer age (no expiry concept) or KMS |
| Encrypting entire file including field names | Use `--encrypted-regex` to only encrypt values |
| No `.sops.yaml` | Create one so team doesn't need to remember key ARNs |
| Losing the age private key | Store in a separate secrets manager (1Password, Vault) |
| Not rotating after team member leaves | Run `sops rotate` on all encrypted files after key rotation |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…