-
Notifications
You must be signed in to change notification settings - Fork 0
iam architecture
Separate roles per service, least-privilege. Defined in iam.tf within the ECS Module.
flowchart LR
ExecRole[ECS Task Execution Role\nshared] --> ManagedPolicy[AmazonECSTaskExecutionRolePolicy\nAWS managed]
ExecRole --> SecretsRead[secrets_read policy\ndynamic]
BRMSRole[BRMS Task Role] --> S3RW[s3_access\nread-write]
BRMSRole --> RDS[rds_iam_connect\ndb auth=iam]
BRMSRole --> KMS[brms_kms_access\nsecrets_provider=aws-kms]
BRMSRole --> ExtBuckets[brms_external_buckets\nexternal_buckets]
BRMSRole --> Bedrock[brms_bedrock_access\nAI provider=amazon-bedrock]
BRMSRole --> BRMSExec[ecs_exec\nenable_execute_command]
AgentRole[Agent Task Role] --> S3RO[s3_read_only\nread-only]
AgentRole --> AgentExec[ecs_exec\nenable_execute_command]
style RDS stroke-dasharray: 5 5
style KMS stroke-dasharray: 5 5
style ExtBuckets stroke-dasharray: 5 5
style Bedrock stroke-dasharray: 5 5
style BRMSExec stroke-dasharray: 5 5
style AgentExec stroke-dasharray: 5 5
Shared by both BRMS and Agent. Handles image pulling and secret retrieval.
AmazonECSTaskExecutionRolePolicy allows:
- ECR image pull
- CloudWatch log creation
Dynamically constructed based on which components are enabled:
| Secret | Service | Condition |
|---|---|---|
| License key | BRMS | Always (BRMS enabled) |
| Cookie secret | BRMS | Always (BRMS enabled) |
| Secrets master key | BRMS | secrets_provider = "env" |
| AI API key | BRMS | AI enabled + API key provided |
| Custom secrets (brms.secrets) | BRMS | User-provided secrets |
| Custom secrets (agent.secrets) | Agent | User-provided secrets |
| Database credentials | BRMS | db auth = "secrets" |
From Storage Module's s3_access policy:
-
s3:ListBucket,s3:GetBucketLocation -
s3:GetObject,s3:PutObject,s3:DeleteObject+ versions
Created by the Database Module when database.auth = "iam". Allows BRMS to authenticate to Aurora using temporary IAM credentials instead of a password:
data "aws_iam_policy_document" "rds_iam_connect" {
statement {
effect = "Allow"
actions = ["rds-db:connect"]
resources = [
"arn:aws:rds-db:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:dbuser:${aws_rds_cluster.this.cluster_resource_id}/${var.iam_username}"
]
}
}When brms.secrets_provider.type = "aws-kms", grants the BRMS task role permission to use the customer-managed KMS key for encrypting and decrypting internal secrets:
data "aws_iam_policy_document" "brms_kms_access" {
statement {
effect = "Allow"
actions = [
"kms:Encrypt",
"kms:Decrypt",
"kms:GenerateDataKey",
"kms:GenerateDataKeyWithoutPlaintext",
"kms:DescribeKey",
]
resources = [local.brms_kms_key_arn]
}
}See Secrets Management for the KMS setup.
When brms.external_buckets is provided (for multi-account deployments), grants BRMS access to S3 buckets in other AWS accounts. A single list statement and a single object-access statement cover all configured buckets via for-expressions over the bucket ARNs:
data "aws_iam_policy_document" "brms_external_buckets" {
statement {
sid = "ListExternalBuckets"
effect = "Allow"
actions = [
"s3:ListBucket",
"s3:GetBucketLocation"
]
resources = [for b in var.brms_external_buckets : b.arn]
}
statement {
sid = "ExternalBucketObjectAccess"
effect = "Allow"
actions = [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:PutObject",
"s3:DeleteObject",
"s3:DeleteObjectVersion"
]
resources = [for b in var.brms_external_buckets : "${b.arn}/*"]
}
}When BRMS AI provider = amazon-bedrock, grants access to invoke the configured foundation model. No API key needed, IAM handles authentication. The policy is scoped to the specific model ID. When a cross-region inference profile is used (model ID with a geographic prefix such as us., eu., or apac.), a second statement grants access to that profile:
data "aws_iam_policy_document" "brms_bedrock_access" {
statement {
sid = "AllowBedrockFoundationModel"
effect = "Allow"
actions = [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
]
resources = [
"arn:aws:bedrock:*::foundation-model/${local.bedrock_base_model_id}"
]
}
dynamic "statement" {
for_each = local.bedrock_is_inference_profile ? [1] : []
content {
sid = "AllowBedrockInferenceProfile"
effect = "Allow"
actions = [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
]
resources = [
"arn:aws:bedrock:*:${local.account_id}:inference-profile/${local.bedrock_model_id}"
]
}
}
}The region is wildcarded because cross-region inference profiles can route to any region within the geography. The model resource is scoped to the single configured model ID, not all foundation models.
See AI LLM Configuration for AI setup.
When enable_execute_command = true, grants SSM permissions for interactive container shell access:
data "aws_iam_policy_document" "ecs_exec" {
statement {
effect = "Allow"
actions = [
"ssmmessages:CreateControlChannel",
"ssmmessages:CreateDataChannel",
"ssmmessages:OpenControlChannel",
"ssmmessages:OpenDataChannel",
]
resources = ["*"]
}
}Much simpler than BRMS:
From Storage Module's s3_read_only policy:
-
s3:ListBucket,s3:GetBucketLocation -
s3:GetObject,s3:GetObjectVersion
No write access, Agent only reads rules, never modifies them.
For the Database Module's IAM user setup Lambda:
-
AWSLambdaVPCAccessExecutionRole(AWS managed) -
secretsmanager:GetSecretValueon the database credentials secret
The Lambda connects to Aurora as the master user using the username and password from Secrets Manager (via the psycopg layer), then runs CREATE USER, GRANT rds_iam, and ALTER DATABASE to provision the IAM-auth database user. It does not use IAM database authentication itself, so it is not granted rds-db:connect. That permission belongs only to the BRMS Task Role (see RDS IAM Connect above).
When storage.auth = "secrets", an IAM user is created:
- The bucket-scoped
s3_accessread-write policy attached (ListBucket and GetBucketLocation on the bucket, Get/Put/Delete object actions on its objects, see Storage Module). This is full read-write on the GoRules bucket only, not account-wide S3 access. - Access keys stored in Secrets Manager
- See Storage Module for details
flowchart LR
StorageMod[Storage Module] -->|creates policies\noutputs ARNs| Root1[Root Module]
Root1 -->|passes ARNs| ECS1[ECS Module]
ECS1 -->|attaches to| TaskRoles[Task Roles]
DBMod[Database Module] -->|creates policies\noutputs ARNs| Root2[Root Module]
Root2 -->|passes ARNs| ECS2[ECS Module]
ECS2 -->|attaches to| BRMSRole[BRMS Task Role]