Skip to content

Commit 1873cd0

Browse files
authored
Merge pull request #2710 from jeromevdl/feat/stepfunctions-eventbridge-onpremise-tf
New serverless pattern : step functions to on-premises API (terraform)
2 parents 316e2d5 + 57ea0c1 commit 1873cd0

File tree

15 files changed

+619
-2
lines changed

15 files changed

+619
-2
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,8 @@ crash.log
206206
crash.*.log
207207

208208
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
209-
# password, private keys, and other secrets. These should not be part of version
210-
# control as they are data points which are potentially sensitive and subject
209+
# password, private keys, and other secrets. These should not be part of version
210+
# control as they are data points which are potentially sensitive and subject
211211
# to change depending on the environment.
212212
*.tfvars
213213
*.tfvars.json
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# AWS Step Functions to on-premises API (Terraform)
2+
3+
This pattern demonstrate how to call an on-premises API from a Step Functions state machine, leveraging Amazon EventBridge connection and VPC Lattice resource gateway and resource configuration.
4+
5+
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.
6+
7+
## Requirements
8+
9+
* [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.
10+
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured
11+
* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
12+
* [Terraform](https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/aws-get-started) installed
13+
14+
## Deployment Instructions
15+
16+
### Pre-requisites
17+
18+
This example assumes you already have a VPC with a connection to your datacenter (through VPN or Direct Connect) and an API is exposed on-premises and accessible from this VPC.
19+
The VPC and connection to your datacenter are not provided by this example. Refer to this [documentation](https://docs.aws.amazon.com/whitepapers/latest/aws-vpc-connectivity-options/network-to-amazon-vpc-connectivity-options.html) to set up such connectivity.
20+
21+
### Deployment
22+
23+
1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository:
24+
```
25+
git clone https://github.com/aws-samples/serverless-patterns
26+
```
27+
2. Change directory to the pattern directory:
28+
```
29+
cd stepfunctions-eventbridge-onpremise-tf
30+
```
31+
3. Create a `.tfvars` file with the following variables (use your custom values)
32+
33+
```
34+
api_domain_name = "api.internal.mycompany.com"
35+
api_key_secret_arn = "arn:aws:secretsmanager:us-east-1:123456789012:secret:07a4e645-fc95-4a10-853a-410b1b1eca5b-012nZO"
36+
vpc_id = "vpc-0e03d4ab114e951be"
37+
private_subnet_ids = ["subnet-05d53fa850148290e","subnet-070324fd8bc5885a5"]
38+
on_premises_cidr = "172.32.0.0/20"
39+
```
40+
41+
4. From the command line, use Terraform to deploy the AWS resources:
42+
```
43+
terraform init
44+
terraform apply -var-file=your-variables.tfvars
45+
```
46+
47+
When prompted "Do you want to deploy the infrastructure", type ```yes``` and press enter.
48+
49+
5. Note the outputs from the terraform deployment process. These contain the resource ARNs which are used for testing.
50+
51+
## How it works
52+
53+
![Architecture](architecture.png)
54+
55+
1. The HTTP task in Step Functions is leveraging an EventBridge Connection. It defines the target endpoint (e.g. https://my-internal-api.company.com/customer) and HTTP method (e.g. GET) as well as eventual HTTP headers.
56+
2. The EventBridge Connection defines the authentication mechanism (OAuth, Basic or API Key in this case) for the target endpoint as well as the resource configuration to use for a private/internal endpoint.
57+
3. The resource configuration defines the target endpoint itself, generally an on-premise IP address or DNS name (e.g. my-internal-api.company.com). Resource configuration is associated to a resource gateway.
58+
4. The resource gateway "opens a door" to the VPC and allow ingress. It is linked to the chosen subnets (generally private) and is also protected by a security group to further protect your backend API. Note: You could stop here at the VPC level, with a private API deployed in a private subnet.
59+
5. The site-to-site VPN or Direct Connect connection establishes the connection between the AWS cloud (generally with a VPN Gateway or a Transit Gateway) and your datacenter (through a Customer Gateway).
60+
6. Finally, the internal API that resides in your datacenter can be accessed via this "route".
61+
62+
You can get more details in this [blog post](https://community.aws/content/2oExiwtkpK7go3wzAVzzF05ysqu).
63+
64+
## Testing
65+
66+
1. First make sure the EventBridge connection is active. Use the command `aws events describe-connection --name on-premise-connection --query ConnectionState` and verify it is `ACTIVE`. Otherwise, wait for an additional minute and verify again.
67+
2. Go to the AWS Step Functions console and open the state machine deployed by the example (`state-machine-call-onprem`).
68+
3. Click on `Start Execution` on the top right and again in the popup (no input is required for this example).
69+
4. Observe the result. Your on-premise API should be called by the state machine and an eventual result returned to the task.
70+
71+
You can also use the AWS CLI with the following command (make sure to use the output of the terraform script):
72+
73+
```shell
74+
aws stepfunctions start-execution --state-machine-arn arn:aws:states:us-east-1:123456789012:stateMachine:state-machine-call-onprem
75+
```
76+
77+
## Cleanup
78+
**To avoid incurring future charges, delete the resources created by the Terraform script.**
79+
1. Return to the directory where you deployed your terraform script.
80+
2. To destroy the infrastructure in AWS, run the command
81+
82+
```bash
83+
terraform destroy
84+
```
85+
When prompted do you want to destroy the infrastructure, type ```yes``` and press enter.
86+
87+
----
88+
Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
89+
90+
SPDX-License-Identifier: MIT-0
61.1 KB
Loading
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{
2+
"title": "Step Functions to on-premises API (Terraform)",
3+
"description": "Step Functions performing HTTP call to on-premises API",
4+
"language": "",
5+
"level": "200",
6+
"framework": "Terraform",
7+
"introBox": {
8+
"headline": "How it works",
9+
"text": [
10+
"This sample project demonstrates how to use an AWS Step Functions state machine to call an on-premises API without using an intermediary Lambda function. This pattern is leveraging EventBridge connection to connect to an HTTP endpoint and VPC Lattice to access private resources (in a VPC or on premises).",
11+
"This pattern deploys one Step Functions, one EventBridge connection, a VPC Lattice resource configuration and resource gateway. You need to have a connection between a VPC and a datacenter (using VPN or Direct Connect)."
12+
]
13+
},
14+
"gitHub": {
15+
"template": {
16+
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/stepfunctions-eventbridge-onpremise-tf",
17+
"templateURL": "serverless-patterns/stepfunctions-eventbridge-onpremise-tf",
18+
"projectFolder": "stepfunctions-eventbridge-onpremise-tf",
19+
"templateFile": "main.tf"
20+
}
21+
},
22+
"resources": {
23+
"bullets": [
24+
{
25+
"text": "Connect to private APIs using EventBridge connections",
26+
"link": "https://docs.aws.amazon.com/eventbridge/latest/userguide/connection-private.html"
27+
},
28+
{
29+
"text": "Call HTTPs endpoints using Step Functions HTTP Task",
30+
"link": "https://docs.aws.amazon.com/step-functions/latest/dg/call-https-apis.html"
31+
}
32+
]
33+
},
34+
"deploy": {
35+
"text": [
36+
"terraform init",
37+
"terraform apply"
38+
]
39+
},
40+
"testing": {
41+
"text": [
42+
"See the GitHub repo for detailed testing instructions."
43+
]
44+
},
45+
"cleanup": {
46+
"text": [
47+
"terraform destroy"
48+
]
49+
},
50+
"authors": [
51+
{
52+
"name": "Jerome Van Der Linden",
53+
"image": "https://serverlessland.com/assets/images/resources/contributors/jerome-van-der-linden.jpg",
54+
"bio": "Jerome is a Solutions Architect Builder at AWS. Passionate about building stuff using the AWS services, and especially the serverless ones.",
55+
"linkedin": "jeromevdl",
56+
"twitter": "jeromevdl"
57+
}
58+
]
59+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
terraform {
2+
required_version = ">= 1.0.0" # Ensure that the Terraform version is 1.0.0 or higher
3+
4+
required_providers {
5+
aws = {
6+
source = "hashicorp/aws" # Specify the source of the AWS provider
7+
version = ">= 5.0.0" # Use a version of the AWS provider that is compatible with version
8+
}
9+
}
10+
}
11+
12+
provider "aws" {
13+
region = "us-east-1"
14+
}
15+
16+
module "eventbridge_connection" {
17+
source = "./modules/eventbridge_connection"
18+
19+
vpc_id = var.vpc_id
20+
on_premises_cidr = var.on_premises_cidr
21+
api_domain_name = var.api_domain_name
22+
private_subnet_ids = var.private_subnet_ids
23+
api_key_secret_arn = var.api_key_secret_arn
24+
}
25+
26+
module "state_machine" {
27+
source = "./modules/state_machine"
28+
29+
connection_arn = module.eventbridge_connection.connection_arn
30+
connection_secret_arn = module.eventbridge_connection.connection_secret_arn
31+
api_domain_name = var.api_domain_name
32+
log_retention_days = 30
33+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
resource "aws_security_group" "resource_gateway_sg" {
2+
name_prefix = "resource-gateway-sg"
3+
description = "Security group for resource gateway"
4+
vpc_id = var.vpc_id
5+
6+
egress {
7+
from_port = 443
8+
to_port = 443
9+
protocol = "tcp"
10+
cidr_blocks = [var.on_premises_cidr]
11+
description = "Allow HTTPS traffic to on-premises"
12+
}
13+
14+
egress {
15+
from_port = 80
16+
to_port = 80
17+
protocol = "tcp"
18+
cidr_blocks = [var.on_premises_cidr]
19+
description = "Allow HTTP traffic to on-premises"
20+
}
21+
}
22+
23+
resource "aws_vpclattice_resource_gateway" "on_premise_resource_gateway" {
24+
name = "resource-gateway"
25+
ip_address_type = "IPV4"
26+
vpc_id = var.vpc_id
27+
security_group_ids = [aws_security_group.resource_gateway_sg.id]
28+
subnet_ids = var.private_subnet_ids
29+
}
30+
31+
resource "aws_vpclattice_resource_configuration" "on_premise_resource_configuration" {
32+
name = "resource-config"
33+
port_ranges = ["80", "443"]
34+
protocol = "TCP"
35+
resource_gateway_identifier = aws_vpclattice_resource_gateway.on_premise_resource_gateway.id
36+
type = "SINGLE"
37+
38+
resource_configuration_definition {
39+
# uncomment if using ip address
40+
# ip_resource {
41+
# ip_address = var.api_ip_address
42+
# }
43+
44+
# remove if using ip address
45+
dns_resource {
46+
domain_name = var.api_domain_name
47+
ip_address_type = "IPV4"
48+
}
49+
}
50+
}
51+
52+
data "aws_secretsmanager_secret_version" "api_key" {
53+
secret_id = var.api_key_secret_arn
54+
}
55+
56+
resource "aws_cloudwatch_event_connection" "on_premise_connection" {
57+
name = "on-premise-connection"
58+
description = "Connection to on premises API"
59+
authorization_type = "API_KEY"
60+
61+
auth_parameters {
62+
# configure basic or oauth instead of api_key, depending on your authentication method
63+
api_key {
64+
key = "x-api-key"
65+
value = data.aws_secretsmanager_secret_version.api_key.secret_string
66+
}
67+
# eventually add http parameters (header, body or query string) to the connection
68+
invocation_http_parameters {
69+
header {
70+
key = "x-origin"
71+
value = "aws-state-machine"
72+
}
73+
}
74+
}
75+
76+
invocation_connectivity_parameters {
77+
resource_parameters {
78+
resource_configuration_arn = aws_vpclattice_resource_configuration.on_premise_resource_configuration.arn
79+
}
80+
}
81+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
output "connection_arn" {
2+
description = "ARN of the EventBridge connection"
3+
value = aws_cloudwatch_event_connection.on_premise_connection.arn
4+
}
5+
6+
output "connection_secret_arn" {
7+
description = "ARN of the secret for EventBridge connection"
8+
value = aws_cloudwatch_event_connection.on_premise_connection.secret_arn
9+
}
10+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
variable "vpc_id" {
2+
type = string
3+
description = "ID of the VPC linked to on-premises network"
4+
}
5+
6+
variable "private_subnet_ids" {
7+
type = list(string)
8+
description = "List of private subnet IDs in the VPC"
9+
}
10+
11+
variable "on_premises_cidr" {
12+
type = string
13+
description = "CIDR block of the on-premises network"
14+
}
15+
16+
# Choose either a domain name if you have one configured for your API, or and IP address
17+
variable "api_domain_name" {
18+
type = string
19+
description = "Domain name of the on-premises API"
20+
}
21+
22+
# variable "api_ip_address" {
23+
# type = string
24+
# description = "IP address of the on-premises API"
25+
# }
26+
27+
# If using Basic or OAuth, change the authentication mechanism
28+
variable "api_key_secret_arn" {
29+
type = string
30+
description = "ARN of the existing secret containing the API key"
31+
}

0 commit comments

Comments
 (0)