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:
amplify 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:
amplify env add --permissions-boundary <iam-policy-arn>
To explicitly specify that the new environment should NOT have a permissions boundary, run:
amplify 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:
amplify env update
In non-interactive shells use
amplify 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.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Deny", "Action": "dynamodb:Scan", "Resource": "arn:aws:dynamodb:<region>:<account-id>:table/users" } ]}
Setup
Create a policy on the AWS console
Add a permissions boundary for a new environment, run:
amplify 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:
amplify add storage
? Please select from one of the below mentioned services: Content (Images, audio, video, etc.)> NoSQL Database? Please provide table name:> 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:
amplify add function
? Select which capability you want to add: Lambda function (serverless function)? Provide an AWS Lambda function name: lambdafunction? Choose the runtime that you want to use: NodeJS? Choose the function template that you want to use: Hello World? Do you want to configure advanced settings? Yes? Do you want to access other resources in this project from your Lambda function? Yes? Select the categories you want this function to have access to. storage? Select the operations you want to permit on users read
In the Lambda function index.js
file, add:
const AWS = require('aws-sdk');const docClient = new AWS.DynamoDB.DocumentClient();
const params = { TableName: process.env.STORAGE_USERS_NAME};
exports.handler = async (event, context) => { try { const data = await docClient.scan(params).promise(); return { body: JSON.stringify(data) }; } catch (err) { return { error: err }; }};
import { DynamoDBClient, ScanCommand } from "@aws-sdk/client-dynamodb";const docClient = new DynamoDBClient();
const params = { TableName: process.env.STORAGE_USERS_NAME,};
export const handler = async (event, context) => { try { const data = new ScanCommand(params); const response = await docClient.send(data); return { body: JSON.stringify(response) }; } catch (err) { return { error: err }; }};
To push the resources, run:
amplify push
Once the push completes, run the Lambda function in the AWS console. You should observe the following error message in the execution result.
User: <assumed-role-arn> is not authorized to perform: dynamodb:Scan on resource: <dynamodb-arn> with an explicit deny in a permissions boundary