Overview
The IAM constructs give AWS services and applications identity-based access control.Role, Policy and InstanceProfile are pass-through wrappers over the CDK classes with identical props and methods. ManagedPolicy adds one default. DelegationRole is a composite construct that Fjall builds for cross-account Route53 delegation.
Most roles in a Fjall application are created for you. Read How Fjall constructs consume roles before writing one by hand.
Resource Classes
lib/... path is a published subpath of the package. IAM constructs are not re-exported from the package root, so this import is the only one that compiles. Import each module directly, since the directory barrel itself is not a resolvable subpath.
This page covers using the construct classes directly. The scaffolded
fjall/<app>/infrastructure.ts that fjall create application writes never
does that: it imports App and the *Factory symbols from the package root,
and fjall add edits it through the codemod engine.What This Creates
Role forces no defaults. Every removal policy, name and permission comes from the props you pass or from CDK’s own defaults.
Basic Usage
props is required. assumedBy is the only required field inside it.
Configuration Options
All standard CDKRoleProps are supported.
Common Patterns
Lambda execution role
ECS task role
EC2 instance role
InstanceProfile wraps the L1 CfnInstanceProfile, so roles takes role names or refs rather than IRole objects.
Principals
Principals come fromaws-cdk-lib/aws-iam unchanged. See the AWS IAM principal reference for the full list.
GitHub Actions OIDC
For CI deploys you do not need this role.
fjall ci setup --provider github
writes the workflow and Fjall mints short-lived credentials for the run. Mint
the deploy token in the web app under Settings → CI/CD Tokens.Policies
Inline policies
Inline policies live and die with the role. Use them for permissions no other identity needs.Managed policies
The FjallManagedPolicy inherits CDK’s static factories, so fromAwsManagedPolicyName and fromManagedPolicyArn work on either import. The one difference is on construction: a Fjall ManagedPolicy created without a description gets `${id} IAM Managed Policy` instead of no description at all.
Adding permissions after creation
Permission boundaries
How Fjall Constructs Consume Roles
Lambda
LambdaFunction builds its own execution role and accepts no role prop. Attach permissions through inlinePolicy, and pin the role’s description, path or name through the dedicated props.
ECS services
The ECS pattern creates two roles per service, named${serviceName}ExecutionRole and ${serviceName}TaskRole. Do not build them yourself.
The execution role carries the four ECR pull actions and a ViaService-conditioned kms:Decrypt, plus path-scoped ssm:GetParameter and ssm:GetParameters when the service declares secrets. It deliberately omits logs:* and secretsmanager:GetSecretValue, because CDK auto-grants those on the exact log group and secret ARNs.
The task role carries the four ECS Exec ssmmessages actions. At the enterprise backup tier the exec session channel and its audit log are encrypted with the stack’s shared key (alias/cmk/<stack>/FjallStackEncryptionKey), and the task role’s kms:Decrypt and kms:GenerateDataKey on it are wired for you. The principal running aws ecs execute-command needs its own grant: ecs:ExecuteCommand on the cluster and its tasks, plus kms:GenerateDataKey on that key at enterprise. grantExecuteCommand grants both halves, scoped to the cluster, at every tier:
fjall aws exec deploy session and the AdministratorAccess permission set already carry both. A custom Identity Center permission set adds the KMS statement itself:
Route53 delegation
DelegationRole is built by the HostedZone construct when a zone mints delegation for child accounts. You read its roleArn, you do not construct it.
The role trusts
OrganizationPrincipal(organisationId) and holds two inline policies: route53:ListHostedZonesByName on *, and route53:ChangeResourceRecordSets scoped to that one zone ARN. The physical name is <stem>DelegateHostedZoneRole, and the ARN is published as a stack export.
Least-Privilege Rules
Scope Secrets Manager ARNs with -*
Secrets Manager appends a six-character random ID after a - separator. A bare * suffix therefore matches sibling secrets.
fjall/iam-secrets-arn-suffix rule. Apply the same shape to policies you write by hand.
Avoid wildcard actions and resources
resources: ["*"]. ecr:GetAuthorizationToken and the ECS Exec ssmmessages actions are the ones Fjall’s own roles use. Constrain everything else with a condition.
Complete Example
Best Practices
- Prefer resource
grant*methods over hand-written statements. - Let
LambdaFunctionand the ECS pattern build their own roles. Extend them throughinlinePolicyandtaskRoleInlinePolicies. - Give every role a
description. Fjall sets one on its own generated roles so an audit sees a purpose on each. - Scope Secrets Manager ARNs with
-*, never a bare*. - Leave
roleNameunset unless a path- or name-scoped grant needs to match it. - Use
permissionsBoundaryfor roles that application code can influence. - Constrain unavoidable
resources: ["*"]statements with a condition.
Troubleshooting
Inspect a deployed role
Run AWS commands through Fjall so credentials are minted for the right account.Next Steps
Secrets Manager
Store and grant access to credentials and API keys.
KMS Key
Encrypt data and scope decryption to specific roles.
Lambda Function
Attach permissions to a serverless function through
inlinePolicy.ECS Cluster
Extend the generated task role for a container service.