Front-End Web & Mobile

Architecture Patterns for AWS AppSync Private APIs

AWS AppSync is a fully managed service that enables developers to create GraphQL APIs that securely access, manipulate and combine data from one or more data sources. Recently, AWS announced the support for AWS AppSync Private APIs to help customers restrict access to your GraphQL APIs to API consumers within a private network, such as Amazon Virtual Private Cloud (VPC) or hybrid environment. Requests to AppSync Private APIs will go through AWS’s private network without going over the internet. GraphQL requests from your application are routed via an interface VPC endpoint to AWS AppSync. Interface VPC endpoint is powered by AWS PrivateLink, a highly available, scalable technology that enables you to privately connect your VPC to AWS services like AWS AppSync as if the services were in your VPC.

With Private APIs, consumers in your private network do not need a route to the internet to communicate with the API endpoints. In this blog, we will go through five common architecture patterns to establish connectivity to your AWS AppSync Private API. These architecture patterns include:

  1. Single VPC connectivity to AppSync Private APIs
  2. Cross VPC connectivity to AppSync Private APIs
  3. Cross Account connectivity to AppSync Private APIs
  4. Hybrid connectivity to AppSync Private APIs
  5. Proxy AppSync Private APIs with API Gateway

AppSync Private APIs are accessed via the interface VPC endpoint DNS name or the AppSync API GraphQL endpoint (if “Private DNS name” is turned on while creating the VPC endpoint) as shown below.

AWS AppSync Interface VPC Endpoint configuration

Figure 1: AWS AppSync Interface VPC Endpoint configuration

In the following sections, we will go through each of the architectural patterns and explain how to set up the architecture to meet your use case. We will explain the configuration required to for API consumers to invoke the API endpoint using the AppSync API GraphQL endpoint or interface VPC endpoint public DNS hostnames.

Pattern 1: Single VPC connectivity to AppSync Private APIs
In this pattern, there are two API consumers (EC2 instances) that are hosted in the same VPC as the AppSync interface endpoint as shown below.

Single VPC connectivity to AppSync Private APIs

Figure 2: Single VPC connectivity to AppSync Private APIs

The API consumers and the interface endpoint are assigned private IP addresses within the CIDR range of the VPC. By default, every route table contains a local route for communication within the VPC CIDR. The interface VPC endpoint DNS name and AppSync API GraphQL endpoint (with Private DNS name turned on) will resolve to the private IP address of the AWS AppSync interface endpoint. This will ensure that requests to the private API is routed to the AppSync Private API via the interface endpoint.

Pattern 2: Cross VPC connectivity to AppSync Private APIs
In this pattern, the API consumer is hosted in a separate VPC from the VPC hosting the AppSync VPC interface endpoint within the same AWS Account, with both VPCs in the same or different AWS regions. You can use this pattern to centralize access to your AppSync Private APIs via a single VPC which can help simplify the security and access requirements to the API. However, it is important to compare centralized versus decentralized interface endpoint design from a cost and security perspective as discussed in this re:Invent talk, VPC endpoints & PrivateLink: Optimize for security, cost & operations.

Cross VPC connectivity to AppSync Private APIs

Figure 3: Cross VPC connectivity to AppSync Private APIs

To get started with this pattern, create the AppSync interface endpoint in one VPC (centralized VPC) and connect the two VPCs using VPC Peering Connection or AWS Transit Gateway as shown in the figure above. This will ensure that API consumers in VPC A can reach the AppSync interface endpoint in VPC B.

If you are using the AppSync interface endpoint DNS name to invoke the AppSync Private API, API consumers in VPC A can reach the Private API via the AppSync interface VPC endpoint in VPC B without any additional configuration.

Invoking the Private API with AppSync API GraphQL endpoint requires the following configurations:

  • Turn off ‘Private DNS names’ in VPC B. This will remove the DNS entry that resolves requests to the AppSync service domain name to the private IP addresses of elastic network interfaces (ENI) created by the AppSync interface endpoint.
  • Create Amazon Route 53 Private Hosted Zone (PHZ) with the domain set to the AppSync service domain appsync-api.{region}.amazonaws.com where region is set to the region of VPC B hosting the AppSync interface endpoint. While creating the PHZ, associate VPC A and VPC B with the hosted zone, you can select any VPC in any region within the AWS Account. Associating a VPC to the PHZ will ensure that any request to the AppSync service domain is resolved using DNS entries in the PHZ.

Create Private Hosted Zone

Figure 4: Create Private Hosted Zone

  • Once the PHZ is created, create an alias DNS record with the name set to the AppSync API GraphQL endpoint Identifier ( {api_url_identifier}.appsync-api.{region}.amazonaws.com/graphql) and target set to the AppSync interface endpoint as shown below. With these settings, the AppSync Private API can be invoked from either VPC A or VPC B using the AppSync API GraphQL endpoint.

Create hosted zone DNS records

Figure 5: Create hosted zone DNS records

Pattern 3: Cross Account connectivity to AppSync Private APIs
In this pattern, the API consumers are hosted in a different AWS account (Account A) from the AWS account hosting the AWS AppSync interface endpoint (Account B), with both VPCs in the same or different AWS regions. This is the use case where you separate your workloads into different AWS accounts with one account dedicated as the API account (Account B). Requests to AppSync Private APIs will have to be routed via the AppSync interface endpoint in the API account to the AppSync service.

Cross Account connectivity to AppSync Private APIs

Figure 6: Cross Account connectivity to AppSync Private APIs

Similar to Pattern 2, create an AppSync interface VPC endpoint in one of the AWS accounts and then connect the two VPCs using VPC Peering Connection or AWS Transit Gateway as shown in the figure above. This will ensure that API consumers in VPC A can reach the AppSync interface endpoint in VPC B.

Invoking the API using AppSync interface endpoint DNS name, API consumers in VPC A will reach the Private API without any additional configuration. However, if you are using the AppSync API GraphQL endpoint, you will need to follow the steps explained in Pattern 2 above. The only difference is on VPC association with the PHZ, which can only be done via the CLI or SDK. Below are the steps you will need to go through in a CLI (for example CloudShell) to associate VPC A to the PHZ.

  1. Open a CloudShell terminal in Account B in the same region as the VPC hosing the AppSync interface endpoint and run the following command to list the available hosted zone. Note the hosted zone ID in Account B that you want to associate with Account A.
    $ aws route53 list-hosted-zones
  2. Run the following command in the CloudShell terminal in the same region as VPC B in Account B. This command authorizes the association between the PHZ in Account B and the VPC in Account A. Use the hosted zone ID from pervious step, AWS region and ID of the VPC in Account A.
    $ aws route53 create-vpc-association-authorization --hosted-zone-id [hosted-zone-id] --vpc VPCRegion=[region],VPCId=[vpc-id]
  3. Open CloudShell terminal in Account A and run the following command. This command creates the association between the PHZ in Account B and the VPC in Account A. Use the hosted zone ID from step 1, region and VPC ID of VPC A in Account A.
    $ aws route53 associate-vpc-with-hosted-zone --hosted-zone-id [hosted-zone-id] --vpc VPCRegion=[region],VPCId=[vpc-id]
  4. It might take a couple of minutes for the PHZ to be associated with the VPC and for changes to propagate. It is also recommended to delete association after you create the association using this command.
    $ aws route53 delete-vpc-association-authorization --hosted-zone-id [hosted-zone-id]  --vpc VPCRegion=[region],VPCId=[vpc-id]
  5. Within Route 53 console in Account B, select the PHZ and verify the VPC ID of Account A is associated with the PHZ

After associating VPC A with the PHZ, create the alias DNS record as explained in Step 3 in Pattern 2 which will complete the configuration. You can now invoke the Private API on AppSync from either VPC A or VPC B using the AppSync API GraphQL endpoint.

Pattern 4: Hybrid connectivity to AppSync Private APIs
In this architecture, a hybrid architecture is in place, with the API consumers hosted on-premises. For example, these can be applications that are yet to be migrated over to AWS or applications that will need to remain on-premises due to regulatory or compliance requirements.

Hybrid connectivity to AppSync Private APIs

Figure 7 Hybrid connectivity to AppSync Private APIs

This architecture pattern will require a hybrid connectivity between AWS and the on-premises site. See the documentation on building hybrid connectivity using AWS Virtual Private Network (VPN) or AWS Direct Connect. Once network connectivity is established between an AWS VPC and the hybrid network, carry out the following configuration for API consumers to invoke AppSync Private API using either AppSync interface VPC endpoint DNS or AppSync GraphQL endpoint:

  • Ensure ‘Private DNS names’ is turned on for the AppSync interface endpoint. This will ensure requests to the AppSync GraphQL endpoint is routed to the AppSync Private API via the AppSync interface endpoint
  • Create Amazon Route 53 Resolver Inbound Endpoint for the VPC hosting the AppSync interface endpoint. You can follow the documentation for a step by step guide on how to create the inbound endpoint. You will need to:
    • Specify a name for the resolver inbound endpoint
    • Specify the VPC to deploy the resolver inbound endpoints
    • Provide the security group that will be used for the endpoints
    • Specify two or more availability zones and subnets from where IP addresses will be allocated to the resolver inbound endpoint for DNS queries

Configure Route 53 resolver for inbound-endpoints

Figure 8: Configure Route 53 resolver for inbound-endpoints

  • In the on-premises environment, update the DNS server to forward requests to the AppSync interface endpoint DNS (appsync-api.{region}.vpce.amazonaws.com) and AppSync service domain name (appsync-api.{region}.amazonaws.com) to the Resolver Inbound Endpoint IP addresses. With these settings, GraphQL requests from API consumers in the on-premises environment will reach the AppSync interface endpoint.

Pattern 5: Proxy AppSync Private APIs with API Gateway
This pattern addresses uses cases where the functionalities of Amazon API Gateway is used to control access to AppSync Private APIs. API Gateway will serve as a proxy, forwarding GraphQL request to the AppSync Private API.

Note:

  1. This architecture pattern should only be used with an AppSync Private API. If your AppSync API has a public endpoint, setup API Gateway API integration (with HTTP integration type) to proxy requests to the AppSync GraphQL endpoint.
  2. GraphQL subscription is not supported on the AppSync API with this architecture pattern.

Proxy AppSync Private APIs with API Gateway

Figure 9 Proxy AppSync Private APIs with API Gateway

In this pattern the AppSync Private API is exposed via a network load balancer and then proxied to API Gateway via a VPC Link. A VPC link acts like any other integration endpoint for an API and is an abstraction layer on top of other networking resources. The following four steps configure this architecture:

  1. Create your private API on AppSync and deploy the AWS AppSync Interface Endpoints on the target subnets.
  2. Create a Network Load Balancer with the targets set as the IP addresses of the AWS AppSync Interface Endpoint.
  3. Create the VPC Link, REST API and the Private Integration using the Network Load Balancer as the target service (refer to the guidance here on how to create these resources).
  4. You can set up your API on API Gateway to be either a Private, Regional or Edge-optimzed API. In this architecture diagram above, we have shown the setup for a Regional API on API Gateway.

With this setup, API consumers with access to the API Gateway endpoint will be able to invoke the private API on AppSync. You can deploy a sample CDK app on github that will create a regional API Gateway endpoint with a sample AppSync Private API you can use to test the setup.

Invoking GraphQL Operations (Queries, Mutations and Subscriptions) on AppSync Private APIs
There are two ways to invoke an AppSync Private API:

  • Using AppSync GraphQL endpoint (this is generated by AppSync) with the format
    https://{api_url_identifier}.appsync-api.{region}.amazonaws.com/graphql
  • Using AppSync interface endpoint DNS (this is generated for the AppSync interface endpoint with the format
    https://{vpc_endpoint_id}-{endpoint_dns_identifier}.appsync-api.{region}.vpce.amazonaws.com/graphql

Using AppSync GraphQL endpoint is recommended for customers that want to maintain the same application configuration for invoking Private APIs and non Private APIs. However, if there are use cases where API consumers will need to invoke both Private API and non Private API from a VPC, you will need to configure AppSync Custom Domain on the non Private API and use the custom domain to invoke the non Private API. This is because the Interface Endpoint for AWS AppSync with Private DNS turned on will route all traffic to the target *.appsync-api.{region}.amazonaws.com/graphql via the Interface Endpoint for AWS AppSync which will blocked for non Private APIs.

With AppSync interface endpoint DNS, API consumers can be configured to invoke AppSync Private APIs which will route traffic via the interface endpoint. When using the AppSync interface endpoint DNS you can turn off “Private DNS name” on the interface endpoint. API consumers can invoke other non AppSync Private APIs using the API AppSync GraphQL endpoint, no need to configure AppSync Custom Domain.

To invoke your Private API for queries and mutations using the the AppSync GraphQL endpoint, see the sample below

$ curl -v https://{api_url_identifier}.appsync-api.{region}.amazonaws.com/graphql \ 
-H "Content-Type:application/graphql" \ 
-H "x-api-key:da2-{xxxxxxxxxxxxxxxxxxxxxxxxxx}" \ 
-d '{"query": "query listTodos {listTodos {items {id title description priority}}}","variables":"{}"}'

and you can setup subscription with the GraphQL real-time endpoint, for example the command below with establish a websocket connection:

$ header=`echo '{"host":"{api_url_identifier}.appsync-api.{region}.amazonaws.com","x-api-key":"da2-{xxxxxxxxxxxxxxxxxxxxxxxxxx}"}' | base64 -w0`
$ wscat -p 13 -s graphql-ws -c "wss://{api_url_identifier}.appsync-realtime-api.{region}.amazonaws.com/graphql?header=$header&payload=e30="

The example below shows how you can invoke your Private API for queries and mutations with AppSync interface endpoint DNS. You will need to set the AppSync GraphQL endpoint as Host or x-appsync-domain header to the request.

$ curl -v https://{vpc_endpoint_id}-{endpoint_dns_identifier}.appsync-api.{region}.vpce.amazonaws.com/graphql \
-H "Content-Type:application/graphql" \
-H "x-api-key:da2-{xxxxxxxxxxxxxxxxxxxxxxxxxx}" \
-H "Host:{api_url_identifier}.appsync-api.{region}.amazonaws.com" \
-d '{"query": "query listTodos {listTodos {items {id title description priority}}}","variables":"{}"}'

and you can setup subscription with the AppSync interface endpoint DNS as shown in the example below,

$ header=`echo '{"host":"{api_url_identifier}.appsync-api.{region}.amazonaws.com","x-api-key":"da2-{xxxxxxxxxxxxxxxxxxxxxxxxxx}"}' | base64 -w0`
$ wscat -H "X-AppSync-Domain:{api_url_identifier}.appsync-realtime-api.{region}.amazonaws.com" -p 13 -s graphql-ws -c "wss://{vpc_endpoint_id}-{endpoint_dns_identifier}.appsync-api.{region}.vpce.amazonaws.com/graphql?header=$header&payload=e30="

Conclusion

In this blog, we covered five architecture patterns for accessing your AWS AppSync Private API. These patterns will help you identify the architecture and configuration for API consumers to securely access your private API. You can also combine two or more of these architecture patterns into one single architecture to cater to API consumers in different locations. For further details refer to Using AWS AppSync Private APIs in the AWS AppSync Documentation.

About the authors

Ozioma Uzoegwu

Ozioma is a Principal Solutions Architect at Amazon Web Services. In his role, he helps customers of all sizes to transform and modernise on AWS cloud platform by providing architectural guidance and best practices. Ozioma has many years of experience with web development, architecture, cloud and IT management. Prior to joining AWS, Ozioma worked with an AWS Advanced Consulting Partner as the Lead Architect for the AWS Practice. He is passionate about software development with a keen interest in building modern applications using serverless technologies.

Kirankumar Chandrashekar

Kirankumar is a Sr. Solutions Architect for Strategic Accounts at AWS. He focuses on leading customers in architecting DevOps, modernization using serverless, containers and container orchestration technologies like Docker, ECS, EKS to name a few. Kirankumar is passionate about DevOps, Infrastructure as Code, modernization and solving complex customer issues. He enjoys music, as well as cooking and traveling.