How IAM permissions work with AppSync

AppSync uses IAM Roles to access resources in the account. Here's how it works

Author's image
Tamás Sallai
3 mins

AppSync follows most other AWS services in terms of how it gets permissions to use resources in an account. By default, it can not access anything and you need to configure IAM policies to allow it access.

In this article, we’ll look into how to configure IAM Roles for AppSync and how to define what permissions the API has.

Data sources

AppSync gets permissions via data sources. Here, you need to define an IAM Role that AppSync will use and gets the permissions from its permissions policy.

Data source

An IAM Role has two types of policies: permissions policies and a trust policy. The former defines what the role can do, while the latter gives access to the role to other entities, in this case, the AppSync service.

Policies

The trust policy to allow AppSync to use this role:

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Principal": {
				"Service": "appsync.amazonaws.com"
			},
			"Action": "sts:AssumeRole"
		}
	]
}

Notice that there is no indication which AppSync API can assume this role. This is a long-standing issue with AWS permissions and the only way to limit using this role for a different API is to restrict the iam:PassRole permission.

Then the permissions policy gives acces to read data from the DynamoDB table:

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Action": [
				"dynamodb:GetItem",
			],
			"Resource": [
				"arn:aws:dynamodb:...:table/...",
			]
		}
	]
}

Under the hood

While it’s entirely transparent, it’s good to know what happens under the hood. This process is used in many other AWS services and even when you use the AWS CLI or the SDKs with temporary credentials.

The first step is AppSync gets temporary credentials for the role. This is allowed as the role’s trust policy specifies the appsync.amazonaws.com service. This credential is made up of three parts:

  • The Access Key ID that identifies the role
  • The Secret Access Key that is needed for the signature
  • The Session Token that needs to be sent with requests

Now that AppSync has the role’s credentials it can make requests to AWS APIs, such as DynamoDB, S3, Lambda, RDS, or one of the other more than 200 services. These are HTTPS endpoints that get various parameters depending on the service.

AppSync then uses the credentials it got in the previous steps to add a signature using the AWS signing process. This involves adding a few extra query parameters and a signature.

Then the AWS service that gets the request first checks the signature then looks up the role’s permissions policy. Finally, it runs the policy evaluation logic to determine if the caller has the necessary permissions or not.

AppSync permissions to call AWS APIsAppSyncIAM roleDDB APIGraphQL requestassume rolecheck trust policyAccess Key IDSecret Access KeySession tokensign requesthttps://...GetItem?X-Amz-Credential=...&Signature=...check signaturecheck policiesresponseresponse

Permissions for Lambda resolvers

Lambda resolvers work similar to other data sources, but there is an extra layer of permissions there. AppSync needs permissions to invoke the Lambda function, but when the code runs it uses a different role to gain access to resources.

AppSync APIDynamoDB TableIAM RoleIAM RoleLambdaService:appsync.amazonaws.comAction:sts:AssumeRoleAction:lambda:InvokeFunctionService:lambda.amazonaws.comAction:sts:AssumeRoleAction:dynamodb:Query

The first part works exactly the same as before: the role trusts the appsync.amazonaws.com service and grants it permission to invoke the Lambda function:

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Action": "lambda:InvokeFunction",
			"Resource": "arn:aws:lambda:..."
		}
	]
}

Then the Lambda function is configured with a different IAM Role:

Role for the Lambda function

This role also has a trust policy and a permissions policy. But this time, it needs to trust the lambda.amazonaws.com service:

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Principal": {
				"Service": "lambda.amazonaws.com"
			},
			"Action": "sts:AssumeRole"
		}
	]
}

Then this role’s permissions policy contains what the function’s code needs access to:

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Action": [
				"dynamodb:GetItem",
			],
			"Resource": [
				"arn:aws:dynamodb:...:table/...",
			]
		}
	]
}
15 June 2022
In this article