Opsitron separates building from deploying. Application code is built once, stored in a shared account, and then promoted to each environment. This ensures you deploy the exact same artifact to staging and production — no “works on dev but fails on prod” surprises.
The Architecture
Application Repo (your code)
│
│ push to main
▼
Build Workflow (GitHub Actions)
│
│ build once
▼
SharedServices Account
├── ECR Repository (containers)
│ └── sha-abc1234
└── S3 Artifact Bucket (static sites)
└── builds/my-app/abc1234.zip
│
│ deploy = pull from shared → push to environment
▼
Workload Accounts
├── Dev (auto-deploy on build)
├── Staging (staff approval)
└── Production (staff + client approval)
Build Once, Deploy Many
Container Applications
When you push to your app’s main branch:
- Build — GitHub Actions builds a Docker image from your Dockerfile
- Tag — Image is tagged with the git short SHA (e.g.,
sha-abc1234) - Push — Image is pushed to the app’s dedicated ECR repository in the SharedServices account
- Notify — The build workflow notifies Opsitron of the new artifact
The same image tag (sha-abc1234) is used across all environments. When you deploy to dev, staging, and production, each environment pulls the identical image from the shared ECR.
Static Sites
When you push to your static site’s main branch:
- Build — GitHub Actions runs your build script (Hugo, Vite, Next.js, etc.)
- Package — Build output is zipped
- Upload — Zip is uploaded to the SharedServices S3 artifact bucket at
builds/{app-slug}/{git-sha}.zip - Notify — The build workflow notifies Opsitron of the new artifact
When deploying, the artifact zip is downloaded from SharedServices and synced to the environment’s website S3 bucket.
Why SharedServices?
All build artifacts live in a single SharedServices account rather than in each workload account:
- One build, many deploys — the same artifact is promoted to each environment without rebuilding
- Cross-account access — workload accounts have read access to SharedServices via AWS Organizations policies
- Centralized lifecycle — ECR lifecycle policies and S3 versioning are managed in one place
- Audit trail — every artifact is tagged with its git SHA, creating a direct link from deployed code to source
ECR: One Repository Per Application
Each container application gets its own ECR repository in SharedServices, named {namespace}/{app-slug}:
920534281604-acme/web-app ← web-app images
920534281604-acme/api-service ← api-service images
Each repository has:
- Immutable tags — once
sha-abc1234is pushed, it can never be overwritten - Lifecycle policy — keeps the latest 30 tagged images, expires untagged after 30 days
- Cross-account pull — all workload accounts in the organization can pull images
Container Deployment Flow
When Opsitron deploys a container to an environment:
- Update SSM — writes the new image tag to
/{app}/{env}/container-image-tag - Get current task definition — reads the ECS task definition from the target cluster
- Register new revision — creates a new task definition with the updated image tag
- Update ECS service — points the service to the new task definition revision
- Wait for stability — ECS rolls out new tasks with the new image, health checks pass
- Callback — reports success/failure back to Opsitron
The deploy workflow reads all configuration from SSM parameters (cluster name, service name, image tag param) — it’s self-contained and can be run manually from the GitHub Actions UI without Opsitron.
Static Site Deployment Flow
When Opsitron deploys a static site to an environment:
- Download artifact — fetches the zip from SharedServices S3
- Sync to website bucket —
aws s3 syncwith smart cache headers:- Hashed assets (CSS, JS) →
Cache-Control: max-age=31536000, immutable - HTML and JSON →
Cache-Control: max-age=0, must-revalidate
- Hashed assets (CSS, JS) →
- Invalidate CloudFront —
/*invalidation ensures fresh content - Update SSM — records the deployed artifact key
- Callback — reports success/failure back to Opsitron
Auto-Deploy to Dev
For both container and static site applications, pushes to main automatically deploy to the dev environment:
Push to main → Build → Notify Opsitron → Auto-deploy to dev1
This is controlled by the auto_deploy_to_dev setting on the Application. Staging and production deployments always require explicit approval.
Promotion Pipeline
Build → Dev (auto) → Staging (staff approval) → Production (client approval)
At each stage, the same artifact is deployed — the image tag or artifact key doesn’t change. What changes is the environment it’s deployed to, with progressively stricter approval requirements.
OIDC Authentication
Build and deploy workflows authenticate to AWS using OIDC federation — no stored credentials. GitHub Actions assumes an IAM role in your management account, then chains to the target account:
GitHub OIDC → Management Account Role → SharedServices Role (build)
GitHub OIDC → Management Account Role → Workload Account Role (deploy)
This means:
- No AWS access keys stored as GitHub secrets
- Roles have least-privilege permissions
- Sessions are short-lived (1 hour max)
- Audit trail in CloudTrail shows exactly which workflow assumed which role