Skip to content

Delivery and environment rules

Environments

An environment is a stage of the product, such as production or staging. It is two GCP projects:

  • The workload project runs the product.
  • The platform project holds everything long-lived. Examples: Terraform state, image registries, the CI identity.

An environment's tier is how close it is to production. These are the tiers, highest first: production, staging, devel.

Environment Workload project Platform project
production production-492618 platform-production-510011
staging staging-505318 platform-staging-506908
devel devel-466814 platform-staging-506908
  • production MUST NOT share its platform project.
  • Every other environment MUST use staging's platform project. This is by design.
  • DO NOT create a third platform project.
  • platform-production and platform-staging name platform projects, not environments. Their env files apply the platform project's own units.

ENV-1: An environment is a complete, self-contained stack

  • An environment MUST own every service it needs, data plane and control plane, in its workload project.
  • This includes the API backend clients call and the identity store they authenticate against.
  • Everything long-lived MUST live in the environment's platform project.
  • A resource one environment owns in a shared platform project MUST carry the environment's name as a prefix. A resource shared by design, such as an image registry, does not.
  • DO NOT borrow a piece of another environment's workload project.

Enforcement: Review only, plus the isolation check at stand-up.

ENV-2: No cross-environment wiring

  • A service's rendered configuration in environment X MUST NOT name a host, database, queue, bucket, project or secret of another environment's workload project.
  • In a shared platform project, X MUST use only its own resources, its own state prefix and what is shared by design.
  • DO NOT reference another environment's platform resources or state.

Enforcement: Review only, plus the isolation check at stand-up.

ENV-3: Parity of shape, not of capacity

  • A non-production environment's workload project MUST run the same services, topology and region as production's.
  • You MUST size it down through per-environment variables.

Enforcement: Review only.

ENV-4: Dependencies point up

  • An environment MAY depend on what a higher-tier environment shares with it.
  • An environment MUST NOT depend on a lower-tier environment.
  • An environment MAY use only what another environment shares explicitly.
  • production is the highest tier. It MUST NOT depend on any other environment.

Example: devel pulls images from the registries in staging's platform project.

Enforcement: Review only.

ENV-5: Promotion is a pin change, never a rebuild

  • You MUST promote an artefact by committing a change to the target environment's pin.
  • DO NOT rebuild per environment.
  • Rollback is the same operation backwards.

Enforcement: Review only. Production still deploys manually. See environments.

ENV-6: Do not name a new environment production

DO NOT name an environment production. The name switches on the production-only settings and the deletion protection in gcp/common.hcl.

Enforcement: the is_production check in gcp/common.hcl.

Credentials and access

SECURITY-1: No long-lived credentials

  • CI MUST authenticate by Workload Identity Federation.
  • An operator MUST use their own ADC.
  • DO NOT create a long-lived service-account key.

Enforcement: sops-find-unencrypted-secrets for the plaintext case. Review only otherwise.

SECURITY-2: No standing administrative access

  • Production admin rights MUST be elevated on request, time-boxed and audited.
  • DO NOT hold them permanently on a laptop.

Enforcement: Review only, on IAM changes. See /people.

SECURITY-3: Secret material MUST be unique per environment

  • You MUST generate a secret fresh for the environment that uses it.
  • DO NOT copy one from another environment.

Enforcement: Review only.

SECURITY-4: Secrets in the repository MUST be sops-encrypted

  • Runtime secrets MUST live encrypted in infra/inventory/<env>/config.yml.
  • You MUST register the merge driver once per clone: git config --local include.path ../.gitconfig. See SOPS.

Enforcement: sops-find-unencrypted-secrets and detect-private-key (pre-commit).

SECURITY-5: One credential model, no side doors

  • The same federated identity that pushes an image MUST pull the base images it builds on.
  • DO NOT add a second credential for one workflow's convenience.
  • If a workflow genuinely needs its own identity, then scope it to that job.

Enforcement: Review only.

Changing infrastructure

INFRA-1: Infrastructure is applied by CI, from a merged commit

  • This binds every environment, not just production.
  • DO NOT run terragrunt apply from a laptop.
  • Emergencies and first stand-ups are legitimate. Announce them at the time, then reconcile into a merged commit.

Enforcement: Review only. CI-driven apply is being built.

INFRA-2: All modules MUST be Terragrunt-managed

  • A new module MUST be a Terragrunt unit from the start.
  • The rest MUST migrate on a stated deadline.

Enforcement: Review only. Deadline tracked in current state of the architecture.

INFRA-3: Drift MUST be detected on a schedule

  • A scheduled plan MUST report drift.
  • Unexplained drift is an incident, not a nuisance.

Enforcement: none. See enforcement gaps.

INFRA-4: Nothing new in _modules/gcp/legacy

  • DO NOT add to it.
  • It MAY shrink into new or existing Terragrunt units.

Enforcement: Review only.

INFRA-5: Environment differences are variables, not conditionals

  • Every knob that differs between environments MUST be a per-environment TF_VAR in infra/terraform/envs/<env>.env.
  • DO NOT branch on the environment name inside a module. ENV-6 is the one place we do.

Enforcement: Review only.

INFRA-6: IP ranges come from the address plan

  • You MUST take a new environment, subnet or peering range from the address plan.
  • You MUST record it there in the same change.
  • Ranges MUST NOT overlap. VPC peering and the tailnet both break on an overlap.

Enforcement: Review only.

INFRA-7: Terraform state lives in the environment's platform project

  • An environment MUST keep its Terraform state in its platform project's bucket, <platform project>-terraform-state.
  • The state MUST be stored with an environment-specific prefix.
  • A unit's state MUST live at <env>/<unit>/terraform.tfstate. root.hcl derives it from TF_VAR_lyceum_env.
  • platform/state_bucket MUST manage every state bucket.
  • An environment's identities MUST get access to their own prefix only. DO NOT grant a bucket-wide role.
  • DO NOT add state to lyceum-terraform-state. It is deprecated, and it is deleted once nothing uses it.

Enforcement: root.hcl for the prefix. Review only otherwise. See enforcement gaps.