Skip to content

Commit

Permalink
Merge pull request #2523 from usama-khan98/usama-khan98-feature-priva…
Browse files Browse the repository at this point in the history
…te-apigw-custom-domain

New serverless pattern - Private Api Gateway Custom Domain Name
  • Loading branch information
julianwood authored Jan 6, 2025
2 parents 8f4d800 + a31dad1 commit a4508b8
Show file tree
Hide file tree
Showing 4 changed files with 326 additions and 0 deletions.
61 changes: 61 additions & 0 deletions private-apigw-custom-domain/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Private Amazon API Gateway with private custom domain name

The AWS SAM template deploys a private Amazon API Gateway with a private custom domain name mapped to deployed stage. This template also create a Amazon Route53 A-Alias record in a private hosted zone to map the private custom domain name (e.g. `private.mydomain.com`) to the target VPC Endpoint DNS name. (e.g. `vpce-abcdefgh123456789-abcd1234.execute-api.us-east-1.vpce.amazonaws.com`).

Learn more about this pattern at [Serverless Land Patterns](https://serverlessland.com/patterns/private-apigw-custom-domain)

## Requirements

* An [AWS account](https://signin.aws.amazon.com/signup?request_type=register) with an IAM user or role that has sufficient permissions to make the necessary AWS service calls and manage AWS resources.
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured.
* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git).
* [AWS Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) (AWS SAM) installed.
* An [execute-api VPC Endpoint](https://docs.aws.amazon.com/vpc/latest/privatelink/interface-endpoints.html).
* A Route 53 [Private Hosted Zone](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/hosted-zones-private.html). (*You can also use Public Hosted Zone but it is recommnded to use Private Hosted Zone to make sure that the Domain Name is only resolvable from within the VPC*)
* An SSL/TLS certificate in [AWS Certificate Manager](https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-specify-certificate-for-custom-domain-name.html#how-to-specify-certificate-for-custom-domain-name-setup).

## Deployment Instructions

1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository:
```bash
git clone https://github.com/aws-samples/serverless-patterns
```
2. Change directory to the pattern directory:
```bash
cd serverless-patterns/private-apigw-custom-domain
```
3. From the command line, use AWS SAM to deploy the AWS resources for the pattern as specified in the template.yml file:
```bash
sam deploy --guided
```
4. During the prompts:
- Enter **stack name** and desired **AWS Region**.
- Enter **DNS Name** of the **execute-api** VPC endpoint for the VpcEndpointDNSName parameter. (e.g. vpce-abcdefgh123456789-abcd1234.execute-api.us-east-1.vpce.amazonaws.com)
- Enter **Hosted Zone ID** of the **execute-api** VPC endpoint for the VPCEndpointHostedZoneID parameter. (This can be found along with the DNS Name of the VPC endpoing on the AWS Console.)
- Enter **Private Custom Domain Name** (e.g. private.mydomain.com) for the CustomDomainName parameter.
- Enter **ACM Certificate ARN** from the same region as Private Amazon API Gateway for the CertificateArn parameter. The certificate must cover the Private Custom Domain name entered in the previous step.
- Enter **Private Hosted Zone ID** that has the domain name you would like to use for the parameter PrivateHostedZoneId.
- Allow SAM to create roles with the required permissions if needed.

Once you have run guided mode once, you can use `sam deploy` in future to use these defaults.

1. Note the outputs from the SAM deployment process. This contain the curl command to test the Private Custom Domain Name.

## Testing

The stack will output the **Private Custom Domain Name**. You can use `curl` to send a HTTP request to the Private Custom Domain endpoint to test the correct mapping to your API.

```bash
curl https://{PrivateCustomDomainName}/
```

## Cleanup

1. Delete the stack
```bash
sam delete
```
1. Confirm the stack has been deleted
```bash
aws cloudformation list-stacks --query "StackSummaries[?contains(StackName,'STACK_NAME')].StackStatus"
```
58 changes: 58 additions & 0 deletions private-apigw-custom-domain/example-pattern.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"title": "Private Amazon API Gateway with private custom domain name",
"description": "Create a Private API Gateway with a private custom domain name, configure access based on VPC endpoint, and set up DNS routing using Amazon Route 53 private hosted zone.",
"language": "",
"level": "200",
"framework": "SAM",
"introBox": {
"headline": "How it works",
"text": [
"This AWS SAM template demonstrates how to create a private Amazon API Gateway with a private custom domain mame, configure secure access based on a specific VPC endpoint, and route traffic through Route 53 in a private hosted zone.",
"Private custom domain name is only accessible from a VPC endpoint, which is mapped to a stage in private Amazon API Gateway. A custom domain name is configured with an SSL/TLS certificate to provide secure access, and an associated Route 53 A-Alias record ensures that traffic is routed to the API.",
"As prerequisites for this pattern, you must have:"
"* A DNS name of execute-api VPC endpoint",
"* A custom domain name that you would like to create (e.g. private.mydomain.com)",
"* A valid certificate in ACM (Amazon Certificate Manager) in the same Region as Private Amazon API Gateway, that covers the namespace of the domain you would like to use (i.e. *.mydomain.com).",
"* A Route 53 Private Hosted Zone ID that has the domain name you would like to use (e.g. mydomain.com).",
]
},
"gitHub": {
"template": {
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/private-apigw-custom-domain",
"templateURL": "serverless-patterns/private-apigw-custom-domain",
"projectFolder": "private-apigw-custom-domain",
"templateFile": "template.yaml"
}
},
"resources": {
"bullets": [
{
"text": "Custom domain names for private APIs in API Gateway",
"link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-private-custom-domains.html"
}
]
},
"deploy": {
"text": [
"Deploy the stack: <code>sam deploy --guided</code>
]
},
"testing": {
"text": [
"See the GitHub repo for detailed testing instructions."
]
},
"cleanup": {
"text": [
"Delete the stack: <code>sam delete</code>."
]
},
"authors": [
{
"name": "Usama Ali Khan",
"image": "https://media.licdn.com/dms/image/v2/D4E03AQHcLMpZ1LV9UQ/profile-displayphoto-shrink_800_800/profile-displayphoto-shrink_800_800/0/1685892371158?e=1737590400&v=beta&t=RaPZkIgm7m3thW4PyKSQNn_w9fMbYBeu5PPrQ6K4vBU",
"bio": "Usama is a Technical Account Manager at Amazon Web Services.",
"linkedin": "usama-ali-khan"
}
]
}
95 changes: 95 additions & 0 deletions private-apigw-custom-domain/pattern.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
{
"title": "Private Amazon API Gateway with private custom domain name",
"description": "Create a Private API Gateway with a custom domain. Configure access via VPC endpoint and set up DNS routing with Amazon Route 53 private hosted zone.",
"language": "",
"level": "200",
"framework": "SAM",
"introBox": {
"headline": "How it works",
"text": [
"This AWS SAM template demonstrates how to create a private Amazon API Gateway with a private custom domain mame, configure secure access based on a specific VPC endpoint, and route traffic through Route 53 in a private hosted zone.",
"Private custom domain name is only accessible from a VPC endpoint, which is mapped to a stage in private Amazon API Gateway. A custom domain name is configured with an SSL/TLS certificate to provide secure access, and an associated Route 53 A-Alias record ensures that traffic is routed to the API.",
"As prerequisites for this pattern, you must have:",
"* A DNS name of execute-api VPC endpoint",
"* A custom domain name that you would like to create (e.g. private.mydomain.com)",
"* A valid certificate in ACM (Amazon Certificate Manager) in the same Region as Private Amazon API Gateway, that covers the namespace of the domain you would like to use (i.e. *.mydomain.com).",
"* A Route 53 Private Hosted Zone ID that has the domain name you would like to use (e.g. mydomain.com)."
]
},
"gitHub": {
"template": {
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/private-apigw-custom-domain",
"templateURL": "serverless-patterns/private-apigw-custom-domain",
"projectFolder": "private-apigw-custom-domain",
"templateFile": "template.yaml"
}
},
"resources": {
"bullets": [
{
"text": "Custom domain names for private APIs in API Gateway",
"link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-private-custom-domains.html"
}
]
},
"deploy": {
"text": ["Deploy the stack: <code>sam deploy --guided</code>"]
},
"testing": {
"text": ["See the GitHub repo for detailed testing instructions."]
},
"cleanup": {
"text": ["Delete the stack: <code>sam delete</code>."]
},
"authors": [
{
"name": "Usama Ali Khan",
"image": "https://media.licdn.com/dms/image/v2/D4E03AQHcLMpZ1LV9UQ/profile-displayphoto-shrink_800_800/profile-displayphoto-shrink_800_800/0/1685892371158?e=1737590400&v=beta&t=RaPZkIgm7m3thW4PyKSQNn_w9fMbYBeu5PPrQ6K4vBU",
"bio": "Usama is a Technical Account Manager at Amazon Web Services.",
"linkedin": "usama-ali-khan"
}
],
"patternArch": {
"icon1": {
"x": 20,
"y": 50,
"service": "route53",
"label": "Amazon Route 53"
},
"icon2": {
"x": 50,
"y": 50,
"service": "apigw",
"label": "Amazon API Gateway"
},
"icon3": {
"x": 80,
"y": 50,
"service": "vpc-endpoint",
"label": "VPC Endpoint"
},
"icon4": {
"x": 20,
"y": 58,
"service": "",
"label": "private hosted zone"
},
"icon5": {
"x": 50,
"y": 58,
"service": "",
"label": "(private)"
},

"line1": {
"from": "icon1",
"to": "icon2",
"label": ""
},
"line2": {
"from": "icon2",
"to": "icon3",
"label": ""
}
}
}
112 changes: 112 additions & 0 deletions private-apigw-custom-domain/template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
Serverless patterns - Amazon Private API Gateway endpoint with Private Custom Domain Name
Parameters:
VpcEndpointDNSName:
Type: String
VPCEndpointHostedZoneID:
Type: String
CustomDomainName:
Type: String
CertificateArn:
Type: String
PrivateHostedZoneId:
Type: String

Resources:
PrivateApi:
Type: AWS::Serverless::Api
Properties:
EndpointConfiguration: PRIVATE
StageName: Prod
AlwaysDeploy: true
DefinitionBody:
openapi: "3.0.1"
info:
version: "1.0"
title: !Sub "PrivateApi-${AWS::StackName}"
paths:
/:
get:
responses:
"200":
description: "200 response"
content:
application/json:
schema:
$ref: "#/components/schemas/Empty"
x-amazon-apigateway-integration:
type: "mock"
responses:
default:
statusCode: "200"
responseTemplates:
application/json: '{\"message\":\"Hello from Amazon Private API Gateway\"\}'
requestTemplates:
application/json: "{\"statusCode\": 200}"
passthroughBehavior: "when_no_match"
x-amazon-apigateway-policy:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal: "*"
Action: "execute-api:Invoke"
Resource: "execute-api:/*"
Condition:
StringEquals:
aws:sourceVpce: !Join ["-", [!Select [0, !Split ["-", !Select [0, !Split [".", !Ref VpcEndpointDNSName]]]], !Select [1, !Split ["-", !Select [0, !Split [".", !Ref VpcEndpointDNSName]]]]]]

PrivateDomainName:
Type: AWS::ApiGateway::DomainNameV2
Properties:
DomainName: !Ref CustomDomainName
CertificateArn: !Ref CertificateArn
EndpointConfiguration:
Types:
- PRIVATE
SecurityPolicy: TLS_1_2
Policy:
Statement:
- Action: 'execute-api:Invoke'
Effect: Allow
Principal: '*'
Resource: 'execute-api:/*'
- Action: 'execute-api:Invoke'
Condition:
StringNotEquals:
aws:SourceVpce : !Join ["-", [!Select [0, !Split ["-", !Select [0, !Split [".", !Ref VpcEndpointDNSName]]]], !Select [1, !Split ["-", !Select [0, !Split [".", !Ref VpcEndpointDNSName]]]]]]
Effect: Deny
Principal: '*'
Resource: 'execute-api:/*'
Version: 2012-10-17

BasePathMapping:
Type: AWS::ApiGateway::BasePathMappingV2
Properties:
RestApiId: !Ref PrivateApi
DomainNameArn: !GetAtt PrivateDomainName.DomainNameArn
Stage: !Ref PrivateApi.Stage

DomainNameAccessAssociation:
Type: AWS::ApiGateway::DomainNameAccessAssociation
Properties:
DomainNameArn: !GetAtt PrivateDomainName.DomainNameArn
AccessAssociationSource: !Join ["-", [!Select [0, !Split ["-", !Select [0, !Split [".", !Ref VpcEndpointDNSName]]]], !Select [1, !Split ["-", !Select [0, !Split [".", !Ref VpcEndpointDNSName]]]]]]
AccessAssociationSourceType: VPCE

R53Alias:
Type: AWS::Route53::RecordSet
Properties:
Name: !Ref CustomDomainName
HostedZoneId: !Ref PrivateHostedZoneId
Type: A
AliasTarget:
DNSName: !Ref VpcEndpointDNSName
HostedZoneId: !Ref VPCEndpointHostedZoneID

Outputs:
CURLCommand:
Description: "Curl Command to test"
Value: !Sub "curl https://${CustomDomainName}/"

0 comments on commit a4508b8

Please sign in to comment.