Front-End Web & Mobile

AWS AppSync Merged APIs Best Practices: Part 3 – Security

In this AWS AppSync Merged API – Best practices series, we cover important topics for developers, architects, and security engineers who are creating and managing AWS AppSync Merged and Source APIs. This multi-part series discusses best practices on schema composition, security, deployment and testing and subscriptions for Merged APIs.

AWS AppSync offers Merged APIs, which allow multiple teams to operate independently, contribute to a unified primary GraphQL organizational data interface, and remove bottlenecks from existing manual processes when teams need to share development of a single AppSync API. The AppSync Merged APIs feature allows AppSync customers to import the resources of multiple source AppSync APIs into a single AppSync API endpoint. The imported resources include GraphQL schema, datasources, AppSync resolvers, and AppSync Functions. AppSync Merged APIs can be created using source APIs from the same account in the same region or different AWS accounts within the same region.

As part of this Merged APIs best practices series, we walked through creation of cross-account Merged APIs and best practices on schema composition. In this post, we go over some of best practices on Merged APIs and Source APIs security features and describe when and how you might want to use them in your own applications.

Authorization Mode

A method of authorization — a token in the request header or signing the request itself with AWS credentials — is always required to access your AppSync Merged API. Multiple authorization modes are available to protect your Merged API. The authorization modes of a Merged API are configured by the Merged API owner. The Merged API owner is responsible for making sure the authorization mode of source APIs are configured either as primary or secondary auth modes for the Merged API and also implementing the business logic of the authorizer. i.e. If a source API has a Lambda authorizer as primary auth mode, the Merged API owner is responsible for implementing the Lambda authorizer for the Merged API as well.

AppSync Merged API and Source API Authorization flow diagram

Primary Authorization Mode

When you create a Merged API, you need to select a Primary Authorization mode. It is recommended to choose this authorization mode based on the client/user needs. In order for source API associations to be compatible, a Merged API must include the primary authentication mode of each source API either as a primary or additional authentication mode in its configuration.

Primary authorization mode selection during creation of Merged API

Secondary Authorization Modes

In case the Primary authorization mode of a Source API is different than the Merged API, you need to configure the authorization mode of the Source API as an additional auth mode for Merged API settings as shown below.

Secondary authorization mode configuration
If the Source API has additional authorization modes, the merge operation will succeed as long as Source API’s primary auth mode is configured as part of Merged API. However, the run time queries/mutations might fail based on authorization rules. So, it is recommended for the Merged API owner to configure and implement secondary authorization modes of the source API(s) as well in the Merged API.

When using multi-auth directives in the source APIs, the merging process is able to automatically merge these directives into the unified endpoint. In the case where the primary authorization mode of the source API doesn’t match the primary authorization mode of the Merged API, it will automatically add these auth directives to ensure that the authorization mode for the types in the source API is consistent. For additional details refer to Configuring authorization modes.

Re-using Authorization providers

Customers can also re-use authorization providers from the source API to the Merged APIs as well. i.e. Customers can re-use the same Cognito user pools and Lambda Authorizer functions if the Source API and Merged APIs are in the same account. In case that the Merged APIs and Source APIs are in different accounts, you can re-use only the Cognito user pools. (refer note below). But in case of Lambda Authorizer function, you have to create a separate Lambda function in Merged API account.

Note : In case of cross-account Cognito user pools, they can be configured only through an CLI/IaC (CloudFormation/CDK) and not through the console. The request will use the same session token to the AppSync endpoint in each separate account. Also, you lose the ability to use the Query Editor in the AppSync console because the Query Editor assumes the user pool is in the same account during authentication.

Example API command to configure cross-account user pool as an auth mode:

aws appsync --region <appsync merged api region> update-graphql-api --api-id <appsync merged api id> --name <Merged API name> --authentication-type AMAZON_COGNITO_USER_POOLS --user-pool-config '{ "userPoolId":"<source api user pool id>", "defaultAction":"ALLOW", "awsRegion":"<source account user pool region>"}'

Merged API Service Role Permissions

When you create a Merged API, you need to define a service role. An AWS service role is an AWS Identity and Access Management (IAM) role that is used by AWS services to perform tasks on your behalf.

The service role for your Merged API is necessary to access resolvers configured and merged from your source APIs. The required service role for this is the mergedApiExecutionRole, and it must have explicit access to execute requests on source APIs included in your Merged API via the appsync:SourceGraphQL IAM permission. During the execution of a GraphQL request, AppSync service principal assumes the execution role on behalf of the Merged API and validates access to the source API. Then, once the access is authorized, the context switches and the source API executes the request to the data source. In order for the source API to access the data source, it follows the same method as a request directly to the source API. The AppSync service principle assumes the source API service role for the data source and executes the request.

Additionally, the mergedApiExecutionRole is also used when you enable auto merge for a source api association. When auto merge is enabled, the Merged API subscribes for any changes to the source API. When the Merged API is notified of a change by the source API, it assumes the execution role and requires the appsync:StartSchemaMerge permission to merge changes from the source API to Merged API.

Here is an example of default permission:

  {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "appsync:SourceGraphQL"
            ],
            "Resource": [
                "arn:aws:appsync:us-west-2:123456789012:apis/<Source API Id>",
                "arn:aws:appsync:us-west-2:123456789012:apis/<Source API Id>/*",
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "appsync:StartSchemaMerge"
            ],
            "Resource": [
                "arn:aws:appsync:us-west-2:123456789012:apis/<Merged API Id>/sourceApiAssociations/*"
            ]
        }
    ]
}

It is recommended to use default permissions to allow Merged API execution role to access all the data sources, resolvers and functions of Source APIs in order for Merged API to securely access the source API resources during queries, mutations and subscriptions. For advanced use cases where you need Merged API to access only certain Source API resources refer to section below.

Restricting access by Source API

AWS AppSync supports allowing or denying this permission on specific top-level fields within the request like how the IAM authorization mode works for IAM APIs. This means you can explicitly control which resolvers of top-level fields within a Merged API schema a Merged API can access.

For example , taking same example of Books-Reviews-Authors schema from the launch blog, if you want to allow only access to certain top level queries and mutations inside the schema, the policy of the Merged API execution role should look like:

{
"Version": "2012-10-17",
    "Statement": [{
"Effect": "Allow", 
        "Action": [ "appsync:SourceGraphQL"], 
        "Resource": [ 
            "arn:aws:appsync:us-west-2:123456789012:apis/YourSourceGraphQLApiId/types/Query/fields/getBook",
            "arn:aws:appsync:us-west-2:123456789012:apis/YourSourceGraphQLApiId/types/Query/fields/listBooks",
            "arn:aws:appsync:us-west-2:123456789012:apis/YourSourceGraphQLApiId/types/Mutation/fields/createBook",
            "arn:aws:appsync:us-west-2:123456789012:apis/YourSourceGraphQLApiId/types/Mutation/fields/updateBook"
            ] 
    }] 
}

For non-top-level fields, AWS AppSync requires you to define the permission on the source API ARN itself. In order to restrict access to specific non-top-level fields in the Merged API, we recommend implementing custom logic within your Lambda or hiding the source API fields from the Merged API using the @hidden directive.

Cross-Account Permission model

When you create a Merged API, you can optionally associate source APIs from other accounts that have been shared via AWS Resource Access Manager (AWS RAM). You can add AWS AppSync APIs to a resource share in AWS RAM. Within a resource share, AWS AppSync provides three different permission sets that can be associated with an AWS AppSync API in RAM:

AWSRAMPermissionAppSyncSourceApiOperationAccess: The default permission set that’s added when sharing an AWS AppSync API in AWS RAM if no other permission is specified. This permission set is used for sharing a source AWS AppSync API with a Merged API owner. This is recommended in most of the use cases where Source API teams are responsible for sharing what access Merged APIs can have on the operations.
AWS RAM managed permission sets for AppSync APIs
In case this permission model does not suit your needs, refer to Configuring cross-account Merged APIs using AWS RAM for additional permission sets you can use.

Private API considerations

AWS AppSync Merged APIs provide built-in support for Private APIs that limit access to your Merged API’s GraphQL and Real-time endpoints to traffic originating from VPC endpoints that you can configure.

Here are some security considerations on restricting access to Merged APIs to clients within a private network.

  • Private DNS
    • It is recommended to enable Private DNS for the Interface Endpoint for AWS AppSync. This will enable customers to use the API URL generated by AppSync within their applications for queries, mutations and subscriptions.
  • Security groups
    • Consider creating a restrictive security group which only allow internal VPC traffic to Interface Endpoint for AWS AppSync. You can configure the security group to narrow it down to the subnet IP address range or the IP address of the resource that will invoke the API.
  • VPC endpoint policies
    • To further restrict access to a Private API you use a VPC endpoint custom policy to restrict which APIs can be invoked from resources in the VPC
    • For example, here is a custom policy to restrict based on the account id
{
	"Statement": [
		{
			"Action": "appsync:*",
			"Effect": "Allow",
			"Principal": "*",
			"Resource": "*",
			"Condition": {
				"StringEquals": {
					"aws:PrincipalAccount": "111122223333"
				}
			}
		}
	]
}

Note :

  • For IAM based authentication, these requests needs to be signed with Sigv4 signature in order to recognize the AWS principal.
  • If you are using Lambda or OIDC Authorization modes, you have to use a wildcard VPCE policy. These requests do not include a Sigv4 signature, so a principal can not be evaluated, hence access will be denied.
  • The VPC Endpoint and the AppSync private API should exist in the same AWS account at this point in time.

Restrict Access to Datasources

Datasource access is important when it comes to who can access your data sources such as Dynamo DB tables, Lambda functions etc. In this case, you can restrict only a specific account or API can access the data source. Merged API execution role is used to run resolvers that access data from the data sources configured in your source APIs. During the execution of a GraphQL request, the Source API will assume this service role and authorize the role to perform the data source access.

The source API needs to have appropriate permissions to perform operations on your AWS resource, such as PutItem on an Amazon DynamoDB table. You can also add conditions to your trust policy to limit access to the data source such as SourceArn and SourceAccountthat can access the data source. For additional information IAM trust policy and conditions that can be applied, refer to Adding a data source documentation.

Web Application Firewall/ Rate Limiting

AWS WAF is a protective tool for web applications and APIs, guarding against attacks. By setting up rules in a web access control list (web ACL), you can permit, reject, or track web requests based on custom security criteria. Integrating AWS AppSync Merged API with AWS WAF enhances control and insight into your API’s accepted HTTP traffic.

With AWS WAF, you can safeguard your AppSync Merged API from common web threats like SQL injection and cross-site scripting (XSS) attacks. These could otherwise harm availability, performance, security, or resource usage. For instance, you can design rules to allow/block requests from specific IP ranges, CIDR blocks, designated countries, or those carrying malicious SQL code or scripts. You’re also able to generate rules that thwart attacks from certain user agents, malicious bots, and content scrapers. As an example, rate-based rules permit you to define the count of allowable web requests per client IP over a rolling 5-minute period.

Refer to the following links on how to Integrate an AppSync API with AWS WAF and example rules.

Limit access to Introspection

AWS AppSync Merged API and Source APIs exposes Introspection capabilities that allows queries on the metadata of the schema for that particular GraphQL API. Introspection should primarily be used as a discovery and diagnostic tool and recommended to turn it off in your production environment and public facing environments.

To protect the Introspection API queries, it is recommended to Integrate with AWS WAF with a web ACL rule to prevent GraphQL __schema introspection queries to an API. Refer here for additional details on the example rule.

Audit Trail

AWS AppSync links with AWS CloudTrail, which records actions within AWS AppSync carried out by an AWS user, role, or service. CloudTrail keeps track of API requests in AWS AppSync as events, covering requests from the AWS AppSync console and programmatic calls to AWS AppSync API operations. For an ongoing record of events in your AppSync Merged and Source APIs create a trail and follow security best practices in AWS CloudTrail.

Conclusion

This is the third post in a five-part series on best practices on Design, Development, Testing and Deployment of AWS AppSync Merged APIs. In this post, we explained recommended practices around Security for your Merged APIs, Cross-account considerations, Fine grained access control, Private API security model, Datasource access, Integrating with AWS WAF and AWS CloudTrail. For additional information on AppSync Security refer to Security best practices for AWS AppSync.

To learn more about AWS AppSync Merged APIs, refer to the AWS AppSync documentation or visit the product page for more general information on AWS AppSync. We can’t wait to see what you will build!

About the author

Venugopalan Vasudevan is a Senior Specialist Solutions Architect focusing on AWS Front-end Web & Mobile services. Venu helps customers build their front-end and mobile strategies on AWS, including maturing and enhancing their DevOps practices.