Page updated Jan 16, 2024

IAM Permissions Boundary for Amplify-generated roles

To set the maximum permissions that can be granted to IAM Roles created by Amplify CLI, configure a permissions boundary for the project. Then, Amplify-generated IAM roles can perform only the actions that are allowed by both the roles’ policies and permissions boundary. You can configure a different permissions boundary for each environment. For example, this enables you to deny a dev environment all access to a prod environment's resources.

The IAM permissions boundary will apply to all IAM Roles created by Amplify. This includes the "auth role" assumed by users that log into the app and the "unauth role" assumed by guest users. It also applies to Lambda execution roles, Cognito user group roles, and any role configured in a custom resource stack.

The IAM Policy, to be used as a permissions boundary, must be configured outside of Amplify CLI. A permissions boundary is an IAM Policy and can be created following the guide here. This is usually part of an AWS Organization rule or other corporate governance requirement. Once you have created an IAM Policy to use as a permissions boundary, copy the IAM Policy ARN for the next steps.

Set up a permissions boundary in a new project

To initialize a project with a permissions boundary run:

1amplify init --permissions-boundary <iam-policy-arn>

Set up a permissions boundary in a new environment

When creating a new Amplify environment using amplify env add the permissions boundary from the current environment is automatically applied to the new environment.

To specify a different permissions boundary for the new environment, run:

1amplify env add --permissions-boundary <iam-policy-arn>

To explicitly specify that the new environment should NOT have a permissions boundary, run:

1amplify env add --permissions-boundary ''

If Amplify CLI is not able to automatically apply the permissions boundary to the new environment and --permissions-boundary is not specified, it will prompt for a IAM Policy ARN as a permissions boundary.

Update an environment's permissions boundary

To modify the permissions boundary of the current environment, run:

1amplify env update

In non-interactive shells use

1amplify env update --permissions-boundary <iam-policy-arn>

The IAM permissions boundary will be applied on the next amplify push.

Set up a permissions boundary in a cross-account Amplify project

Amplify CLI cannot automatically apply the existing boundary to a new environment in a different AWS account if the --yes flag is used during amplify env add. In this case, a new permissions boundary must be specified using amplify env add --yes --permissions-boundary <iam-policy-arn> or to explicitly remove the permissions boundary from the new environment use amplify env add --yes --permissions-boundary ''.

Permissions boundary usage example

For example, assume that your environment named dev should not be allowed to call a DynamoDB table named users. To enforce this rule, you can use the following policy to set the permissions boundary for the dev environment.

1{
2 "Version": "2012-10-17",
3 "Statement": [
4 {
5 "Sid": "VisualEditor0",
6 "Effect": "Deny",
7 "Action": "dynamodb:Scan",
8 "Resource": "arn:aws:dynamodb:<region>:<account-id>:table/users"
9 }
10 ]
11}

Setup

Create a policy on the AWS console

Add a permissions boundary for a new environment, run:

1amplify env add --permissions-boundary <iam-policy-arn>

Verify if the permissions boundary has been applied by checking the AWS IAM console for the authRole and unauthRole created by Amplify CLI.

To add a DynamoDB table, run:

1amplify add storage
1? Please select from one of the below mentioned services:
2 Content (Images, audio, video, etc.)
3> NoSQL Database
4? Please provide table name:
5> users

To test if the environment enforces the permissions boundary, we can utilize a Lambda function with resource access permissions to the DynamoDB table.

To add a Lambda function, run:

1amplify add function
1? Select which capability you want to add: Lambda function (serverless function)
2? Provide an AWS Lambda function name: lambdafunction
3? Choose the runtime that you want to use: NodeJS
4? Choose the function template that you want to use: Hello World
5? Do you want to configure advanced settings? Yes
6? Do you want to access other resources in this project from your Lambda function? Yes
7? Select the categories you want this function to have access to. storage
8? Select the operations you want to permit on users read

In the Lambda function index.js file, add:

1const AWS = require('aws-sdk');
2const docClient = new AWS.DynamoDB.DocumentClient();
3
4const params = {
5 TableName: process.env.STORAGE_USERS_NAME
6};
7
8exports.handler = async (event, context) => {
9 try {
10 const data = await docClient.scan(params).promise();
11 return { body: JSON.stringify(data) };
12 } catch (err) {
13 return { error: err };
14 }
15};
1import { DynamoDBClient, ScanCommand } from "@aws-sdk/client-dynamodb";
2const docClient = new DynamoDBClient();
3
4const params = {
5 TableName: process.env.STORAGE_USERS_NAME,
6};
7
8export const handler = async (event, context) => {
9 try {
10 const data = new ScanCommand(params);
11 const response = await docClient.send(data);
12 return { body: JSON.stringify(response) };
13 } catch (err) {
14 return { error: err };
15 }
16};

To push the resources, run:

1amplify push

Once the push completes, run the Lambda function in the AWS console. You should observe the following error message in the execution result.

1User: <assumed-role-arn> is not authorized to perform: dynamodb:Scan on resource: <dynamodb-arn> with an explicit deny in a permissions boundary