From 67acfc8a6bc5d9bb462f0180dcaee3d6fa36e388 Mon Sep 17 00:00:00 2001 From: Abhishek Agawane Date: Wed, 3 Dec 2025 10:12:29 +0530 Subject: [PATCH 1/3] Add REST API Gateway with VPC Link V2 to Private ALB pattern This pattern demonstrates how to integrate a REST API Gateway with a private Application Load Balancer and ECS Fargate cluster using VPC Link V2. Key features: - REST API Gateway with proxy integration - VPC Link V2 for private integration - Private ALB routing to ECS Fargate - Security groups and IAM roles - Uses existing VPC and subnets --- .../.gitignore | 29 ++ .../README.md | 96 +++++ .../example-pattern.json | 62 ++++ apigw-rest-vpclink-pvt-alb-terraform/main.tf | 333 ++++++++++++++++++ .../outputs.tf | 24 ++ .../variables.tf | 15 + 6 files changed, 559 insertions(+) create mode 100644 apigw-rest-vpclink-pvt-alb-terraform/.gitignore create mode 100644 apigw-rest-vpclink-pvt-alb-terraform/README.md create mode 100644 apigw-rest-vpclink-pvt-alb-terraform/example-pattern.json create mode 100644 apigw-rest-vpclink-pvt-alb-terraform/main.tf create mode 100644 apigw-rest-vpclink-pvt-alb-terraform/outputs.tf create mode 100644 apigw-rest-vpclink-pvt-alb-terraform/variables.tf diff --git a/apigw-rest-vpclink-pvt-alb-terraform/.gitignore b/apigw-rest-vpclink-pvt-alb-terraform/.gitignore new file mode 100644 index 000000000..e4abf1de0 --- /dev/null +++ b/apigw-rest-vpclink-pvt-alb-terraform/.gitignore @@ -0,0 +1,29 @@ +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log +crash.*.log + +# Exclude all .tfvars files +*.tfvars +*.tfvars.json + +# Ignore override files +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include tfplan files +*tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc + +# No additional exclusions needed diff --git a/apigw-rest-vpclink-pvt-alb-terraform/README.md b/apigw-rest-vpclink-pvt-alb-terraform/README.md new file mode 100644 index 000000000..42d342c1a --- /dev/null +++ b/apigw-rest-vpclink-pvt-alb-terraform/README.md @@ -0,0 +1,96 @@ +# REST API Gateway to Private HTTP Endpoint via VPC Link V2 + +This Terraform template deploys a complete serverless integration pattern connecting a public REST API Gateway to a private ECS Fargate cluster via VPC Link V2. + +### Prerequisites: +* An existing VPC with private subnets +* Private subnets must have internet access (via NAT Gateway or Internet Gateway) to pull container images from Docker Hub + +### Deployed resources: +* Security Groups for ALB and ECS tasks +* ECS Fargate cluster with service and task definitions +* Private Application Load Balancer with listener and target group +* VPC Link V2 connecting API Gateway to the private ALB +* REST API Gateway with proxy integration to the ALB + +Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/apigw-rest-vpclink-pvt-alb-terraform/ + +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 details. You are responsible for any AWS costs incurred. No warranty is implied in this example. + +## Requirements + +* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make 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](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) installed and configured +* [Terraform](https://learn.hashicorp.com/tutorials/terraform/install-cli) installed + +## Deployment Instructions + +1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: + ``` + git clone https://github.com/aws-samples/serverless-patterns + ``` +2. Change directory to the pattern directory: + ``` + cd serverless-patterns/apigw-rest-vpclink-pvt-alb-terraform + ``` +3. Update the `terraform.tfvars` file with your VPC ID and private subnet IDs: + ```hcl + vpc_id = "vpc-xxxxxxxxx" + + private_subnets = [ + "subnet-xxxxxxxxx", + "subnet-yyyyyyyyy" + ] + ``` +4. Run the below command to initialize, download, and install the defined providers. In case you are not already familiar with the Terraform CLI, refer Terraform [documentation](https://www.terraform.io/cli/commands) to learn more about the various commands. + ``` + terraform init + ``` +5. Deploy the AWS resources for the pattern as specified in the `main.tf` file. Input variables are configured in `variables.tf`. But, there are different ways to pass variables to the CLI. + + Use the below command to review the changes before deploying. + ``` + terraform plan + ``` + Deploy: + ``` + terraform apply --auto-approve + ``` +6. Note the output from the Terraform deployment process. These contain the resource names and/or ARNs which are used for testing. + +## How it works + +This pattern allows integration of public REST API Gateway endpoint to a private Application Load Balancer with an ECS Fargate cluster behind it. It allows to build a secure pattern without exposing the private subnet resources and can be accessed only via a VPC Link V2. + +The integration uses the `--integration-target` parameter with AWS CLI to properly configure the REST API Gateway with VPC Link V2, as this feature is not yet fully supported in the Terraform AWS provider. + +## Testing + +The stack creates and outputs the REST API endpoint. Open a browser and try out the generated API endpoint. You should see the Nginx home page. +Or, run the below command with the appropriate API endpoint. You should get a 200 response code. + +```bash +curl -s -o /dev/null -w "%{http_code}" ; echo +``` + +## Cleanup + +1. Change to the below directory inside the cloned git repo: + ``` + cd serverless-patterns/apigw-rest-vpclink-pvt-alb-terraform + ``` +2. Delete the resources + ```bash + terraform destroy + ``` +3. Enter 'yes' when prompted. + +4. Check if all the resources were deleted successfully. + ```bash + terraform show + ``` +---- +Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: MIT-0 diff --git a/apigw-rest-vpclink-pvt-alb-terraform/example-pattern.json b/apigw-rest-vpclink-pvt-alb-terraform/example-pattern.json new file mode 100644 index 000000000..fa37a34f4 --- /dev/null +++ b/apigw-rest-vpclink-pvt-alb-terraform/example-pattern.json @@ -0,0 +1,62 @@ +{ + "title": "REST API Gateway to Private ALB and ECS Fargate via VPC Link V2", + "description": "This pattern demonstrates REST API Gateway integration with a private Application Load Balancer and ECS Fargate cluster using VPC Link V2", + "language": "HCL", + "level": "200", + "framework": "Terraform", + "introBox": { + "headline": "How it works", + "text": [ + "This pattern deploys a REST API Gateway endpoint that integrates with a private Application Load Balancer using VPC Link V2", + "The private ALB routes traffic to an ECS Fargate cluster running containerized applications", + "The pattern creates all required security groups, IAM roles, and networking components for secure private integration" + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/apigw-rest-vpclink-pvt-alb-terraform", + "templateURL": "serverless-patterns/apigw-rest-vpclink-pvt-alb-terraform", + "projectFolder": "apigw-rest-vpclink-pvt-alb-terraform", + "templateFile": "apigw-rest-vpclink-pvt-alb-terraform/main.tf" + } + }, + "resources": { + "bullets": [ + { + "text": "REST API private integration using VPC link", + "link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-private-integration.html" + }, + { + "text": "Working with VPC links for REST APIs", + "link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-vpc-link.html" + }, + { + "text": "Tutorial: Build a REST API with API Gateway private integration", + "link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started-with-private-integration.html" + } + ] + }, + "deploy": { + "text": [ + "terraform init && terraform apply" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "terraform destroy" + ] + }, + "authors": [ + { + "name": "Abhishek Agawane", + "image": "https://drive.google.com/file/d/1E-5koDaKEaMUtOctX32I9TLwfh3kgpAq/view?usp=drivesdk", + "bio": "I am a Cloud Support Engineer (Serverless) at AWS who loves cloud computing", + "linkedin": "https://www.linkedin.com/in/agawabhi/" + } + ] +} diff --git a/apigw-rest-vpclink-pvt-alb-terraform/main.tf b/apigw-rest-vpclink-pvt-alb-terraform/main.tf new file mode 100644 index 000000000..b06177a57 --- /dev/null +++ b/apigw-rest-vpclink-pvt-alb-terraform/main.tf @@ -0,0 +1,333 @@ +# Required providers configuration +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.80" + } + } + required_version = ">= 1.9" +} + +provider "aws" { + profile = "default" + region = var.aws_region +} + +############################################## +# PART 1: Private ALB with ECS Fargate Target +############################################## + +# ALB security group +resource "aws_security_group" "alb_sg" { + name = "rest-api-alb-sg" + description = "Security group for private ALB" + vpc_id = var.vpc_id + + ingress { + description = "Allow HTTP from anywhere" + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = "rest-api-alb-sg" + } +} + +# ALB egress rule to ECS +resource "aws_security_group_rule" "alb_to_ecs" { + type = "egress" + description = "Allow traffic to ECS tasks" + from_port = 80 + to_port = 80 + protocol = "tcp" + security_group_id = aws_security_group.alb_sg.id + source_security_group_id = aws_security_group.ecs_sg.id +} + +# ECS task security group +resource "aws_security_group" "ecs_sg" { + name = "rest-api-ecs-sg" + description = "Security group for ECS tasks" + vpc_id = var.vpc_id + + egress { + description = "Allow all outbound" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = "rest-api-ecs-sg" + } +} + +# ECS ingress rule from ALB +resource "aws_security_group_rule" "ecs_from_alb" { + type = "ingress" + description = "Allow traffic from ALB" + from_port = 80 + to_port = 80 + protocol = "tcp" + security_group_id = aws_security_group.ecs_sg.id + source_security_group_id = aws_security_group.alb_sg.id +} + +# ECS Cluster +resource "aws_ecs_cluster" "main" { + name = "rest-api-cluster" + + tags = { + Name = "rest-api-cluster" + } +} + +# ECS Task Execution Role +resource "aws_iam_role" "ecs_task_execution_role" { + name = "rest-api-ecs-task-execution-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "ecs-tasks.amazonaws.com" + } + } + ] + }) +} + +resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" { + role = aws_iam_role.ecs_task_execution_role.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" +} + +# ECS Task Role +resource "aws_iam_role" "ecs_task_role" { + name = "rest-api-ecs-task-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "ecs-tasks.amazonaws.com" + } + } + ] + }) +} + +# ECS Task Definition +resource "aws_ecs_task_definition" "app" { + family = "rest-api-task" + network_mode = "awsvpc" + requires_compatibilities = ["FARGATE"] + cpu = "512" + memory = "1024" + execution_role_arn = aws_iam_role.ecs_task_execution_role.arn + task_role_arn = aws_iam_role.ecs_task_role.arn + + container_definitions = jsonencode([ + { + name = "web" + image = "nginx" + essential = true + portMappings = [ + { + containerPort = 80 + protocol = "tcp" + } + ] + } + ]) + + tags = { + Name = "rest-api-task" + } +} + +# ECS Service +resource "aws_ecs_service" "app" { + name = "rest-api-service" + cluster = aws_ecs_cluster.main.id + task_definition = aws_ecs_task_definition.app.arn + desired_count = 2 + deployment_maximum_percent = 200 + deployment_minimum_healthy_percent = 50 + enable_ecs_managed_tags = false + health_check_grace_period_seconds = 60 + launch_type = "FARGATE" + + network_configuration { + subnets = var.private_subnets + security_groups = [aws_security_group.ecs_sg.id] + } + + load_balancer { + target_group_arn = aws_lb_target_group.ecs_tg.arn + container_name = "web" + container_port = 80 + } + + depends_on = [aws_lb_target_group.ecs_tg, aws_lb_listener.http] + + tags = { + Name = "rest-api-service" + } +} + +# Create private Application Load Balancer +resource "aws_lb" "private_alb" { + name = "rest-api-private-alb" + internal = true + load_balancer_type = "application" + security_groups = [aws_security_group.alb_sg.id] + subnets = var.private_subnets + + tags = { + Name = "rest-api-private-alb" + } +} + +# Create target group for ECS +resource "aws_lb_target_group" "ecs_tg" { + name = "rest-api-ecs-tg" + port = 80 + protocol = "HTTP" + vpc_id = var.vpc_id + target_type = "ip" + + tags = { + Name = "rest-api-ecs-tg" + } +} + +# Create ALB listener +resource "aws_lb_listener" "http" { + load_balancer_arn = aws_lb.private_alb.arn + port = "80" + protocol = "HTTP" + + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.ecs_tg.arn + } +} + +############################################## +# PART 2: VPC Link V2 +############################################## + +resource "aws_apigatewayv2_vpc_link" "vpclink" { + name = "rest-api-vpclink-v2" + security_group_ids = [] + subnet_ids = var.private_subnets + + tags = { + Name = "rest-api-vpclink-v2" + } +} + +############################################## +# PART 3: REST API with VPC Link Integration +############################################## + +# Create REST API +resource "aws_api_gateway_rest_api" "rest_api" { + name = "rest-api-vpclink-demo" + description = "REST API with VPC Link V2 to private ALB" + + endpoint_configuration { + types = ["REGIONAL"] + } +} + +# Create proxy resource +resource "aws_api_gateway_resource" "proxy" { + rest_api_id = aws_api_gateway_rest_api.rest_api.id + parent_id = aws_api_gateway_rest_api.rest_api.root_resource_id + path_part = "{proxy+}" +} + +# Create ANY method +resource "aws_api_gateway_method" "proxy_any" { + rest_api_id = aws_api_gateway_rest_api.rest_api.id + resource_id = aws_api_gateway_resource.proxy.id + http_method = "ANY" + authorization = "NONE" + + request_parameters = { + "method.request.path.proxy" = true + } +} + +# Create VPC Link integration with VPC Link V2 +# Note: REST API + VPC Link V2 integration requires using AWS CLI directly +# as Terraform AWS provider doesn't fully support the integration_target parameter yet +resource "null_resource" "vpclink_integration" { + triggers = { + rest_api_id = aws_api_gateway_rest_api.rest_api.id + resource_id = aws_api_gateway_resource.proxy.id + vpc_link_id = aws_apigatewayv2_vpc_link.vpclink.id + alb_arn = aws_lb.private_alb.arn + } + + provisioner "local-exec" { + command = <<-EOT + aws apigateway put-integration \ + --rest-api-id ${aws_api_gateway_rest_api.rest_api.id} \ + --resource-id ${aws_api_gateway_resource.proxy.id} \ + --http-method ANY \ + --type HTTP_PROXY \ + --integration-http-method ANY \ + --connection-type VPC_LINK \ + --connection-id ${aws_apigatewayv2_vpc_link.vpclink.id} \ + --integration-target ${aws_lb.private_alb.arn} \ + --uri http://${aws_lb.private_alb.dns_name}/{proxy} \ + --request-parameters '{"integration.request.path.proxy":"method.request.path.proxy"}' + EOT + } + + depends_on = [ + aws_apigatewayv2_vpc_link.vpclink, + aws_lb_listener.http, + aws_api_gateway_method.proxy_any + ] +} + +# Create deployment +resource "aws_api_gateway_deployment" "deployment" { + rest_api_id = aws_api_gateway_rest_api.rest_api.id + + triggers = { + redeployment = sha1(jsonencode([ + aws_api_gateway_resource.proxy.id, + aws_api_gateway_method.proxy_any.id, + null_resource.vpclink_integration.id, + ])) + } + + lifecycle { + create_before_destroy = true + } + + depends_on = [null_resource.vpclink_integration] +} + +# Create stage +resource "aws_api_gateway_stage" "prod" { + deployment_id = aws_api_gateway_deployment.deployment.id + rest_api_id = aws_api_gateway_rest_api.rest_api.id + stage_name = "prod" +} diff --git a/apigw-rest-vpclink-pvt-alb-terraform/outputs.tf b/apigw-rest-vpclink-pvt-alb-terraform/outputs.tf new file mode 100644 index 000000000..a093b6c21 --- /dev/null +++ b/apigw-rest-vpclink-pvt-alb-terraform/outputs.tf @@ -0,0 +1,24 @@ +output "rest_api_endpoint" { + value = aws_api_gateway_stage.prod.invoke_url + description = "REST API Gateway Endpoint URL" +} + +output "vpc_link_id" { + value = aws_apigatewayv2_vpc_link.vpclink.id + description = "VPC Link V2 ID" +} + +output "alb_dns_name" { + value = aws_lb.private_alb.dns_name + description = "Private ALB DNS name" +} + +output "ecs_cluster_name" { + value = aws_ecs_cluster.main.name + description = "ECS cluster name" +} + +output "ecs_service_name" { + value = aws_ecs_service.app.name + description = "ECS service name" +} diff --git a/apigw-rest-vpclink-pvt-alb-terraform/variables.tf b/apigw-rest-vpclink-pvt-alb-terraform/variables.tf new file mode 100644 index 000000000..50a46d5b8 --- /dev/null +++ b/apigw-rest-vpclink-pvt-alb-terraform/variables.tf @@ -0,0 +1,15 @@ +variable "aws_region" { + description = "AWS region" + type = string + default = "us-east-1" +} + +variable "vpc_id" { + description = "VPC ID where resources will be created" + type = string +} + +variable "private_subnets" { + description = "List of private subnet IDs" + type = list(string) +} From f86f6c8db1dcaaf5115895f156d261ad28ff4787 Mon Sep 17 00:00:00 2001 From: Abhishek Agawane Date: Wed, 3 Dec 2025 10:26:26 +0530 Subject: [PATCH 2/3] Add REST API Gateway with VPC Link V2 to Private ALB pattern (SAM) This pattern demonstrates how to integrate a REST API Gateway with a private Application Load Balancer and ECS Fargate cluster using VPC Link V2. Key features: - REST API Gateway with proxy integration - VPC Link V2 for private integration - Private ALB routing to ECS Fargate - Security groups and IAM roles - AWS SAM implementation - Uses existing VPC and subnets --- apigw-rest-vpclink-pvt-alb-sam/.gitignore | 39 +++ apigw-rest-vpclink-pvt-alb-sam/README.md | 82 ++++++ .../example-pattern.json | 62 ++++ apigw-rest-vpclink-pvt-alb-sam/template.yaml | 275 ++++++++++++++++++ 4 files changed, 458 insertions(+) create mode 100644 apigw-rest-vpclink-pvt-alb-sam/.gitignore create mode 100644 apigw-rest-vpclink-pvt-alb-sam/README.md create mode 100644 apigw-rest-vpclink-pvt-alb-sam/example-pattern.json create mode 100644 apigw-rest-vpclink-pvt-alb-sam/template.yaml diff --git a/apigw-rest-vpclink-pvt-alb-sam/.gitignore b/apigw-rest-vpclink-pvt-alb-sam/.gitignore new file mode 100644 index 000000000..bf44992fd --- /dev/null +++ b/apigw-rest-vpclink-pvt-alb-sam/.gitignore @@ -0,0 +1,39 @@ +# SAM +.aws-sam/ +samconfig.toml + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# IDEs +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db diff --git a/apigw-rest-vpclink-pvt-alb-sam/README.md b/apigw-rest-vpclink-pvt-alb-sam/README.md new file mode 100644 index 000000000..daa876d80 --- /dev/null +++ b/apigw-rest-vpclink-pvt-alb-sam/README.md @@ -0,0 +1,82 @@ +# REST API Gateway to Private HTTP Endpoint via VPC Link V2 + +This AWS SAM template deploys the following resources. It requires a VPC id and private subnet ids as inputs. It is assumed that the VPC and subnets already exist and are configured with the required network routes (internet gateway for private subnets to pull container images). + +### Prerequisites: +* An existing VPC with private subnets +* Private subnets must have internet access (via NAT Gateway or Internet Gateway) to pull container images from Docker Hub + +### Deployed resources: +* Security Groups for ALB and ECS tasks +* ECS Fargate cluster with service and task definitions +* Private Application Load Balancer with listener and target group +* VPC Link V2 connecting API Gateway to the private ALB +* REST API Gateway with proxy integration to the ALB + +Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/apigw-rest-vpclink-pvt-alb-sam/ + +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 details. You are responsible for any AWS costs incurred. No warranty is implied in this example. + +## Requirements + +* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make 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](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) installed and configured +* [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) installed + +## Deployment Instructions + +1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: + ``` + git clone https://github.com/aws-samples/serverless-patterns + ``` +2. Change directory to the pattern directory: + ``` + cd serverless-patterns/apigw-rest-vpclink-pvt-alb-sam + ``` +3. From the command line, use AWS SAM to deploy the AWS resources for the pattern. You will be prompted for the VPC ID and private subnet IDs: + ``` + sam deploy --guided + ``` +4. During the prompts: + * Enter a stack name + * Enter the desired AWS Region + * Enter your VPC ID for the VpcId parameter + * Enter your first private subnet ID for the PrivateSubnet1 parameter + * Enter your second private subnet ID for the PrivateSubnet2 parameter + * Allow SAM CLI to create IAM roles with the required permissions + * Accept the defaults for the remaining prompts + + Once you have run `sam deploy --guided` mode once and saved arguments to a configuration file (samconfig.toml), you can use `sam deploy` in future to use these defaults. + +5. Note the outputs from the SAM deployment process. These contain the resource names and/or ARNs which are used for testing. + +## How it works + +This pattern allows integration of public REST API Gateway endpoint to a private Application Load Balancer with an ECS Fargate cluster behind it. It allows to build a secure pattern without exposing the private subnet resources and can be accessed only via a VPC Link V2. + +The integration uses CloudFormation's native support for VPC Link V2 with REST API Gateway. + +## Testing + +The stack creates and outputs the REST API endpoint. Open a browser and try out the generated API endpoint. You should see the Nginx home page. +Or, run the below command with the appropriate API endpoint. You should get a 200 response code. + +```bash +curl -s -o /dev/null -w "%{http_code}" ; echo +``` + +## Cleanup + +1. Delete the stack: + ```bash + sam delete + ``` +2. Confirm the stack has been deleted: + ```bash + aws cloudformation list-stacks --query "StackSummaries[?contains(StackName,'STACK_NAME')].StackStatus" + ``` +---- +Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: MIT-0 diff --git a/apigw-rest-vpclink-pvt-alb-sam/example-pattern.json b/apigw-rest-vpclink-pvt-alb-sam/example-pattern.json new file mode 100644 index 000000000..25b953747 --- /dev/null +++ b/apigw-rest-vpclink-pvt-alb-sam/example-pattern.json @@ -0,0 +1,62 @@ +{ + "title": "REST API Gateway to Private ALB and ECS Fargate via VPC Link V2", + "description": "This pattern demonstrates REST API Gateway integration with a private Application Load Balancer and ECS Fargate cluster using VPC Link V2", + "language": "YAML", + "level": "200", + "framework": "SAM", + "introBox": { + "headline": "How it works", + "text": [ + "This pattern deploys a REST API Gateway endpoint that integrates with a private Application Load Balancer using VPC Link V2", + "The private ALB routes traffic to an ECS Fargate cluster running containerized applications", + "The pattern creates all required security groups, IAM roles, and networking components for secure private integration" + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/apigw-rest-vpclink-pvt-alb-sam", + "templateURL": "serverless-patterns/apigw-rest-vpclink-pvt-alb-sam", + "projectFolder": "apigw-rest-vpclink-pvt-alb-sam", + "templateFile": "apigw-rest-vpclink-pvt-alb-sam/template.yaml" + } + }, + "resources": { + "bullets": [ + { + "text": "REST API private integration using VPC link", + "link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-private-integration.html" + }, + { + "text": "Working with VPC links for REST APIs", + "link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-vpc-link.html" + }, + { + "text": "Tutorial: Build a REST API with API Gateway private integration", + "link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started-with-private-integration.html" + } + ] + }, + "deploy": { + "text": [ + "sam deploy --guided" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "sam delete" + ] + }, + "authors": [ + { + "name": "Abhishek Agawane", + "image": "https://drive.google.com/file/d/1E-5koDaKEaMUtOctX32I9TLwfh3kgpAq/view?usp=drivesdk", + "bio": "I am a Cloud Support Engineer (Serverless) at AWS who loves cloud computing", + "linkedin": "https://www.linkedin.com/in/agawabhi/" + } + ] +} diff --git a/apigw-rest-vpclink-pvt-alb-sam/template.yaml b/apigw-rest-vpclink-pvt-alb-sam/template.yaml new file mode 100644 index 000000000..004937c3a --- /dev/null +++ b/apigw-rest-vpclink-pvt-alb-sam/template.yaml @@ -0,0 +1,275 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: REST API Gateway to Private ALB and ECS Fargate via VPC Link V2 + +Parameters: + VpcId: + Type: AWS::EC2::VPC::Id + Description: VPC ID where resources will be created + + PrivateSubnet1: + Type: AWS::EC2::Subnet::Id + Description: First private subnet ID + + PrivateSubnet2: + Type: AWS::EC2::Subnet::Id + Description: Second private subnet ID + +Resources: + # ALB Security Group + ALBSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupName: rest-api-alb-sg + GroupDescription: Security group for private ALB + VpcId: !Ref VpcId + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 80 + ToPort: 80 + CidrIp: 0.0.0.0/0 + Description: Allow HTTP from anywhere + Tags: + - Key: Name + Value: rest-api-alb-sg + + # ALB to ECS egress rule + ALBToECSEgressRule: + Type: AWS::EC2::SecurityGroupEgress + Properties: + GroupId: !Ref ALBSecurityGroup + IpProtocol: tcp + FromPort: 80 + ToPort: 80 + DestinationSecurityGroupId: !Ref ECSSecurityGroup + Description: Allow traffic to ECS tasks + + # ECS Security Group + ECSSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupName: rest-api-ecs-sg + GroupDescription: Security group for ECS tasks + VpcId: !Ref VpcId + SecurityGroupEgress: + - IpProtocol: -1 + CidrIp: 0.0.0.0/0 + Description: Allow all outbound + Tags: + - Key: Name + Value: rest-api-ecs-sg + + # ECS from ALB ingress rule + ECSFromALBIngressRule: + Type: AWS::EC2::SecurityGroupIngress + Properties: + GroupId: !Ref ECSSecurityGroup + IpProtocol: tcp + FromPort: 80 + ToPort: 80 + SourceSecurityGroupId: !Ref ALBSecurityGroup + Description: Allow traffic from ALB + + # ECS Cluster + ECSCluster: + Type: AWS::ECS::Cluster + Properties: + ClusterName: rest-api-cluster + + # ECS Task Execution Role + ECSTaskExecutionRole: + Type: AWS::IAM::Role + Properties: + RoleName: rest-api-ecs-task-execution-role + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: ecs-tasks.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy + + # ECS Task Role + ECSTaskRole: + Type: AWS::IAM::Role + Properties: + RoleName: rest-api-ecs-task-role + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: ecs-tasks.amazonaws.com + Action: sts:AssumeRole + + # ECS Task Definition + ECSTaskDefinition: + Type: AWS::ECS::TaskDefinition + Properties: + Family: rest-api-task + NetworkMode: awsvpc + RequiresCompatibilities: + - FARGATE + Cpu: '512' + Memory: '1024' + ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn + TaskRoleArn: !GetAtt ECSTaskRole.Arn + ContainerDefinitions: + - Name: web + Image: nginx + Essential: true + PortMappings: + - ContainerPort: 80 + Protocol: tcp + + # Application Load Balancer + PrivateALB: + Type: AWS::ElasticLoadBalancingV2::LoadBalancer + Properties: + Name: rest-api-private-alb + Type: application + Scheme: internal + SecurityGroups: + - !Ref ALBSecurityGroup + Subnets: + - !Ref PrivateSubnet1 + - !Ref PrivateSubnet2 + Tags: + - Key: Name + Value: rest-api-private-alb + + # Target Group + ECSTargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + Name: rest-api-ecs-tg + Port: 80 + Protocol: HTTP + VpcId: !Ref VpcId + TargetType: ip + Tags: + - Key: Name + Value: rest-api-ecs-tg + + # ALB Listener + ALBListener: + Type: AWS::ElasticLoadBalancingV2::Listener + Properties: + LoadBalancerArn: !Ref PrivateALB + Port: 80 + Protocol: HTTP + DefaultActions: + - Type: forward + TargetGroupArn: !Ref ECSTargetGroup + + # ECS Service + ECSService: + Type: AWS::ECS::Service + DependsOn: + - ALBListener + Properties: + ServiceName: rest-api-service + Cluster: !Ref ECSCluster + TaskDefinition: !Ref ECSTaskDefinition + DesiredCount: 2 + LaunchType: FARGATE + DeploymentConfiguration: + MaximumPercent: 200 + MinimumHealthyPercent: 50 + HealthCheckGracePeriodSeconds: 60 + NetworkConfiguration: + AwsvpcConfiguration: + Subnets: + - !Ref PrivateSubnet1 + - !Ref PrivateSubnet2 + SecurityGroups: + - !Ref ECSSecurityGroup + LoadBalancers: + - ContainerName: web + ContainerPort: 80 + TargetGroupArn: !Ref ECSTargetGroup + + # VPC Link V2 + VpcLink: + Type: AWS::ApiGatewayV2::VpcLink + Properties: + Name: rest-api-vpclink-v2 + SubnetIds: + - !Ref PrivateSubnet1 + - !Ref PrivateSubnet2 + + # REST API Gateway + RestApi: + Type: AWS::ApiGateway::RestApi + Properties: + Name: rest-api-vpclink-demo + Description: REST API with VPC Link V2 to private ALB + EndpointConfiguration: + Types: + - REGIONAL + + # API Gateway Resource (proxy) + ProxyResource: + Type: AWS::ApiGateway::Resource + Properties: + RestApiId: !Ref RestApi + ParentId: !GetAtt RestApi.RootResourceId + PathPart: '{proxy+}' + + # API Gateway Method (ANY) + ProxyMethod: + Type: AWS::ApiGateway::Method + Properties: + RestApiId: !Ref RestApi + ResourceId: !Ref ProxyResource + HttpMethod: ANY + AuthorizationType: NONE + RequestParameters: + method.request.path.proxy: true + Integration: + Type: HTTP_PROXY + IntegrationHttpMethod: ANY + Uri: !Sub 'http://${PrivateALB.DNSName}/{proxy}' + ConnectionType: VPC_LINK + ConnectionId: !Ref VpcLink + RequestParameters: + integration.request.path.proxy: method.request.path.proxy + + # API Gateway Deployment + ApiDeployment: + Type: AWS::ApiGateway::Deployment + DependsOn: + - ProxyMethod + Properties: + RestApiId: !Ref RestApi + + # API Gateway Stage + ApiStage: + Type: AWS::ApiGateway::Stage + Properties: + RestApiId: !Ref RestApi + DeploymentId: !Ref ApiDeployment + StageName: prod + +Outputs: + RestApiEndpoint: + Description: REST API Gateway Endpoint URL + Value: !Sub 'https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/prod' + + VpcLinkId: + Description: VPC Link V2 ID + Value: !Ref VpcLink + + ALBDnsName: + Description: Private ALB DNS name + Value: !GetAtt PrivateALB.DNSName + + ECSClusterName: + Description: ECS cluster name + Value: !Ref ECSCluster + + ECSServiceName: + Description: ECS service name + Value: !GetAtt ECSService.Name From 4a2f7f8ac098c592251d70d27ce7ff2e6afe2400 Mon Sep 17 00:00:00 2001 From: Abhishek Agawane Date: Wed, 3 Dec 2025 12:47:44 +0530 Subject: [PATCH 3/3] Update author bio in SAM pattern --- apigw-rest-vpclink-pvt-alb-sam/example-pattern.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apigw-rest-vpclink-pvt-alb-sam/example-pattern.json b/apigw-rest-vpclink-pvt-alb-sam/example-pattern.json index 25b953747..567f9b39e 100644 --- a/apigw-rest-vpclink-pvt-alb-sam/example-pattern.json +++ b/apigw-rest-vpclink-pvt-alb-sam/example-pattern.json @@ -55,7 +55,7 @@ { "name": "Abhishek Agawane", "image": "https://drive.google.com/file/d/1E-5koDaKEaMUtOctX32I9TLwfh3kgpAq/view?usp=drivesdk", - "bio": "I am a Cloud Support Engineer (Serverless) at AWS who loves cloud computing", + "bio": "Abhishek Agawane is a Security Consultant at Amazon Web Services with more than 8 years of industry experience. He helps organizations architect resilient, secure, and efficient cloud environments, guiding them through complex challenges and large-scale infrastructure transformations. He has helped numerous organizations enhance their cloud operations through targeted optimizations, robust architectures, and best-practice implementations.", "linkedin": "https://www.linkedin.com/in/agawabhi/" } ]