Files
acdl/modules/l1/iam-role
Jon Chery ad3cc5f129
acdl-ci / Lint (pull_request) Successful in 7s
acdl-ci / Test (pull_request) Successful in 4m3s
acdl-ci / Platform check-only (offline) (pull_request) Successful in 21s
acdl-modules-lifecycle / CI VPC apply (pull_request) Failing after 1m25s
acdl-modules-lifecycle / L1 lifecycle (alb) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (cloudfront) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (ecr) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (ecs-cluster) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (ecs-service) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (iam-role) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (kms-key) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (rds) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (s3) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (uptime) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (vpc) (pull_request) Has been skipped
acdl-modules-lifecycle / L1 lifecycle (waf) (pull_request) Has been skipped
acdl-modules-lifecycle / CI VPC destroy (pull_request) Successful in 44s
fix(ci): separate short-lived CI VPC + fix 8 module lifecycle failures
Two architectural changes:
1. Created terraform/ci-vpc/ — a short-lived VPC for L1 module lifecycle
   testing, separate from the long-lived platform VPC. Created before
   VPC-dependent modules (alb, ecs-service, rds, uptime) are tested,
   destroyed after. Outputs (vpc_id, subnet_ids, sg_id, cluster_arn) are
   passed to those modules via scripts/run_lifecycle_test.sh +
   run_lifecycle_destroy.sh wrappers that inject the CI VPC outputs into
   the example contracts.
2. Updated the workflow to use ci-vpc-apply → lifecycle (with artifact
   passing) → ci-vpc-destroy (always runs).

8 module-specific fixes:
- s3: unique bucket names (acdl-ci-s3a-simple/complex) instead of
  globally-taken 'my-simple-bucket'
- kms-key: alias name with no spaces (locals.tf → alias/acdl-ci-kms)
- iam-role: example contract uses role_name (not name, which the interface
  doesn't declare)
- ecs-service: example contract uses family (not name); VPC inputs
  (cluster_arn, subnets, security_group) injected by CI VPC wrapper
- uptime: added subnets, security_group, cluster_arn to interface + module;
  network_configuration is dynamic (only when subnets provided)
- rds: added subnet_ids input + db_subnet_group resource (conditional
  on subnet_ids being non-empty)
- alb: removed hardcoded placeholder sg/subnet values from examples;
  vpc_id + subnets + security_group injected by CI VPC wrapper
- cloudfront: removed invalid placeholder WAF ARN from complex example

Regression: 479 passed, 0 skipped, 5 deselected. All 24 example contracts
pass --check-only.

---ci---
project: acdl
phase: P59
milestone: v1.11
status: execute
---/ci---
2026-07-28 17:52:58 +00:00
..

iam-role — IAM role

Module kind: primitive | Version: 1.0.0

A single IAM role with an assume-role policy and optional managed policy attachments. Used as the ECS task execution role.

Resources

Resource Type Purpose
role aws_iam_role The IAM role with assume-role policy

Inputs

Name Type Required Default Description
role_name string yes The IAM role name
assume_role_policy string yes Assume-role policy document (JSON string)
managed_policies string no Comma-separated list of managed policy ARNs to attach
region string yes AWS region the role is created in

Outputs

Name Type Description
role_arn arn The IAM role ARN
role_id string The IAM role id

Usage

{
  "id": "roles",
  "type": "aws:iam:role",
  "module": "iam-role@1.0.0",
  "inputs": {
    "role_name": "acdl-microservice-exec",
    "assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ecs-tasks.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}",
    "managed_policies": "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",
    "region": "us-east-1"
  }
}

The assume_role_policy is a JSON string — the adapter jsonencodes it into the Terraform assume_role_policy argument. The managed_policies input is a comma-separated list of ARNs, emitted as managed_policy_arns = [...].

Compliance extension points

  • Permissions boundary — add permissions_boundary to enforce least-privilege guardrails (SOC2 CC6.1, SOX ITGC, DORA ICT access control).
  • Inline policy — add aws_iam_role_policy for fine-grained least-privilege instead of broad managed policies (SOC2 CC6.1.
  • MFA conditions — add condition blocks requiring MFA for assume-role (SOC2 CC6.1.
  • Source IP / region conditions — add aws:SourceIp / aws:RequestedRegion conditions for data residency enforcement (GDPR Art.44-49, DORA ICT third-party risk).
  • Access Analyzer — add aws_accessanalyzer_analyzer to verify least-privilege (SOC2 CC6.1, GDPR Art.32).
  • Role separation — add a separate task role vs. execution role (SOC2 CC6.3 segregation of duties).

Examples

Validated example contracts are in examples/. The platform-test pipeline validates them against schemas/contract.schema.json.

Simple

A minimal deployment:

examples/simple.yml

environment: dev
id: role
infrastructure:
  iam-role:
    inputs:
      name: my-task-role
      region: us-east-1
    version: 1.0.0
name: iam-role

Complex

A production deployment with optional inputs:

examples/complex.yml

environment: dev
id: role
infrastructure:
  iam-role:
    inputs:
      name: my-production-task-role
      region: us-east-1
    version: 1.0.0
name: iam-role

Versioning

1.0.0 — interface MAJOR, behavior MINOR, lifecycle PATCH. MAJOR bumps require a new registry entry (immutable publication); old entries enter a 12-month deprecation window.