Using AWS AppSync Private APIs - AWS AppSync

Using AWS AppSync Private APIs

If you use Amazon Virtual Private Cloud (Amazon VPC), you can create AWS AppSync Private APIs, which are APIs that can only be accessed from a VPC. With a Private API, you can restrict API access to your internal applications and connect to your GraphQL and Realtime endpoints without exposing data publicly.

To establish a private connection between your VPC and the AWS AppSync service, you must create an interface VPC endpoint. Interface endpoints are powered by AWS PrivateLink, which enables you to privately access AWS AppSync APIs without an internet gateway, NAT device, VPN connection, or AWS Direct Connect connection. Instances in your VPC don't need public IP addresses to communicate with AWS AppSync APIs. Traffic between your VPC and AWS AppSync doesn't leave the AWS network.

There are some additional factors to consider before enabling Private API features:

  • Setting up VPC interface endpoints for AWS AppSync with Private DNS features enabled will prevent resources in the VPC from being able to invoke other AWS AppSync public APIs using the AWS AppSync generated API URL. This is due to the request to the public API being routed via the interface endpoint, which is not allowed for public APIs. To invoke public APIs in this scenario, it is recommended to configure custom domain names on public APIs, which can then be used by resources in the VPC to invoke the public API.

  • Your AWS AppSync Private APIs will only be available from your VPC. The AWS AppSync console Query editor will only be able to reach your API if your browser's network configuration can route traffic to your VPC (e.g., connection via VPN or over AWS Direct Connect).

  • With a VPC interface endpoint for AWS AppSync, you can access any Private API in the same AWS account and Region. To further restrict access to Private APIs, you can consider the following options:

    • Ensuring only the required administrators can create VPC endpoint interfaces for AWS AppSync.

    • Using VPC endpoint custom policies to restrict which APIs can be invoked from resources in the VPC.

    • For resources in the VPC, we recommend that you use IAM authorization to invoke AWS AppSync APIs by ensuring that the resources are given scoped-down roles to the APIs.

  • When creating or using policies that restrict IAM principals, you must set the authorizationType of the method to AWS_IAM or NONE.

Creating AWS AppSync Private APIs

The following steps below show you how to create Private APIs in the AWS AppSync service.

Warning

You can enable Private API features only during the creation of the API. This setting cannot be modified on an AWS AppSync API or an AWS AppSync Private API after it has been created.

  1. Sign in to the AWS Management Console and open the AppSync console.

    1. In the Dashboard, choose Create API.

  2. Choose Design an API from scratch, then choose Next.

  3. In the Private API section, choose Use Private API features.

  4. Configure the rest of the options, review your API's data, then choose Create.

Before you can use your AWS AppSync Private API, you must configure an interface endpoint for AWS AppSync in your VPC. Note that both the Private API and VPC must be in the same AWS account and Region.

Creating an interface endpoint for AWS AppSync

You can create an interface endpoint for AWS AppSync using either the Amazon VPC console or the AWS Command Line Interface (AWS CLI). For more information, see Creating an interface endpoint in the Amazon VPC User Guide.

Console
  1. Sign in to the AWS Management Console and open the Endpoints page of the Amazon VPC console.

  2. Choose Create endpoint.

    1. In the Service category field, verify that AWS services is selected.

    2. In the Services table, choose com.amazonaws.{region}.appsync-api. Verify that the Type column value is Interface.

    3. In the VPC field, choose a VPC and its subnets.

    4. To enable private DNS features for the interface endpoint, tick the Enable DNS Name check box.

    5. In the Security group field, choose one or more security groups.

  3. Choose Create endpoint.

CLI

Use the create-vpc-endpoint command and specify the VPC ID, VPC endpoint type (interface), service name, subnets that will use the endpoint, and security groups to associate with the endpoint's network interfaces. For example:

$ aws ec2 create-vpc-endpoint —vpc-id vpc-ec43eb89 \ —vpc-endpoint-type Interface \ —service-name com.amazonaws.{region}.appsync-api \ —subnet-id subnet-abababab —security-group-id sg-1a2b3c4d

To use the private DNS option, you must set the enableDnsHostnames and enableDnsSupportattributes values of your VPC. For more information, see Viewing and updating DNS support for your VPC in the Amazon VPC User Guide. If you enable private DNS features for the interface endpoint, you can make requests to your AWS AppSync API GraphQL and Real-time endpoint using its default public DNS endpoints using the format below:

https://{api_url_identifier}.appsync-api.{region}.amazonaws.com/graphql

For more information on service endpoints, see Service endpoints and quotas in the AWS General Reference.

For more information on service interactions with interface endpoints, see Accessing a service through an interface endpoint in the Amazon VPC User Guide.

For information about creating and configuring an endpoint using AWS CloudFormation, see the AWS::EC2::VPCEndpoint resource in the AWS CloudFormation User Guide.

Advanced examples

If you enable private DNS features for the interface endpoint, you can make requests to your AWS AppSync API GraphQL and Real-time endpoint using its default public DNS endpoints using the format below:

https://{api_url_identifier}.appsync-api.{region}.amazonaws.com/graphql

Using the interface VPC endpoint public DNS hostnames, the base URL to invoke the API will be in the following format:

https://{vpc_endpoint_id}-{endpoint_dns_identifier}.appsync-api.{region}.vpce.amazonaws.com/graphql

You can also use the AZ-specific DNS hostname if you have deployed an endpoint in the AZ:

https://{vpc_endpoint_id}-{endpoint_dns_identifier}-{az_id}.appsync-api.{region}.vpce.amazonaws.com/graphql.

Using the VPC endpoint public DNS name will require the AWS AppSync API endpoint hostname to be passed as Host or as a x-appsync-domain header to the request. These examples use a TodoAPI that was created in the Launch a sample schema guide:

curl 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":"mutation add($createtodoinput: CreateTodoInput!) {\n createTodo(input: $createtodoinput) {\n id\n name\n where\n when\n description\n }\n}","variables":{"createtodoinput":{"name":"My first GraphQL task","when":"Friday Night","where":"Day 1","description":"Learn more about GraphQL"}}}'

In the following examples, we will use the Todo app that is generated in the Launch a sample schema guide. To test out the sample Todo API, we will be using the Private DNS to invoke the API. You can use any command line tool of your choice; this example uses curl to send queries and mutations and wscat to set up subscriptions. To emulate our example, replace the values in brackets { } in the commands below with the corresponding values from your AWS account.

Testing Mutation Operation – createTodo Request

curl https://{api_url_identifier}.appsync-api.{region}.amazonaws.com/graphql \ -H "Content-Type:application/graphql" \ -H "x-api-key:da2-{xxxxxxxxxxxxxxxxxxxxxxxxxx}" \ -d '{"query":"mutation add($createtodoinput: CreateTodoInput!) {\n createTodo(input: $createtodoinput) {\n id\n name\n where\n when\n description\n }\n}","variables":{"createtodoinput":{"name":"My first GraphQL task","when":"Friday Night","where":"Day 1","description":"Learn more about GraphQL"}}}'

Testing Mutation Operation – createTodo Response

{ "data": { "createTodo": { "id": "<todo-id>", "name": "My first GraphQL task", "where": "Day 1", "when": "Friday Night", "description": "Learn more about GraphQL" } } }

Testing Query Operation – listTodos Request

curl 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 {\n listTodos {\n items {\n description\n id\n name\n when\n where\n }\n }\n}\n","variables":{"createtodoinput":{"name":"My first GraphQL task","when":"Friday Night","where":"Day 1","description":"Learn more about GraphQL"}}}'

Testing Query Operation – listTodos Request

{ "data": { "listTodos": { "items": [ { "description": "Learn more about GraphQL", "id": "<todo-id>", "name": "My first GraphQL task", "when": "Friday night", "where": "Day 1" } ] } } }

Testing Subscription Operation – Subscribing to createTodo mutation

To set up GraphQL subscriptions in AWS AppSync, see Building a real-time WebSocket client. From an Amazon EC2 instance in a VPC, you can test your AWS AppSync Private API subscription endpoint using wscat. The example below uses an API KEY for authorization.

$ header=`echo '{"host":"{api_url_identifier}.appsync-api.{region}.amazonaws.com","x-api-key":"da2-{xxxxxxxxxxxxxxxxxxxxxxxxxx}"}' | base64 | tr -d '\n'` $ wscat -p 13 -s graphql-ws -c "wss://{api_url_identifier}.appsync-realtime-api.us-west-2.amazonaws.com/graphql?header=$header&payload=e30=" Connected (press CTRL+C to quit) > {"type": "connection_init"} < {"type":"connection_ack","payload":{"connectionTimeoutMs":300000}} < {"type":"ka"} > {"id":"f7a49717","payload":{"data":"{\"query\":\"subscription onCreateTodo {onCreateTodo {description id name where when}}\",\"variables\":{}}","extensions":{"authorization":{"x-api-key":"da2-{xxxxxxxxxxxxxxxxxxxxxxxxxx}","host":"{api_url_identifier}.appsync-api.{region}.amazonaws.com"}}},"type":"start"} < {"id":"f7a49717","type":"start_ack"}

Alternatively, use the VPC endpoint domain name while making sure to specify the Host header in the wscat command to establish the websocket:

$ header=`echo '{"host":"{api_url_identifier}.appsync-api.{region}.amazonaws.com","x-api-key":"da2-{xxxxxxxxxxxxxxxxxxxxxxxxxx}"}' | base64 | tr -d '\n'` $ wscat -p 13 -s graphql-ws -c "wss://{vpc_endpoint_id}-{endpoint_dns_identifier}.appsync-api.{region}.vpce.amazonaws.com/graphql?header=$header&payload=e30=" --header Host:{api_url_identifier}.appsync-realtime-api.us-west-2.amazonaws.com Connected (press CTRL+C to quit) > {"type": "connection_init"} < {"type":"connection_ack","payload":{"connectionTimeoutMs":300000}} < {"type":"ka"} > {"id":"f7a49717","payload":{"data":"{\"query\":\"subscription onCreateTodo {onCreateTodo {description id priority title}}\",\"variables\":{}}","extensions":{"authorization":{"x-api-key":"da2-{xxxxxxxxxxxxxxxxxxxxxxxxxx}","host":"{api_url_identifier}.appsync-api.{region}.amazonaws.com"}}},"type":"start"} < {"id":"f7a49717","type":"start_ack"}

Run the mutation code below:

curl https://{api_url_identifier}.appsync-api.{region}.amazonaws.com/graphql \ -H "Content-Type:application/graphql" \ -H "x-api-key:da2-{xxxxxxxxxxxxxxxxxxxxxxxxxx}" \ -d '{"query":"mutation add($createtodoinput: CreateTodoInput!) {\n createTodo(input: $createtodoinput) {\n id\n name\n where\n when\n description\n }\n}","variables":{"createtodoinput":{"name":"My first GraphQL task","when":"Friday Night","where":"Day 1","description":"Learn more about GraphQL"}}}'

Afterwards, a subscription is trigged, and the message notification appears as shown below:

< {"id":"f7a49717","type":"data","payload":{"data":{"onCreateTodo":{"description":"Go to the shops","id":"169ce516-b7e8-4a6a-88c1-ab840184359f","priority":5,"title":"Go to the shops"}}}}

Using IAM policies to limit public API creation

AWS AppSync supports IAM Condition statements for use with Private APIs. The visibility field can be included with IAM policy statements for the appsync:CreateGraphqlApi operation to control which IAM roles and users can create private and public APIs. This gives an IAM administrator the ability to define an IAM policy that will only allow a user to create a Private GraphQL API. A user attempting to create a public API will receive an unauthorized message.

For example, an IAM administrator could create the following IAM policy statement to allow for the creation of Private APIs:

{ "Sid": "AllowPrivateAppSyncApis", "Effect": "Allow", "Action": "appsync:CreateGraphqlApi", "Resource": "*", "Condition": { "ForAnyValue:StringEquals": { "appsync:Visibility": "PRIVATE" } } }

An IAM administrator could also add the following service control policy to block all users in an AWS organization from creating AWS AppSync APIs other than Private APIs:

{ "Sid": "BlockNonPrivateAppSyncApis", "Effect": "Deny", "Action": "appsync:CreateGraphqlApi", "Resource": "*", "Condition": { "ForAnyValue:StringNotEquals": { "appsync:Visibility": "PRIVATE" } } }