Access Control
You can control which recipients are allowed or denied from decrypting specific secrets using the allow and deny fields in the [secret] section of the corresponding *.cott.toml metadata file.
Scenarios for managing access control:
- I want to allow only prod-server to be able to decrypt prod-secret
- I want to allow everyone except prod-server to be able to decrypt dev-secret
- I want to ensure that access control rules are enforced for all secrets before I merge a pull request
I want to allow only prod-server to be able to decrypt prod-secret
In this scenario, we restrict access to a production secret so that only the production server can decrypt it.
First, let’s add a new recipient key for the production server in the admin workspace:
cd /tmp/myproject ssh-keygen -t ed25519 -f .cottage/prod-server.key -N "" cp .cottage/prod-server.key.pub .cottage/recipients/prod-server
Now, create and encrypt the production secret:
echo "prod-db-password: supersecret" > prod-secret.yml ctg encrypt prod-secret.ymlencrypt prod-secret.yml into prod-secret.yml.cott.age edit .gitignore edit prod-secret.yml.cott.toml
Edit the generated prod-secret.yml.cott.toml file to add the allow rule:
sed -i '/\[secret\]/a allow = ["prod-server"]' prod-secret.yml.cott.toml cat prod-secret.yml.cott.toml[checksum] encrypted = "blake3:...XXX..." recipients = "blake3:...XXX..." [preview] format = "yaml" preview = """ prod-db-password: "...XXX..." """ [secret] allow = ["prod-server"] timestamp = "...XXX..."
Re-encrypt the secret to apply the new access rules:
ctg encrypt prod-secret.ymlencrypt prod-secret.yml into prod-secret.yml.cott.age edit prod-secret.yml.cott.toml
Now, only someone with the prod-server key can decrypt this secret. Even the admin who created it will be denied access unless they are explicitly added to the allow list.
Verify that access is denied for the default identity (admin):
rm prod-secret.yml ctg decrypt prod-secret.yml.cott.ageError: No matching keys found
Verify that access is granted for the prod-server key:
ctg decrypt prod-secret.yml.cott.age -i .cottage/prod-server.key cat prod-secret.ymldecrypt prod-secret.yml.cott.age into prod-secret.yml prod-db-password: supersecret
I want to allow everyone except prod-server to be able to decrypt dev-secret
In this scenario, we allow all team members and admins to access a development secret, but prevent the production server from being able to decrypt it.
Create and encrypt the development secret:
echo "dev-db-password: devsecret" > dev-secret.yml ctg encrypt dev-secret.ymlencrypt dev-secret.yml into dev-secret.yml.cott.age edit dev-secret.yml.cott.toml
Edit the dev-secret.yml.cott.toml file to add the deny rule:
sed -i '/\[secret\]/a deny = ["prod-server"]' dev-secret.yml.cott.toml cat dev-secret.yml.cott.toml[checksum] encrypted = "blake3:...XXX..." recipients = "blake3:...XXX..." [preview] format = "yaml" preview = """ dev-db-password: "...XXX..." """ [secret] deny = ["prod-server"] timestamp = "...XXX..."
Re-encrypt to apply the rules:
ctg encrypt dev-secret.ymlencrypt dev-secret.yml into dev-secret.yml.cott.age edit dev-secret.yml.cott.toml
Verify that the admin can still decrypt the secret (since they are not prod-server and are in the recipients list):
rm dev-secret.yml ctg decrypt dev-secret.yml.cott.age cat dev-secret.ymldecrypt dev-secret.yml.cott.age into dev-secret.yml dev-db-password: devsecret
Verify that the prod-server is denied access:
rm dev-secret.yml COTTAGE_IDENTITY=.cottage/prod-server.key ctg decrypt dev-secret.yml.cott.ageError: No matching keys found
Tip
You can use glob patterns in
allowanddenyrules. For example,allow = ["team-*"]would allow any recipient whose name starts withteam-.
I want to ensure that access control rules are enforced for all secrets before I merge a pull request
To ensure that access control rules are properly set up for all secrets before merging a pull request, you can run ctg verify in a CI workflow or a git hook.
Example using GitHub Actions:
# .github/workflows/cottage-verify.yml
name: Cottage Verify
on: [push, pull_request]
permissions:
contents: read
jobs:
verify-secrets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify secrets
run: docker run --rm -v "${{ github.workspace }}:/app" ghcr.io/sayanarijit/cottage verify
This way, if someone pushes a secret with incorrect access control rules, or without updating the checksum in metadata, the verification will fail and prevent the pull request from being merged until the issues are resolved.