Skip to main content

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

The deep 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 CDK RoleProps are supported.
A fixed roleName is account-global. Set one only on a role confined to a single account and region stack, otherwise regional duplicates of the same stack collide on the name and roll back.

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 from aws-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 Fjall ManagedPolicy 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

Prefer resource grant methods where they exist. They write the tightest possible statement and wire up KMS decrypt for you.

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.
LambdaFunction rejects deprecated runtimes at synth time. nodejs18.x and every earlier Node.js, Python 3.9 and below, java8, dotnet6, go1.x and the rest of the deprecated set throw with a message pointing at Runtime.NODEJS_24_X. This is the shift-left of the posture scan’s LAMBDA_DEPRECATED_RUNTIME finding.

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:
The fjall aws exec deploy session and the AdministratorAccess permission set already carry both. A custom Identity Center permission set adds the KMS statement itself:
Extend the task role from the service props.

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.
Changing naming changes both the role name and the construct id, which replaces the role. Child accounts hold the old ARN literally and lose delegation. Apex zones pin naming: "first-label" for exactly this reason.

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’s own constructs are lint-enforced on this by the fjall/iam-secrets-arn-suffix rule. Apply the same shape to policies you write by hand.

Avoid wildcard actions and resources

Some AWS actions are account-level and legitimately need 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

  1. Prefer resource grant* methods over hand-written statements.
  2. Let LambdaFunction and the ECS pattern build their own roles. Extend them through inlinePolicy and taskRoleInlinePolicies.
  3. Give every role a description. Fjall sets one on its own generated roles so an audit sees a purpose on each.
  4. Scope Secrets Manager ARNs with -*, never a bare *.
  5. Leave roleName unset unless a path- or name-scoped grant needs to match it.
  6. Use permissionsBoundary for roles that application code can influence.
  7. 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.