claw-log

SOPS secrets management

Encrypt your API keys at rest so they're never stored as plaintext. Your agent decrypts them at runtime — nothing changes about how it works, except now your secrets file is safe to commit.

The problem

You have API keys scattered around your OpenClaw config. Anthropic key, Discord bot token, maybe a Stripe key or a proxy credential. They're sitting in plaintext JSON files on disk. If someone gets access to the machine — or you accidentally push a config file to GitHub — everything is exposed.

SOPS (Secrets OPerationS) encrypts your secrets file so the values are unreadable without the decryption key. Your agent decrypts them at runtime. Everything else works the same.

Setting it up

1
Install age and SOPS

age handles key management — it encrypts the data key that SOPS uses to protect your secrets file.

# Install age (key management)
# Ubuntu 22.04+ / Debian 12+:
sudo apt install age

# Older Ubuntu/Debian — install from GitHub releases:
# https://github.com/FiloSottile/age/releases/latest

# macOS:
brew install age

# Install SOPS
# Ubuntu/Debian (check https://github.com/getsops/sops/releases for the latest version):
curl -LO https://github.com/getsops/sops/releases/latest/download/sops_amd64.deb
sudo dpkg -i sops_amd64.deb

# macOS:
brew install sops
2
Generate an age key pair

This creates a private key (for decryption) and a public key (for encryption). The private key stays on the machine that runs your agent. The public key goes in your SOPS config.

# Create the key directory
mkdir -p ~/.config/sops/age

# Generate the key pair
age-keygen -o ~/.config/sops/age/keys.txt

# Check the output — you'll see something like:
# Public key: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
cat ~/.config/sops/age/keys.txt

Copy the public key (starts with age1...). You'll need it in the next step.

3
Create a SOPS config

In your OpenClaw workspace directory, create .sops.yaml. This tells SOPS which key to use when encrypting files:

# ~/.openclaw/workspace/.sops.yaml
creation_rules:
  - path_regex: secrets\.json$
    age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    # Replace with YOUR public key from step 2
4
Create and encrypt your secrets

Start with a plaintext JSON file containing your secrets, then encrypt it in place:

# Create the plaintext secrets file
cat > ~/.openclaw/workspace/secrets.json << 'EOF'
{
  "anthropic_api_key": "sk-ant-XXXXX",
  "discord_bot_token": "XXXXX",
  "openai_api_key": "sk-XXXXX"
}
EOF

# Encrypt it in place
export SOPS_AGE_KEY_FILE=~/.config/sops/age/keys.txt
sops --encrypt --in-place ~/.openclaw/workspace/secrets.json

# Verify — values should now show as ENC[AES256_GCM,...]
cat ~/.openclaw/workspace/secrets.json

The file now contains encrypted values. The keys (like anthropic_api_key) are still visible — only the values are encrypted. This is by design: you can see what's in the file without being able to read the actual secrets.

5
Tell OpenClaw where to find the secrets

Register the SOPS secrets provider in your OpenClaw config. This tells OpenClaw how to decrypt the file at startup. The source field must be "exec", and command must be the absolute path to the sops binary:

// openclaw.json
{
  "secrets": {
    "providers": {
      "sops": {
        "source": "exec",
        "command": "/usr/local/bin/sops",
        "args": ["-d", "--extract", '["KEY_NAME"]', "~/.openclaw/workspace/secrets.json"],
        "passEnv": ["SOPS_AGE_KEY_FILE"],
        "jsonOnly": false
      }
    }
  }
}

Replace /usr/local/bin/sops with the actual path on your system (which sops will tell you). The --extract flag lets you pull individual keys — replace KEY_NAME with the key you want, e.g. anthropic_api_key.

Make sure the SOPS_AGE_KEY_FILE environment variable is set wherever OpenClaw runs — in your shell, your systemd service file, or your Docker compose:

# Shell:
export SOPS_AGE_KEY_FILE=~/.config/sops/age/keys.txt

# Systemd service:
[Service]
Environment="SOPS_AGE_KEY_FILE=/home/you/.config/sops/age/keys.txt"

# Docker Compose:
environment:
  - SOPS_AGE_KEY_FILE=/secrets/age-key.txt
6
Reference secrets in your config

Now instead of pasting plaintext keys into your config, reference them by name using a SecretRef:

// openclaw.json
{
  "channels": {
    "discord": {
      "token": {
        "source": "exec",
        "provider": "sops",
        "id": "discord_bot_token"
      }
    }
  }
}

The id field is the key name to extract from your secrets JSON. provider matches the name you gave the provider in the previous step. OpenClaw resolves these at startup and injects the values — your config file never contains plaintext credentials.

Editing secrets later

SOPS can open the encrypted file in your editor, decrypt it temporarily for editing, and re-encrypt when you save:

export SOPS_AGE_KEY_FILE=~/.config/sops/age/keys.txt
sops ~/.openclaw/workspace/secrets.json
# Opens in $EDITOR — edit values, save, and it re-encrypts automatically

Back up your age private key

If you lose ~/.config/sops/age/keys.txt, you cannot decrypt your secrets. Ever. Back it up: