IAM Roles & Policies
After the Phase 7 cleanup of 2026-05-14 the legacy EC2 instance roles + their 9 custom policies are gone. The production-active set is:
- ECS task roles for backend + bg-tasks (carry the runtime AWS permissions).
- ECS execution roles for Fargate runtime (image pull, logs, secrets).
- github-actions-role for CI/CD via OIDC.
- EC2-SSM-Profile for the only remaining EC2 (Jitsi).
- A handful of single-purpose roles (
aiqlick-scheduler-role,aiqlick-canary-role-dev,aiqlick-rum-dev-unauth-role,aiqlick-aws-config-role).
No static access keys are used anywhere.
ECS task roles (active)
These are the runtime roles every Fargate task assumes. Each carries one inline policy that covers the full app-level permission surface; no managed policies are attached, so the per-env grants are visible in one place.
| Role | Trust principal | Inline policy | Used by |
|---|---|---|---|
aiqlick-ecs-backend-task-role-prod | ecs-tasks.amazonaws.com | BackendTaskPolicy | backend-prod ECS service |
aiqlick-ecs-backend-task-role-dev | ecs-tasks.amazonaws.com | BackendTaskPolicy | backend-dev ECS service |
aiqlick-ecs-bg-task-role-prod | ecs-tasks.amazonaws.com | BgTaskPolicy | bg-tasks-prod ECS service |
aiqlick-ecs-bg-task-role-dev | ecs-tasks.amazonaws.com | BgTaskPolicy | bg-tasks-dev ECS service |
BackendTaskPolicy grants
- S3 CRUD on
aiqlick-uploads/*andaiqlick-dev-uploads/* - SQS send/receive on
aiqlick-{mail,notifications-delivery,notifications-fanout,inbound-jobs,inbound-cvs,agent-docs,bg-events}-{env}+ their DLQs - SNS publish on
arn:aws:sns:eu-north-1:842697652860:aiqlick-pubsub-{env} - EventBridge
PutEventsonaiqlick-events-{env} - AppConfig read on the
e6qub9kapplication's{env}environment +zatlet7profile - Secrets Manager read on
aiqlick-backend/{env}* - X-Ray
PutTraceSegments/PutTelemetryRecords
BgTaskPolicy grants
- Bedrock
InvokeModel/InvokeModelWithResponseStream(eu-north-1 + cross-region inference profiles) - Rekognition
DetectFaces(eu-west-1) - Transcribe
StartStreamTranscription(eu-west-1) - Polly
SynthesizeSpeech,DescribeVoices(eu-west-1) - S3 CRUD on uploads buckets
- SQS receive/delete on
aiqlick-{inbound-jobs,inbound-cvs,agent-docs,bg-events}-{env}+ DLQs - SNS publish on
aiqlick-pubsub-{env} - EventBridge
PutEventsonaiqlick-events-{env} - AppConfig read
- Secrets Manager read on
aiqlick-backend/{env}* - X-Ray
The repo source for these is at
aiqlick-backend/infrastructure/ecs/iam/
and
background-tasks/infrastructure/ecs/iam/.
ECS execution roles
These are the roles Fargate itself assumes to launch a task — distinct from the task role, which the running app uses.
| Role | Trust principal | Grants |
|---|---|---|
aiqlick-ecs-execution-role-prod | ecs-tasks.amazonaws.com | ECR pull, CloudWatch Logs CreateLogStream/PutLogEvents on /ecs/aiqlick-*-prod, Secrets Manager GetSecretValue on aiqlick-backend/production* |
aiqlick-ecs-execution-role-dev | ecs-tasks.amazonaws.com | Same shape, scoped to *-dev log groups + aiqlick-backend/development* secret |
The execution role's secretsmanager:GetSecretValue is what
hydrates _BUNDLE_JSON into the container at task startup — see
Secrets Management.
CI/CD role
github-actions-role
Authentication: OIDC federation with GitHub Actions (no static credentials).
| Policy | Grants |
|---|---|
AmazonEC2ContainerRegistryPowerUser | Push + pull images to/from ECR |
aiqlick-ecs-deploy-policy (inline) | ecs:RegisterTaskDefinition, ecs:UpdateService, ecs:RunTask, ecs:DescribeServices, ecs:DescribeTasks, ecs:Wait*; iam:PassRole on the four ECS task roles + the two execution roles |
AmazonSSMFullAccess | SSM commands — used only by the Jitsi deploy workflow now (backend / BG / FE / docs deploys talk to ECS APIs directly, no SSM) |
github-actions-amplify-policy | Read-only access to Amplify (build status monitor) |
OIDC trust policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::842697652860:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:AiQlickProject/*:*"
}
}
}
]
}
The sub condition scopes access to the AiQlickProject GitHub
organization. Individual workflows assume this role using
aws-actions/configure-aws-credentials@v4 with role-to-assume.
EC2 (Jitsi only)
| Profile | Used by | Grants |
|---|---|---|
EC2-SSM-Profile (instance profile only — no role attached today) | aiqlick-jitsi | AmazonSSMManagedInstanceCore (SSM agent). Jitsi doesn't talk to AWS services directly. |
The legacy aiqlick-{backend,ai}-ec2-role and their 9 custom policies
were deleted in the
Phase 7 cleanup of 2026-05-14.
Other AWS service roles
| Role | Trust principal | Purpose |
|---|---|---|
aiqlick-scheduler-role | scheduler.amazonaws.com | EventBridge Scheduler → invokes the aiqlick-cron-destination API destination for cron POSTs into the backend. Idle until CRON_MODE=external is flipped. |
aiqlick-canary-role-dev | lambda.amazonaws.com | CloudWatch Synthetics canary execution. |
aiqlick-rum-dev-unauth-role | Cognito identity pool | CloudWatch RUM unauthenticated identity for browser RUM. |
aiqlick-aws-config-role | config.amazonaws.com | AWS Config aggregator. |
CodeBuildServiceRole-aiqlick-backend | codebuild.amazonaws.com | CodeBuild (used by the support-backend-rust pipeline). |
Security groups
See Network & DNS — Security Groups
for the canonical SG inventory. The legacy aiqlick-backend-sg and
aiqlick-ai-dev-private-sg were deleted in the Phase 7 cleanup.
Cross-region service access
The bg-tasks ECS task role accesses these services in other regions via the eu-north-1 NAT gateway:
| Service | Region | Accessed by |
|---|---|---|
| Rekognition | eu-west-1 (Ireland) | aiqlick-ecs-bg-task-role-{dev,prod} |
| Transcribe | eu-west-1 (Ireland) | aiqlick-ecs-bg-task-role-{dev,prod} |
| Polly (Neural TTS) | eu-west-1 (Ireland) | aiqlick-ecs-bg-task-role-{dev,prod} |
| SSO Identity Center | us-east-1 | Console login only |
ACM certs for CloudFront and Amplify must live in us-east-1 (AWS
requirement); ALB certs live in eu-north-1 with the ALB.