The Javabin platform is shared AWS infrastructure that gives javaBin app repos automated CI/CD, infrastructure provisioning, monitoring, and cost management.
javaBin/registry
(team YAML)
│
▼ repository_dispatch
javaBin/platform
(Terraform + workflows)
│
┌───────────────┼───────────────┐
▼ ▼ ▼
IAM / OIDC ECS Cluster Monitoring
(CI roles) (Fargate) (SNS, Lambda)
│ │ │
▼ ▼ ▼
App repos ALB routing Slack alerts
assume roles *.javazone.no cost reports
in CI compliance
Seven Terraform sub-modules manage shared resources:
| Module | Resources |
|---|---|
| networking | VPC, public/private subnets across 3 AZs, NAT gateway, security groups |
| ingress | ALB, ACM wildcard certificate for *.javazone.no, Route53 DNS |
| iam | GitHub OIDC provider, per-team CI roles (ABAC), permission boundary |
| compute | ECS Fargate cluster (javabin-platform), ECR base config |
| monitoring | SNS topics, EventBridge rules, AWS Config, GuardDuty, Security Hub |
| lambdas | 11 Lambda functions for alerts, cost reporting, compliance, budget enforcement, resource tagging, team provisioning |
| identity | Cognito user pools (internal + external). Internal pool connected to Google IdP. Identity Center is in terraform/org/ (deployed) |
Twelve Terraform modules that app repos source via git:: URLs. CI generates expanded Terraform from app.yaml using expand-modules.py + registry.py. Supported resources: ECR, ECS service, ALB routing, IAM role (configurable for ECS/EC2/Lambda), S3, DynamoDB, RDS PostgreSQL, SQS, Secrets Manager. Cross-service access is auto-wired via access_policy_json outputs.
App repos call javaBin/platform/.github/workflows/javabin.yml as their CI entrypoint. It orchestrates:
- Detect repo contents (JVM, TypeScript, Docker, Terraform)
- Build (Maven or pnpm)
- Docker build + ECR push
- Terraform plan + S3 artifact upload
- LLM risk review via Bedrock (blocks HIGH risk changes)
- Terraform apply (SHA-verified from plan artifact)
- ECS deploy (task definition update)
| Function | Trigger | Purpose |
|---|---|---|
slack-alert |
SNS subscription | Routes security/cost events to Slack with LLM analysis |
cost-report |
Weekly schedule (Mon 08:00 UTC) | Cost breakdown with LLM narrative, per-team attribution |
daily-cost-check |
Daily schedule (08:00 UTC) | Spike detection with team breakdown, silent if no anomalies |
compliance-reporter |
EventBridge (resource create/run) | Reports untagged resources to Slack |
resource-tagger |
EventBridge (all AWS create/run) | Auto-tags created-by + commit from CI session names |
budget-enforcer |
SNS (AWS Budgets 200%) | Scales team's ECS services to zero, posts Slack alert |
override-cleanup |
Hourly schedule | Deletes stale SSM override tokens |
team-provisioner |
Registry merge | Syncs Google Groups, GitHub teams, AWS Budgets, Cognito, Identity Center, hero provisioning |
apply-gate |
CI invocation | Credential broker for gated Terraform apply with risk verification |
securityhub-summary |
Weekly schedule (Mon 08:00 UTC) | HIGH/CRITICAL Security Hub findings summary |
password-set |
Function URL | Self-service password set for new hero accounts |
- Developer creates a repo from
javaBin/app-template(or runsjavabin init) - Registers their team in
javaBin/registry(PR withteams/{name}.yaml) - Platform owner merges — team-provisioner syncs Google Group, GitHub team, Cognito, IAM
- Developer adds the repo to their GitHub team (via GitHub UI or
gh api orgs/javaBin/teams/TEAM/repos) - Developer adds
app.yamlto repo root with service config - Every push to
maintriggers the full pipeline: build, plan, review, deploy
The registry is the IAM gate: unregistered teams have no IAM role, so CI can't deploy. For CI/CD to work, a repo must be under a registered team and have an app.yaml at root.
No per-repo workflow files needed. The platform handles everything.
The registry serves two purposes:
Teams (teams/) — app developer teams that need AWS access. Each team gets an IAM role, budget, GitHub team, and Google Group.
Groups & Heroes (groups/) — organizational membership for all javaBin volunteers:
groups.yamldefines all groups (helter, styret, javazone, pkom, kodesmia, region, drift, admin, developers, etc.) with their properties (Google Workspace email, Cognito/Identity Center flags)heros.yamldefines all hero members with their group assignments
Changes to groups/ trigger provisioning: Google Workspace account creation, group membership sync, email aliases, and Cognito/Identity Center sync where configured. Heroes are synced from a yearly Google Sheets application process.
Every AWS resource gets 7 tags — 5 static (Terraform-managed) and 2 dynamic (auto-applied by the resource-tagger Lambda):
| Tag | Source | Example | Purpose |
|---|---|---|---|
team |
app.yaml / default_tags | web-team |
ABAC, cost attribution, budgets |
service |
app.yaml / default_tags | moresleep |
Cost breakdown within team |
repo |
app.yaml / default_tags | javaBin/moresleep |
Link resource to source code |
environment |
default_tags | production |
Multi-env support |
managed-by |
default_tags | terraform |
Distinguish TF vs console |
created-by |
resource-tagger Lambda | alice |
Who created (set once) |
commit |
resource-tagger Lambda | abc12345 |
Which commit (set once) |
Cost allocation tags are activated in AWS, so Cost Explorer can group by team and service.
Teams get a monthly budget (default 500 NOK). Two thresholds:
- 80% — SNS alert to #javabin-cost-alerts
- 200% —
budget-enforcerLambda scales the team's ECS services todesired_count=0(not destroyed, easy recovery)
- Account: (private — see platform repo)
- Region: eu-central-1 (Frankfurt)
- Domain: javazone.no (Route53)
- ECS cluster: javabin-platform