deploying-custom-domain-rest-api
Deploys a Regional REST API with a custom domain name, a Lambda backend function, and a request-based Lambda authorizer using AWS CLI. Covers ACM certificate provisioning, API Gateway REST API creation, Lambda function deployment, request authorizer setup, custom domain configuration, base path mapp
By aws · 3,587 installs
npx skills add aws/agent-toolkit-for-aws --skill deploying-custom-domain-rest-api
Source repository · Upstream listing
Custom Domain REST API with Lambda and Request Authorizer
Overview
This SOP deploys a REST API with a Regional custom domain name, a Lambda backend function, and a request based Lambda authorizer. It handles ACM certificate provisioning, IAM role creation, Lambda function deployment, API Gateway REST API creation with a custom authorizer, custom domain configuration, base path mapping, and Route 53 DNS setup.
The architecture includes:
An API Gateway REST API with an endpoint type of REGIONAL
A request based Lambda authorizer that validates headers, query string parameters, and stage variables
A Lambda backend function at GET /example
A custom domain name with TLS 1.2
A base path mapping connecting the custom domain to the API stage
A Route 53 A alias record pointing the custom domain to the API Gateway Regional endpoint
Important: This SOP uses Regional endpoints. If the user requests a private endpoint, inform them that this skill covers Regional endpoints only. Private endpoints require VPC endpoint configuration.
Parameters
custom domain name (required): Fully qualified domain name for the API (e.g., api.example.com )
region (required): AWS Region for all resources. The ACM certificate must be in this same Region for Regional endpoints
hosted zone id (required): Route 53 hosted zone ID for the domain
acm certificate arn (optional): ARN of an existing ACM certificate covering the custom domain. If not provided, Step 2 creates one
stage name (optional, default: "dev"): API Gateway stage name
Constraints for parameter acquisition:
You MUST ask for all required parameters upfront in a single prompt rather than one at a time
You MUST support multiple input methods (direct input, file path, URL)
You MUST confirm successful acquisition of all parameters before proceeding
You MUST inform the user that this skill uses hardcoded demo authorization values (headerValue1, queryValue1, stageValue1) that are NOT suitable for production. For production, use AWS Secrets Manager or Systems Manager Parameter Store to manage authorization credentials. See: https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html
You MUST validate that custom domain name is a valid FQDN
Steps
0. Verify Dependencies
Constraints:
You MUST verify the following tools are available: aws cli, python3, sed, node (v22+)
You MUST inform the user about any missing tools with a clear message
You MUST ask if the user wants to proceed despite missing tools
You MUST respect the customer's decision to abort at any point
You MUST explain to the customer what step is being executed, why, and which tool is being called
1. Retrieve AWS Account ID
This step MUST be performed before all other steps.
Constraints:
You MUST retrieve the account ID with: aws sts get caller identity query 'Account' output text
You MUST store the result as {account id} and reuse it in all subsequent steps that reference {account id}
You MUST abort if credentials are not configured
2. Request ACM Certificate
Skip this step if acm certificate arn is already provided.
Constraints:
You MUST request the certificate with: aws acm request certificate domain name {custom domain name} validation method DNS region {region}
You MUST capture the CertificateArn from the response
You MUST retrieve the DNS validation record with: aws acm describe certificate certificate arn {cert arn} query 'Certificate.DomainValidationOptions[0].ResourceRecord' region {region}
You MUST create the validation CNAME in Route 53 with: aws route53 change resource record sets hosted zone id {hosted zone id} change batch '{"Changes":[{"Action":"UPSERT","ResourceRecordSet":{"Name":"{validation name}","Type":"CNAME","TTL":300,"ResourceRecords":[{"Value":"{validation value}"}]}}]}'
You MUST wait for certificate validation with: aws acm wait certificate validated certificate arn {cert arn} region {region}
The wait command may take up to 30 minutes. If it times out, check status manually with: aws acm describe certificate certificate arn {cert arn} query 'Certificate.Status' region {region} and retry the wait if status is still PENDING VALIDATION
You MUST NOT proceed until the certificate status is ISSUED
You MUST store the certificate ARN as acm certificate arn for use in Step 7
3. Create IAM Execution Roles
Constraints:
You MUST create two IAM roles: one for the authorizer Lambda and one for the example function Lambda
Both roles use the same trust policy from scripts/lambda trust policy.json . The trust policy includes an aws:SourceAccount condition scoped to the user's account ID
You MUST create a working copy of the trust policy and replace the ACCOUNT ID placeholder with the actual account ID from Step 1. Use: sed 's/ACCOUNT ID/{account id}/' scripts/lambda trust policy.json /tmp/lambda trust policy.json
You MUST create the authorizer role with: aws iam create role role name request authorizer role assume role policy document file:///tmp/lambda trust policy.json
You MUST attach the basic execution policy to the authorizer role with: aws iam attach role policy role name request authorizer role policy arn arn:aws:iam::aws:policy/service role/AWSLambdaBasicExecutionRole
You MUST create the example function role with: aws iam create role role name example function role assume role policy document file:///tmp/lambda trust policy.json
You MUST attach the basic execution policy to the example function role with: aws iam attach role policy role name example function role policy arn arn:aws:iam::aws:policy/service role/AWSLambdaBasicExecutionRole
You MUST capture the role ARNs from each create role response for use in Step 4
You MUST wait at least 10 seconds after role creation before creating Lambda functions because IAM role propagation is eventually consistent
4. Create and Deploy Lambda Functions
Constraints:
You MUST create two Lambda functions: the request authorizer and the example function
For the authorizer function:
You MUST create the function with inline code. First write the code to a file and package it:
python3 c "import zipfile,io,base64; z=io.BytesIO(); f=zipfile.ZipFile(z,'w'); f.writestr('index.mjs', open('scripts/authorizer.mjs').read()); f.close(); open('/tmp/authorizer.zip','wb').write(z.getvalue())"
Then create the function with: aws lambda create function function name request authorizer runtime nodejs22.x handler index.handler role {authorizer role arn} zip file fileb:///tmp/authorizer.zip timeout 10 region {region}
For the example function:
You MUST create the function with inline code. First write the code to a file and package it:
python3 c "import zipfile,io; z=io.BytesIO(); f=zipfile.ZipFile(z,'w'); f.writestr('index.mjs', open('scripts/example function.mjs').read()); f.close(); open('/tmp/example function.zip','wb').write(z.getvalue())"
Then create the function with: aws lambda create function function name example function runtime nodejs22.x handler index.handler role {example role arn} zip file fileb:///tmp/example function.zip timeout 10 region {region}
You MUST verify each function was created by calling: aws lambda get function function name {function name} region {region}
5. Create REST API with Request Authorizer
Constraints:
You MUST create the REST API with: aws apigateway create rest api name custom domain api endpoint configuration types=REGIONAL region {region}
You MUST capture the API id and get the root resource ID with: aws apigateway get resources rest api id {api id} region {region}
You MUST create the request based Lambda authorizer with: aws apigateway create authorizer rest api id {api id} name request authorizer type REQUEST authorizer uri 'arn:aws:apigateway:{region}:lambda:path/2015 03 31/functions/arn:aws:lambda:{region}:{account id}:function:request authorizer/invocations' identity source 'method.request.header.HeaderAuth1,method.request.querystring.QueryString1,context.stage' region {region}
You MUST capture the authorizer ID from the response
You MUST grant API Gateway permission to invoke the authorizer with: aws lambda add permission function name request authorizer statement id apigateway auth invoke action lambda:InvokeFunction principal apigateway.amazonaws.com source arn 'arn:aws:execute api:{region}:{account id}:{api id}/authorizers/{authorizer id}' region {region}
You MUST create the /example resource with: aws apigateway create resource rest api id {api id} parent id {root resource id} path part example region {region}
You MUST create the GET method with: aws apigateway put method rest api id {api id} resource id {example resource id} http method GET authorization type CUSTOM authorizer id {authorizer id} region {region}
You MUST create the Lambda proxy integration with: aws apigateway put integration rest api id {api id} resource id {example resource id} http method GET type AWS PROXY integration http method POST uri 'arn:aws:apigateway:{region}:lambda:path/2015 03 31/functions/arn:aws:lambda:{region}:{account id}:function:example function/invocations' region {region}
You MUST grant API Gateway permission to invoke the example function with: aws lambda add permission function name example function statement id apigateway invoke action lambda:InvokeFunction principal apigateway.amazonaws.com source arn 'arn:aws:execute api:{region}:{account id}:{api id}/ /GET/example' region {region}
You MUST NOT create the deployment until all resources, methods, and integrations are configured
You MUST configure request validation to reject malformed query parameters and headers by validating that QueryString1 and HeaderAuth1 match expected patterns and enforcing size limits
6. Deploy the API
Constraints:
You MUST create the deployment with: aws apigateway create deployment rest api id {api id} stage name {stage name} region {region}
You MUST set the stage variable required by the authorizer with: aws apigateway update stage rest api id {api id} stage name {stage name} patch operations op=replace,path=/variables/StageVar1,value=stageValue1 region {region}
You MUST verify the deployment and stage variable by calling: aws apigateway get stage rest api id {api id} stage name {stage name} region {region} and confirming StageVar1 is present in the variables
You MUST enable access logging on the stage. First create the log group: aws logs create log group log group name api gw access logs region {region} . Then enable logging with format: aws apigateway update stage rest api id {api id} stage name {stage name} patch operations op=replace,path=/accessLogSettings/destinationArn,value=arn:aws:logs:{region}:{account id}:log group:api gw access logs op=replace,path=/accessLogSettings/format,value='{"requestId":"$context.requestId","ip":"$context.identity.sourceIp","requestTime":"$context.requestTime","httpMethod":"$context.httpMethod","resourcePath":"$context.resourcePath","status":"$context.status"}' region {region}
7. Create Custom Domain and Base Path Mapping
Constraints:
You MUST create the custom domain with: aws apigateway create domain name domain name {custom domain name} regional certificate arn {acm certificate arn} endpoint configuration types=REGIONAL security policy TLS 1 2 region {region}
You MUST capture the regionalDomainName and regionalHostedZoneId from the response for use in Step 8
You MUST create the base path mapping with: aws apigateway create base path mapping domain name {custom domain name} rest api id {api id} stage {stage name} base path '(none)' region {region}
You MUST verify the domain was created by calling: aws apigateway get domain name domain name {custom domain name} region {region}
You MUST NOT downgrade the sec