AWS Resource Verification Matrix
What CloudForge deploys to MiniStack, how it differs from the canonical AWS template, and how to verify each resource against live state.
See also: Verification layers · Template adaptations · Extended Testing
Three Sources of Truth
Every verification question maps to one of three artifacts:
┌─────────────────────────────────────────────────────────────────────────┐
│ 1. Canonical template cdk.out/<stack>.template.json │
│ What CDK would deploy to real AWS. Never modified by MiniStack. │
└───────────────────────────────┬─────────────────────────────────────────┘
│ MiniStackTemplateAdapter
┌───────────────────────────────▼─────────────────────────────────────────┐
│ 2. Adapted template cdk.out/<stack>.ministack.template.json │
│ What CloudFormation sends to MiniStack. Audit: .ministack-adaptations│
└───────────────────────────────┬─────────────────────────────────────────┘
│ MiniStackDeployer (create/update)
┌───────────────────────────────▼─────────────────────────────────────────┐
│ 3. Deployed + runtime CFN stack + service APIs + Docker + auth proxy│
│ What MiniStack recorded and what runs on your machine. │
└─────────────────────────────────────────────────────────────────────────┘
| Question | Where to look |
|---|---|
| “Should this resource exist for my config?” | Canonical template (Layer 6 / comprehensive-resource-validator.sh) |
| “Did we deploy the adapted shape?” | Adapted template + adaptation report |
| “Did MiniStack accept and materialize it?” | CFN list-stack-resources + service APIs |
| “Does the app respond?” | Stack outputs, HTTP, Docker, auth proxy |
Always set endpoint credentials before API checks:
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_DEFAULT_REGION=us-east-1
export AWS_ENDPOINT_URL=http://localhost:4566
export STACK_NAME=my-jenkins # deployment-context.json stackName
export MINISTACK_STACK="${STACK_NAME}-ministack"
If the host aws binary is unavailable or the wrong architecture, run the CLI in Docker:
alias aws='docker run --rm -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY \
-e AWS_DEFAULT_REGION -e AWS_ENDPOINT_URL \
--add-host=host.docker.internal:host-gateway amazon/aws-cli'
export AWS_ENDPOINT_URL=http://host.docker.internal:4566
Verification Methods (How)
| Method | AWS Console equivalent | What it proves |
|---|---|---|
| CFN stack status | CloudFormation → Stacks | Create/update/delete succeeded |
| CFN resource inventory | Stack → Resources tab | Logical resources and physical IDs exist |
| CFN stack events | Stack → Events | Which resource failed and why |
| CFN outputs | Stack → Outputs | Adapter-generated local URLs |
| Service API describe/list | EC2, ECS, ELB, Route53, etc. | Emulator backend populated records |
| Template JSON diff | — (pre-deploy) | Intended add/remove/change between transitions |
| Adaptation report | — (MiniStack-specific) | Explicit local divergences from canonical |
| HTTP probe | Browser / curl | Application responds |
| Docker inspect | ECS task → container | Container running with expected port/volume |
| Auth proxy / mock OIDC | — (local substitute, opt-in) | OIDC flow when ALB auth is in canonical template |
Rule: For infrastructure wiring (VPC, Route53 alias → ALB, Cognito pool present), trust CFN + service APIs. For user-facing reachability locally, trust stack outputs + HTTP, not public DNS or ALB forward behavior.
Resource Matrix — Jenkins Fargate
Legend:
| Column | Meaning |
|---|---|
| Canonical | In cdk.out/<stack>.template.json when config enables the feature |
| Deployed CFN | In adapted template and expected in list-stack-resources after deploy |
| Adapter | Change applied before deploy (none, remove, transform, local-only) |
| Verify via | Primary checks (combine CFN inventory + service API where both apply) |
| Local fidelity | How closely runtime matches real AWS |
Core networking and compute
| Resource type | Canonical | Deployed CFN | Adapter | Verify via | Local fidelity |
|---|---|---|---|---|---|
AWS::EC2::VPC | Always | Yes | none | CFN inventory; aws ec2 describe-vpcs | Metadata + partial networking |
AWS::EC2::Subnet | Always | Yes | none | CFN; aws ec2 describe-subnets | Same |
AWS::EC2::InternetGateway | Always | Yes | none | CFN; aws ec2 describe-internet-gateways | Same |
AWS::EC2::SecurityGroup | Always | Yes | none | CFN; aws ec2 describe-security-groups | Same |
AWS::EC2::SecurityGroupIngress | Often (standalone) | No (inlined) | remove → merge into parent SG | Adaptation report; parent SG rules in describe-security-groups | Equivalent rule intent, different CFN shape |
AWS::ECS::Cluster | Always | Yes | none | CFN; aws ecs list-clusters | Same |
AWS::ECS::TaskDefinition | Always | Yes | none | CFN; aws ecs describe-task-definition | Runs real Docker task locally |
AWS::ECS::Service | Always | Yes | none | CFN; aws ecs describe-services | Service exists; task maps to container |
AWS::IAM::Role | Always | Yes | none | CFN; aws iam get-role (if supported) | Metadata / pass-through for task |
AWS::Logs::LogGroup | Always | Yes | none | CFN; aws logs describe-log-groups | Log group recorded; log delivery varies |
Load balancer
| Resource type | Canonical | Deployed CFN | Adapter | Verify via | Local fidelity |
|---|---|---|---|---|---|
AWS::ElasticLoadBalancingV2::LoadBalancer | Always | Yes | deterministic name | CFN; aws elbv2 describe-load-balancers | ALB metadata; data plane via /_alb/ path |
AWS::ElasticLoadBalancingV2::TargetGroup | Always | Yes | none | CFN; aws elbv2 describe-target-groups | Registered; not used for forward |
AWS::ElasticLoadBalancingV2::Listener | Always | Yes | redirect replaces forward/TLS redirect | CFN; aws elbv2 describe-listeners | Redirect to localhost port, not forward to ECS |
AWS::ElasticLoadBalancingV2::ListenerRule | If present | Yes | auth actions stripped | CFN; aws elbv2 describe-rules | Same redirect/auth stripping rules |
ALB behavior check:
# Listener action should be redirect → localhost:<port> in adapted template
jq '.Resources[] | select(.Type=="AWS::ElasticLoadBalancingV2::Listener") |
.Properties.DefaultActions' "cdk.out/${STACK_NAME}.ministack.template.json"
# Data-plane URL from stack outputs (redirect chain)
aws cloudformation describe-stacks --stack-name "$MINISTACK_STACK" \
--query 'Stacks[0].Outputs[?OutputKey==`MiniStackLocalUrl`].OutputValue' --output text
curl -sIL "$(aws cloudformation describe-stacks --stack-name "$MINISTACK_STACK" \
--query 'Stacks[0].Outputs[?OutputKey==`MiniStackLocalUrl`].OutputValue' --output text)" \
| grep -E '^HTTP|^Location'
Storage and scaling (adapted away)
| Resource type | Canonical | Deployed CFN | Adapter | Verify via | Local fidelity |
|---|---|---|---|---|---|
AWS::EFS::FileSystem | Jenkins default | No | remove | Adaptation report; absent from CFN inventory | Replaced by host bind mount |
AWS::EFS::MountTarget | Jenkins default | No | remove | Same | — |
AWS::EFS::AccessPoint | Jenkins default | No | remove | Same | — |
| Host bind mount | — | Runtime only | local-only | Output MiniStackHostVolume*; docker inspect mount | Persists under .ministack-volumes/<stack>/ |
AWS::ApplicationAutoScaling::* | If configured | No | remove | Adaptation report; absent from CFN | No local autoscaling |
# Bind mount path from stack outputs
aws cloudformation describe-stacks --stack-name "$MINISTACK_STACK" \
--query 'Stacks[0].Outputs[?starts_with(OutputKey, `MiniStackHostVolume`)].{Key:OutputKey,Path:OutputValue}' \
--output table
docker ps --format '{{.Names}} {{.Mounts}}' | grep -i jenkins
Domain and TLS (incremental)
| Resource type | Canonical | Deployed CFN | Adapter | Verify via | Local fidelity |
|---|---|---|---|---|---|
AWS::Route53::HostedZone | domain set | Yes | none | CFN; aws route53 list-hosted-zones | Emulator DNS only — not your laptop resolver |
AWS::Route53::RecordSet | domain / subdomain | Yes | none | CFN; aws route53 list-resource-record-sets | Alias → ALB DNS verifiable via API |
AWS::CertificateManager::Certificate | enableSsl: true | Yes | none | CFN; aws acm list-certificates | Certificate resource exists; local HTTPS termination differs |
| HTTPS listener + cert | TLS enabled | Yes | TLS redirect may become HTTP redirect locally | aws elbv2 describe-listeners | Use outputs for browser URLs |
Domain API check (source of truth — not browser DNS):
aws cloudformation list-stack-resources --stack-name "$MINISTACK_STACK" \
--query 'StackResourceSummaries[?contains(ResourceType,`Route53`)]' --output table
ZONE_ID=$(aws route53 list-hosted-zones \
--query 'HostedZones[?Name==`ministack.local.`].Id' --output text | awk '{print $1}')
aws route53 list-resource-record-sets --hosted-zone-id "$ZONE_ID" \
--query 'ResourceRecordSets[?Name==`jenkins.ministack.local.`]' --output json
See Local DNS vs API verification.
Authentication (incremental)
The local auth runtime is off by default (
MINISTACK_AUTH_AUTOSTART=false). Adapter behavior and CFN inventory checks below apply whenever you deploy with auth enabled; useauthMode: nonefor day-to-day MiniStack testing. See Local Auth Runtime.
| Resource type | Canonical | Deployed CFN | Adapter | Verify via | Local fidelity |
|---|---|---|---|---|---|
AWS::Cognito::UserPool | authMode: alb-oidc + auto-provision | Yes | none | CFN; aws cognito-idp list-user-pools | Pool exists in emulator |
AWS::Cognito::UserPoolClient | Auth enabled | Yes | none | CFN; aws cognito-idp list-user-pool-clients | Same |
AWS::Cognito::UserPoolDomain | Auth enabled | Yes | none | CFN inventory | Same |
ALB authenticate-oidc / authenticate-cognito | Auth enabled | Stripped from listener | transform | Adaptation report; listener describe-listeners has no auth action | Not executed on ALB |
MiniStackAuthProxy + mock OIDC | — | Runtime only (opt-in) | local-only | curl http://localhost:4180/_ministack/auth/health; stack output MiniStackAuthenticatedUrl | Substitutes ALB edge auth |
# Cognito in stack
aws cloudformation list-stack-resources --stack-name "$MINISTACK_STACK" \
--query 'StackResourceSummaries[?contains(ResourceType,`Cognito`)]' --output table
# Auth stripped in adapted template
jq '.[] | select(.reason | contains("authenticate"))' \
"cdk.out/${STACK_NAME}.ministack-adaptations.json"
# Local auth runtime
curl -s http://localhost:4180/_ministack/auth/health
When auth is removed from config, expect Cognito resources absent from CFN inventory after update (same as AWS stack update).
By Deployment Step
What to assert after each incremental step (matches Advanced: incremental deployments):
| Step | Config flags | Assert in CFN inventory | Assert via service API | Assert runtime |
|---|---|---|---|---|
| 0 — Base | no domain, no SSL, no auth | VPC, ALB, ECS, IAM, Logs | describe-load-balancers, list-clusters | MiniStackApplicationUrl HTTP < 500; Docker container |
| 1 — Domain | domain, optional subdomain, createZone | + Route53 zone + records | list-resource-record-sets alias → ALB | FQDN in browser optional |
| 2 — TLS | enableSsl: true | + ACM cert, HTTPS listener | acm list-certificates, listener port 443 | Canonical has cert; local browser may still use output URLs |
| 3 — Auth | authMode: alb-oidc | + Cognito resources in CFN | Cognito APIs | Auth proxy only with MINISTACK_AUTH_AUTOSTART=true |
| 4 — Remove auth | authMode: none | Cognito gone | — | — |
| 5 — Remove domain | clear domain | Route53 gone | Zones/records removed | — |
No-op redeploy: identical adapted template → deployer reports no change set; CFN stack status unchanged.
Template-Level Verification (Pre- and Post-Deploy)
Compare canonical vs adapted vs deployed inventory:
cd cfc-testing
# Resource types — canonical AWS
jq -r '.Resources | to_entries[] | .value.Type' \
"cdk.out/${STACK_NAME}.template.json" | sort | uniq -c
# Resource types — adapted (what CFN receives)
jq -r '.Resources | to_entries[] | .value.Type' \
"cdk.out/${STACK_NAME}.ministack.template.json" | sort | uniq -c
# Every adapter change with reason
jq '.[] | {path, reason}' "cdk.out/${STACK_NAME}.ministack-adaptations.json"
# Deployed inventory (live)
aws cloudformation list-stack-resources --stack-name "$MINISTACK_STACK" \
--query 'StackResourceSummaries[].ResourceType' --output text | tr '\t' '\n' | sort | uniq -c
Parity rule: Deployed CFN resource types should match the adapted template (not the canonical template). Differences from canonical must appear in .ministack-adaptations.json.
For transition testing, use CloudFormationTemplateDiff (in cloudforge-core) between canonical templates at each config step; see Verification.
What Is Not Verified on MiniStack
These appear in canonical templates for AWS compliance and production profiles but are not supported on MiniStack. Preflight blocks templates that contain them, so disable the features that add them before deploying locally:
| Resource / concern | Verified on AWS | MiniStack local |
|---|---|---|
AWS::Config::* | CDK Template.fromStack() integration tests | Blocked by preflight |
AWS::CloudTrail::* | Same | Blocked by preflight |
AWS::GuardDuty::* | Same | Blocked by preflight |
AWS::WAFv2::* | Same | Blocked by preflight |
AWS::RDS::*, AWS::Backup::* | Same | Blocked by preflight; use LocalStack |
| Compliance Config rules / audit posture | COMPLIANCE_TRUTH_TABLES.md | Not emulated |
| Public DNS propagation | Route53 + registrar | Emulator-only Route53 |
| ALB → ECS forward | Real target health | Redirect to localhost |
| ALB edge OIDC/Cognito | Listener authenticate actions | Stripped; optional auth proxy + mock OIDC |
| EFS NFS | Mount in task | Host bind mount |
| Application Auto Scaling | CFN + ECS scaling | Removed by adapter |
Quick Commands Reference
# Full stack picture
aws cloudformation describe-stacks --stack-name "$MINISTACK_STACK"
aws cloudformation list-stack-resources --stack-name "$MINISTACK_STACK" --output table
aws cloudformation describe-stacks --stack-name "$MINISTACK_STACK" \
--query 'Stacks[0].Outputs' --output table
# Built-in verify (outputs + HTTP poll)
java -cp "target/classes:target/dependency/*" \
com.cloudforgeci.ministack.MiniStackCli verify "$MINISTACK_STACK"
# Application container
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' | grep -i jenkins
Related Documentation
- Verification layers — operational walkthrough
- Advanced adaptations — why resources change
- INTEGRATION_TESTS.md — AWS template tests (separate from MiniStack deploy)
- Extended Testing — synthesis and validation scripts