Skip to content
TulipFarmDocs

Last updated

Use any KMS

Protect TulipFarm operator settings and backups with SOPS and AWS KMS, GCP Cloud KMS, Azure Key Vault keys, Vault Transit, or age.

A key management service (KMS) holds a master key that never leaves it. You ask the KMS to encrypt or decrypt small values, and it checks your identity each time. TulipFarm never calls a KMS. Instead, you use a KMS to protect the files that hold TulipFarm’s settings:

  • the operator settings file (self-host/.env)
  • the state.json backup and other backups

This guide uses SOPS. SOPS works with AWS KMS, GCP KMS, Azure Key Vault keys, HashiCorp Vault Transit, and offline age keys.

SOPS uses envelope encryption. It creates a random data key, encrypts each value with it, then asks every configured KMS key to encrypt the data key. The encrypted file stores the encrypted data key next to the values.

encrypt decrypt at startup
.env ──▶ sops ──┬─ values ⟵ AES-256-GCM(data key) sops exec-env
└─ data key ─▶ KMS ─▶ wrapped key ├─ wrapped key ─▶ KMS ─▶ data key
│ └─ values ─▶ environment ─▶ docker compose
tulipfarm.sops.env ◀──────┘ (safe to commit)

Only someone whom the KMS authorizes can decrypt. You can commit the encrypted file to a private operations repository. The plaintext exists only in the environment of the process that SOPS starts.

  1. Install SOPS on the host.

  2. Create self-host/.sops.yaml with one rule. Pick your provider from the provider table. This example lists two master keys, so either one can decrypt. Keep an offline age key for emergency recovery:

    creation_rules:
    - path_regex: \.sops\.(env|json)$
    kms: arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab
    age: age1qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs3290gq
  3. Encrypt the operator settings, then delete the plaintext:

    Terminal window
    cp .env.example tulipfarm.env # fill it in
    sops encrypt --filename-override tulipfarm.sops.env tulipfarm.env > tulipfarm.sops.env
    rm tulipfarm.env

    --filename-override matches the .sops.yaml rule and selects the dotenv format. Values are taken literally, so $ needs no quoting.

  4. Start TulipFarm with the decrypted values in the environment. Make sure no self-host/.env exists:

    Terminal window
    sops exec-env tulipfarm.sops.env 'docker compose up -d --build'
  5. To change a value, run sops edit tulipfarm.sops.env, then repeat step 4.

The host needs permission to decrypt, but not to encrypt. On cloud hosts, use the instance identity instead of stored keys.

KMS (SOPS docs) .sops.yaml key Key format Decrypt permission Host credentials
AWS KMS kms Key ARN kms:Decrypt Instance role, or AWS_PROFILE
GCP Cloud KMS gcp_kms projects/P/locations/L/keyRings/R/cryptoKeys/K roles/cloudkms.cryptoKeyDecrypter Attached service account, or gcloud auth application-default login
Azure Key Vault azure_keyvault https://VAULT.vault.azure.net/keys/KEY/VERSION Key Vault Crypto User (unwrap key) Managed identity, or az login
Vault / OpenBao Transit hc_vault_transit_uri https://vault.example.com:8200/v1/transit/keys/tulipfarm update on transit/decrypt/tulipfarm VAULT_ADDR and VAULT_TOKEN
age age age1… public key Holds the private key SOPS_AGE_KEY_FILE

age needs no cloud account. Use it for a laptop, a single server, or emergency recovery. Store its private key outside the server, for example in a password manager.

Encrypt state.json as you export it, so the plaintext never reaches disk:

Terminal window
docker compose run --rm -T --no-deps --entrypoint cat setup /setup/state.json \
| sops encrypt --filename-override state.sops.json > state.sops.json

Restore it on a new host:

Terminal window
sops decrypt state.sops.json \
| docker compose run --rm -T --no-deps --entrypoint sh setup -c 'umask 077 && cat > /setup/state.json'

SOPS is designed for small structured files. For database dumps and volume archives, use storage that encrypts with your KMS, such as S3 SSE-KMS, GCS CMEK, or Azure customer-managed keys. Or stream the dump through age -r age1….

What How
KMS master key Enable automatic rotation in your KMS. Old key versions still decrypt, so you do nothing.
SOPS data key sops rotate -i tulipfarm.sops.env creates a new data key and encrypts again.
Add or remove a master key Edit .sops.yaml, then run sops updatekeys tulipfarm.sops.env.
A setting, such as an API key sops edit tulipfarm.sops.env, then restart.
TulipFarm encryption keys See key rotation.

After you remove someone’s access, rotate the settings they could read. Old copies of the encrypted file still open with the old master keys.

  • Kubernetes: SOPS with Flux or Argo CD decrypts in the cluster. Or use the External Secrets Operator.
  • Cloud secret managers: AWS Secrets Manager, Google Secret Manager, and Azure Key Vault secrets already encrypt with KMS. Choose your own key (CMEK) if you need control. Deliver values as described in Secret stores.
  • Infisical: SOPS has no Infisical backend. Keep settings in Infisical secrets, which it encrypts for you. To encrypt a backup with your own key, use Infisical KMS through its encrypt and decrypt API, Infisical Cloud or self-hosted. Turn on Allow Export when you create the key: you can’t change it later, and without it you can’t move the key to another Infisical instance.

Was this page helpful?