The gateway needed its own boundary
A private release repository separates the gateway appliance from the public infrastructure that surrounds it.
The gateway is no longer just an EC2 instance with a few provisioners attached.
It is an appliance with an operating-system lifecycle, a network runtime, reconciliation rules, recovery constraints, acceptance tests, and a release process. That distinction changed where its code belongs.
rs-gateway is now the private repository for that appliance and its AMI
release path. rs-infra remains public and owns the AWS infrastructure around
it. The split is deliberately narrow: it separates two kinds of responsibility
that had begun to share one repository without sharing one lifecycle.
An image is not a Terraform implementation detail
Terraform is still the right owner for the gateway’s AWS envelope: VPCs, subnets, routes, security groups, KMS, IAM, secret containers, the EC2 instance, its Elastic IP, alarms, and infrastructure recovery.
Those resources answer a provisioning question: what must exist around the appliance for it to run?
The appliance answers a different question: what exactly is allowed to run there, and how can that answer be reproduced?
The new repository owns the Ubuntu Server ARM64 root filesystem and provisioning scripts, Packer source, pinned build inputs, WireGuard, nftables, AdGuard Home, systemd units, schemas, reconciliation, contract tests, AMI candidates, and promotion evidence. It also owns image-level recovery.
That is too much independent behavior to hide behind an infrastructure stack. It has its own update cadence and its own failure modes. An operating-system security fix should result in a rebuilt and replaced appliance, not an unattended package mutation on a running gateway. A change to peer reconciliation needs tests that describe a complete network generation, not a Terraform plan that happens to create the host.
The boundary is therefore not “Terraform versus code.” Both repositories contain engineering work. The boundary is between infrastructure state and appliance release.
Provisioning decides where the gateway can run. The appliance release decides what it is.
Private does not mean secret-bearing
Most platform implementation repositories are public from their first commit. That is an intentional discipline: source, desired state, artifacts, and history must be safe to inspect because no public artifact carries authority.
rs-gateway is the exception, not a retreat from that rule. It owns production
image inputs and the privileged workflow that releases an AMI. A change there
belongs inside a tighter review, rollback, and compromise boundary than
ordinary public infrastructure code.
Private visibility still does not authorize secrets in Git, an AMI, or a build log. The repository contains no private keys, WireGuard key material, generated peer inventory, reusable AWS credentials, or runtime secret values. Those remain in AWS Secrets Manager. Terraform may create the containers, references, and policies, but never the values.
The difference matters. “Private repository” is an access-control setting; it is not a data-classification system or a substitute for a secret manager.
Bind the privilege to the release, not the repository name
The gateway image needs a privileged AWS role to create AMI candidates. That role remains part of the infrastructure envelope, including its IAM definition and instance profile. Its physical name remains unchanged during the migration to avoid needless replacement of live identities.
What changes is who may assume it.
The role’s OIDC trust is bound to the immutable numeric identity of the private
rs-gateway repository and its exact reusable image workflow. No rs-infra
workflow may assume it.
This makes the permission useful without making it ambient. Renaming a repository, adding a nearby workflow, or changing an unrelated public infrastructure action does not silently inherit the right to build an image. The release path is both explicit and reviewable.
That is a better shape for a high-consequence action than a broad same-repository permission. The relevant question is not whether a workflow can reach AWS. It is whether this exact reviewed release contract is the one allowed to do so.
Reproducibility starts before the final AMI
The gateway’s build contract now begins with immutable inputs. It uses an official Canonical Ubuntu Server 26.04 LTS ARM64 source image, resolved through the public SSM namespace and then pinned by regional AMI ID and source-image serial. It builds from a dated Ubuntu archive snapshot with reviewed package versions.
The release records the source AMI, archive snapshot, installed package inventory, SSM Agent revision, checksums, SBOM, provenance, and resulting AMI ID. The final appliance has no OpenSSH server and no EC2 key pair. SSM Session Manager is its only operating-system administration and recovery path.
Packer may use SSH only through an SSM tunnel to a temporary builder. There is no inbound port 22, and OpenSSH is removed before the final image is captured.
These are not decorative supply-chain fields. They make replacement a question with evidence behind it: which source did this appliance come from, what was installed, how was it tested, and can recovery work through the only administrative path that will exist after promotion?
The split also exposes what is unresolved
The old delivery design put complete production .tfvars documents in GitHub
Actions secrets. That made opaque GitHub settings a configuration database:
reviewers could not inspect a proposed configuration diff, bind it to a plan,
or recover intended state from history.
That authority is now rejected. Remote Terraform plans and applies are paused until a separate decision defines a versioned, reviewable, attributable configuration authority that binds the approved configuration to the exact reviewed plan. Static validation remains useful, but it is not evidence that a cloud change is safe to apply.
The gateway split does not solve that separate problem. It does not build an AMI, apply Terraform, write a secret version, settle production network or DNS configuration, or prove the platform ready.
Those limits are part of the value of the boundary. A repository should not become the place where every unresolved concern accumulates simply because it is private or because it touches the gateway.
A smaller, clearer release contract
The result is not more repositories for their own sake. It is a smaller contract for each review path.
rs-infra can remain public, reusable infrastructure code. It provisions the
stage and retains the identities and resources the gateway needs. rs-gateway
can own the appliance that runs on that stage, prove its release inputs, and
exercise the one privileged image workflow.
Cross-repository changes still exist. A change to the WireGuard interfaces or
the secret-free runtime input contract must be coordinated across
rs-platform, rs-infra, and rs-gateway. The split does not remove that
work; it makes the handoff visible.
The gateway was already designed to be replaced rather than repaired. Giving its release path an explicit boundary applies the same idea to the engineering around it: preserve the contracts, make privilege narrow, and leave behind evidence that the next appliance is the intended one.