Skip to content
GantryCD

Security model

GantryCD sits between your team and your cloud accounts, so its security model is the product. This page gathers the guarantees that are explained piecemeal elsewhere into one story — useful when you’re evaluating GantryCD or reviewing it for adoption.

The core idea: nothing stands still

A continuous-delivery tool is a juicy target: it holds the keys to your infrastructure. GantryCD’s answer is to hold almost nothing.

  • No standing agent with cloud access. Work runs on ephemeral runners — a fresh worker per run that exits when the run ends. There is no long-lived process sitting in your network holding credentials between deployments.
  • No static cloud keys. GantryCD never stores your cloud secrets. For each run it exchanges its own identity for temporary credentials (AWS AssumeRole with an external ID; GCP service-account impersonation).
  • Credentials expire with the run. State, logs, artifacts, and cloud access are all minted at run start and invalid at run end. They share one budget (RUN_TTL, default one hour) and a hard duration cap kills runaway runs while their credentials are still valid.

See Cloud credentials and Storage.

Credentials are scoped, not just short-lived

Short-lived isn’t enough if a credential is also over-broad. Each storage credential is prefix-scoped by an inline session policy: a run’s logs and artifacts to that run, and its OpenTofu state to that stack. A runner can’t reach another run’s logs or another stack’s state. The minted permissions are the intersection of that session policy and the role’s own grants.

Secrets at rest are encrypted and write-only

Everything sensitive GantryCD does persist is encrypted with AES-256-GCM and is write-only through the API — once set, a secret is never returned to the UI or API:

  • stack and context environment variables marked secret;
  • OIDC client secrets and SCM webhook secrets / App private keys;
  • the backend-held signing keys for github-actions runner groups.

You choose how the encryption key is held, via GANTRYCD_DATA_ENCRYPTION_PROVIDER:

  • aes-256 — you supply a base64 32-byte key (GANTRYCD_DATA_ENCRYPTION_AES_256_KEY_B64). Simplest; for self-hosting.
  • aws-kms-aes-256 — AWS KMS envelope encryption. A fresh data key is generated per secret and wrapped by your KMS CMK; only the wrapped key is sent to KMS, never your data. Your CMK never leaves AWS KMS.

Every ciphertext carries a one-byte scheme tag, so the provider that produced any stored secret is identifiable from the bytes — easing audits and future key/algorithm migrations. Encryption is bound to each row (additional authenticated data — and, for KMS, the KMS EncryptionContext), so a row swapped in the database fails to decrypt.

Authentication: no local accounts

Every user is provisioned through SSO — GitHub, Google, or OIDC. There is no local password store to leak. A user’s identity is derived from the provider’s (provider, login, subject) triple, which means a reused/recycled username from your IdP becomes a different GantryCD identity and never inherits the old account’s access. See Single sign-on.

Authorization: least privilege by default

Access is role-based and scoped per organization. A permission is a (resource type, action, resource pattern) tuple, so a role can be narrowed to, say, only stacks named team-a-*. Every request resolves to a single authorization query; membership in the org is a hard gate before any grant counts. Service-account tokens can’t be granted identity-management roles, so an automation token can’t escalate into account administration. See Access control.

Two details worth knowing:

  • Single-resource routes answer 404, not 403, on denial — so an outsider can’t probe which stack names exist.
  • Tokens are org-scoped and revocable. Revoking a member, disabling a user, or forcing logout invalidates their tokens in the same transaction.

Trust boundaries

The components talk in one direction only, by design:

Web  ──▶  Backend  ──▶  PostgreSQL, S3, AWS STS, GitHub, Redis
Runner ─▶ Backend

Runners never reach the web app, the database, or each other — only the backend API, authenticated by a per-run JWT. Inbound webhooks are verified by an HMAC signature per integration before anything is admitted. Off-network runners (github-actions) get a publicly reachable storage endpoint without exposing the backend’s internal addresses.

What you operate

Your responsibilities as an operator:

  • Provision the IAM role / service account GantryCD assumes, with a trust policy scoped to GantryCD’s principal and external ID.
  • Keep your data-encryption key stable: the aes-256 key (GANTRYCD_DATA_ENCRYPTION_AES_256_KEY_B64) or the aws-kms-aes-256 CMK. Changing it without re-encrypting breaks existing secrets.
  • Configure SSO and grant the first super-admin out-of-band.

Implementation-level detail lives in Authorization, Runner Runtime Credentials, and Runner Authentication.