Skip to content

Commit 2f31472

Browse files
authored
Merge pull request #2541 from luketr03/luketr03-private-custom-domain-name-cross-account
NEW Serverless Pattern - Invoke a Private Custom Domain Name cross account
2 parents 1bda70c + 926084e commit 2f31472

File tree

4 files changed

+319
-0
lines changed

4 files changed

+319
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
Invoking a Private Custom Domain Name cross-account
2+
3+
## Architecture Overview
4+
5+
This architecture enables the invocation of a Private Custom Domain Name deployed for a Private API Gateway cross-account. The solution leverages [Amazon Private API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-private-apis.html), [Execute-API VPC Endpoint](https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html), and the Private Custom Domain N [Private Custom Domain name](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-private-custom-domains.html).
6+
7+
Learn more about this pattern at [Serverless Land Patterns](https://serverlessland.com/patterns/apigw-private-custom-domain-name-cross-account).
8+
9+
You can update the template to add AWS resources through the same deployment process that updates your application code.
10+
11+
Important: This application uses various AWS Services and there are costs associated with these services after the Free Tier Usage - please see the [AWS Pricing Page](https://aws.amazon.com/pricing/) for more details. You are responsible for any AWS costs incurred. No warranty is implied in this example.
12+
13+
### Requirements
14+
15+
- Two [AWS accounts](https://signin.aws.amazon.com/signup?request_type=register). IAM users or roles with sufficient permissions to make the necessary AWS service calls and manage AWS resources.
16+
- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) installed and configured.
17+
- [AWS Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) (AWS SAM) installed.
18+
- Setup .aws/credentials [named profiles](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html) namely **accountA** and **accountB** so you can run CLI and AWS SAM commands against them.
19+
- An [Amazon Execute-API VPC Endpoint](https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html) needed to invoke your private custom domain name.
20+
- A [Public ACM Certificate issued](https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-request-public.html) so that API Gateway can prove its identity to clients establishing secure HTTPS connections
21+
22+
### How it works
23+
24+
This pattern utilizes two AWS Sccounts and their respective templates.
25+
26+
1. **Account A** : Hosts the Private API Gateway and the Private Custom Domain Name:
27+
- **Amazon API Gateway (Private)**: Receives requests from the Account B via the Execute VPC Endpoint deployed in Account B
28+
- **Custom Domain Name** which is hit by the client in Account B to invoke the API Gateway
29+
- The **Custom Domain Name** is then shared with Account B via AWS Resource Access Manager (AWS RAM)
30+
31+
2. **Account B** : Hosts the Private Hosted Zone, the Execute API VPC Endpoint and creates the Domain Name Access association. A client in the VPC where the VPC Endpoint is deployed can then send requests to the Private API Gateway in Account A using the Custom Domain Name
32+
33+
34+
### Deployment Instructions
35+
36+
**Note**: Please make sure to follow the below steps in order to make sure the deployment is successful.
37+
38+
1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository:
39+
``` bash
40+
git clone https://github.com/aws-samples/serverless-patterns
41+
```
42+
2. Change directory to the pattern directory:
43+
```bash
44+
cd serverless-patterns/apigw-private-custom-domain-name-cross-account
45+
```
46+
47+
#### AccountA
48+
49+
1. In account A, where you would like to create **Private API Gateway**, along with its Private Custom Domain Name, navigate to the `accountA` directory from the main directory and deploy using *(if you are in a different directory, then run `cd ..` before entering the below command)*:
50+
```bash
51+
cd accountA
52+
53+
sam deploy --guided --profile accountA
54+
55+
2. During the prompts:
56+
- Enter **stack name** and desired **AWS Region**.
57+
- Enter **the AccountB VPC Endpoint**.
58+
- Enter **the AWS ACM Certificate ARN**.
59+
- Enter the **Custom Domain Name** which is covered by the aforementioned certificate.
60+
- Enter the **AccountB ID**. This will be used to share the Custom Domain Name resource with.
61+
- Allow SAM CLI to create IAM roles with the required permissions.
62+
3. Note the outputs from the SAM deployment process. This contains both the `Custom Domain Name` and `Custom Domain Name ARN`, which will be used as inputs for the second account's stack deployment.
63+
64+
#### Accept the Resource Share Invitation
65+
Upon deploying the first template, you can get the invitation ARN from the AWS CLI by running the following command:
66+
```
67+
aws ram get-resource-share-invitations --profile <target-account-profile>
68+
```
69+
70+
Copy the invitation ARN, and paste it in the following command:
71+
```
72+
aws ram accept-resource-share-invitation \
73+
--resource-share-invitation-arn arn:aws:ram:region:account-id:resource-share-invitation/invitation-id \
74+
--profile <target-account-profile>
75+
```
76+
77+
#### AccountB
78+
1. In account B, where you would like to create the **Custom Domain Name Access Association** and the **Private Hosted Zone**, navigate to the `accountB` directory from the main directory and deploy using *(if you are in a different directory, then run `cd ..` before entering the below command)*:
79+
```bash
80+
cd accountB
81+
82+
sam deploy --guided --profile accountB
83+
```
84+
2. During the prompts:
85+
- Enter **stack name** and desired **AWS Region**.
86+
- Enter the **VPC ID** where the Hosted Zone will be created
87+
- Enter the **VPC Endpoint DNS Name**. It will be used to create the Alias record in the Private Hosted Zone
88+
- Enter the **Custom Domain Name** created in the first template
89+
- Enter the **Custom Domain Name ARN** created in the first template
90+
- Enter the **VPC Endpoint Hosted Zone ID**
91+
- Allow SAM CLI to create IAM roles with the required permissions.
92+
93+
94+
## Cleanup
95+
To avoid incurring future charges, it's important to delete the resources in the correcct order. Follow these steps to clean up the resources created by the four templates *(Make sure to navigate to the directory containing the template before running the below commands)*:
96+
97+
1. Delete Account A template
98+
```bash
99+
sam delete --stack-name STACK_NAME --profile PROFILE_NAME
100+
```
101+
2. Delete Account B template
102+
```bash
103+
sam delete --stack-name STACK_NAME_ACCOUNT_B --profile accountB
104+
```
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Transform: AWS::Serverless-2016-10-31
3+
Description: >
4+
Serverless patterns - Amazon Private API Gateway endpoint with Private Custom Domain Name
5+
6+
Parameters:
7+
VpcEndpoint:
8+
Type: String
9+
CustomDomainName:
10+
Type: String
11+
CertificateArn:
12+
Type: String
13+
TargetAccountID:
14+
Type: String
15+
16+
Resources:
17+
PrivateApi:
18+
Type: AWS::Serverless::Api
19+
Properties:
20+
EndpointConfiguration: PRIVATE
21+
StageName: Prod
22+
AlwaysDeploy: true
23+
DefinitionBody:
24+
openapi: "3.0.1"
25+
info:
26+
version: "1.0"
27+
title: !Sub "PrivateApi-${AWS::StackName}"
28+
paths:
29+
/:
30+
get:
31+
responses:
32+
"200":
33+
description: "200 response"
34+
content:
35+
application/json:
36+
schema:
37+
$ref: "#/components/schemas/Empty"
38+
x-amazon-apigateway-integration:
39+
type: "mock"
40+
responses:
41+
default:
42+
statusCode: "200"
43+
responseTemplates:
44+
application/json: '{\"message\":\"Hello from Amazon Private API Gateway\"\}'
45+
requestTemplates:
46+
application/json: "{\"statusCode\": 200}"
47+
passthroughBehavior: "when_no_match"
48+
x-amazon-apigateway-policy:
49+
Version: "2012-10-17"
50+
Statement:
51+
- Effect: "Allow"
52+
Principal: "*"
53+
Action: "execute-api:Invoke"
54+
Resource: "execute-api:/*"
55+
Condition:
56+
StringEquals:
57+
aws:sourceVpce: !Ref VpcEndpoint
58+
59+
PrivateDomainName:
60+
Type: AWS::ApiGateway::DomainNameV2
61+
Properties:
62+
DomainName: !Ref CustomDomainName
63+
CertificateArn: !Ref CertificateArn
64+
EndpointConfiguration:
65+
Types:
66+
- PRIVATE
67+
SecurityPolicy: TLS_1_2
68+
Policy:
69+
Statement:
70+
- Action: 'execute-api:Invoke'
71+
Effect: Allow
72+
Principal: '*'
73+
Resource: 'execute-api:/*'
74+
- Action: 'execute-api:Invoke'
75+
Condition:
76+
StringNotEquals:
77+
aws:SourceVpce : !Ref VpcEndpoint
78+
Effect: Deny
79+
Principal: '*'
80+
Resource: 'execute-api:/*'
81+
Version: '2012-10-17'
82+
83+
BasePathMapping:
84+
Type: AWS::ApiGateway::BasePathMappingV2
85+
Properties:
86+
RestApiId: !Ref PrivateApi
87+
DomainNameArn: !GetAtt PrivateDomainName.DomainNameArn
88+
Stage: !Ref PrivateApi.Stage
89+
90+
ResourceShare:
91+
Type: "AWS::RAM::ResourceShare"
92+
Properties:
93+
Name: "Private Domain Name"
94+
ResourceArns:
95+
- !GetAtt PrivateDomainName.DomainNameArn
96+
Principals:
97+
- !Ref TargetAccountID
98+
99+
Outputs:
100+
CustomDomainName:
101+
Description: "Custom Domain Name"
102+
Value: !Ref CustomDomainName
103+
104+
CustomDomainNameArn:
105+
Description: "Custom Domain Name Arn"
106+
Value: !GetAtt PrivateDomainName.DomainNameArn
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Transform: AWS::Serverless-2016-10-31
3+
Description: >
4+
todo
5+
6+
Parameters:
7+
VPC:
8+
Type: AWS::EC2::VPC::Id
9+
Description: VPC where the hosted zone will be created
10+
11+
VpcEndpointDNSName:
12+
Type: String
13+
Description: DNS name of the VPC endpoint
14+
15+
CustomDomainName:
16+
Type: String
17+
Description: Domain name for the private hosted zone
18+
19+
CustomDomainNameARN:
20+
Type: String
21+
Description: Domain name ARN of the Private API Gateway
22+
23+
VpcEndpointHostedZoneId:
24+
Type: String
25+
Description: Hosted Zone ID of the VPC endpoint
26+
27+
Resources:
28+
PrivateHostedZone:
29+
Type: AWS::Route53::HostedZone
30+
Properties:
31+
Name: !Ref CustomDomainName
32+
VPCs:
33+
- VPCId: !Ref VPC
34+
VPCRegion: !Ref AWS::Region
35+
36+
DNSRecord:
37+
Type: AWS::Route53::RecordSet
38+
Properties:
39+
Name: !Ref CustomDomainName
40+
HostedZoneId: !Ref PrivateHostedZone
41+
Type: A
42+
AliasTarget:
43+
DNSName: !Ref VpcEndpointDNSName
44+
HostedZoneId: !Ref VpcEndpointHostedZoneId
45+
46+
DomainNameAccessAssociation:
47+
Type: AWS::ApiGateway::DomainNameAccessAssociation
48+
Properties:
49+
DomainNameArn: !Ref CustomDomainNameARN
50+
AccessAssociationSource: !Join ["-", [!Select [0, !Split ["-", !Select [0, !Split [".", !Ref VpcEndpointDNSName]]]], !Select [1, !Split ["-", !Select [0, !Split [".", !Ref VpcEndpointDNSName]]]]]]
51+
AccessAssociationSourceType: VPCE
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"title": "Cross Account Private Domain Name Access",
3+
"description": "Setting up Cross-Account Private API Gateway with Custom Domain",
4+
"language": "Python",
5+
"level": "300",
6+
"framework": "SAM",
7+
"introBox": {
8+
"headline": "How it works",
9+
"text": [
10+
"This pattern demonstrates how to implement cross-account access to a Private API Gateway using Custom Domain Names. Learn how to configure, deploy, and invoke private APIs across AWS accounts"
11+
]
12+
},
13+
"gitHub": {
14+
"template": {
15+
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/apigw-private-custom-domain-name-cross-account",
16+
"templateURL": "serverless-patterns/apigw-private-custom-domain-name-cross-account",
17+
"projectFolder": "apigw-private-custom-domain-name-cross-account",
18+
"templateFile": "accountA/template.yaml"
19+
}
20+
},
21+
"resources": {
22+
"bullets": [
23+
{
24+
"text": "Amazon Private API Gateway",
25+
"link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-private-apis.html"
26+
},
27+
{
28+
"text": "Execute-API VPC Endpoint",
29+
"link": "https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html"
30+
},
31+
{
32+
"text": "Private Custom Domain name",
33+
"link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-private-custom-domains.html"
34+
}
35+
]
36+
},
37+
"deploy": {
38+
"text": [
39+
"sam deploy"
40+
]
41+
},
42+
"testing": {
43+
"text": [
44+
"See the GitHub repo for detailed testing instructions."
45+
]
46+
},
47+
"cleanup": {
48+
"text": [
49+
"Delete the stack: <code>sam delete</code>."
50+
]
51+
},
52+
"authors": [
53+
{
54+
"name": "Luigi Napoleone Capasso",
55+
"bio": "Luigi Napoleone Capasso is a Technical Account Manager at Amazon Web Services."
56+
}
57+
]
58+
}

0 commit comments

Comments
 (0)