This Terraform module deploys a template automation solution using AWS Lambda and API Gateway. It provides a serverless architecture for automating template creation and management.
This repository provides reusable Terraform modules for deploying and managing the Lambda function and related infrastructure that automate repository creation and configuration. It is part of a four-repository system for infrastructure automation.
This repository works together with the following:
- template-repos-lambda-deployment: Uses these modules to deploy the Lambda function and manage AWS resources.
- template-automation-lambda: The Lambda function code that is deployed and managed by these modules.
- packer-pipeline: Powers the CI/CD process by building the Lambda container images that this module deploys.
The modules in this repository are consumed by the deployment repository to provision all necessary AWS resources for the automation system.
- Serverless API endpoint via API Gateway
- Python-based Lambda function deployment
- Secure IAM roles and permissions
- Configurable environment variables
- CORS configuration for API Gateway
- Customizable resource naming via prefix
- Integration with container images built by the packer-pipeline tool
This module deploys the template automation Lambda function as a container image that is built separately using the packer-pipeline tool. The packer-pipeline tool:
- Creates or updates an AWS CodeBuild project
- Uploads the Lambda function source code to S3
- Executes a Packer build in CodeBuild
- Pushes the resulting container image to Amazon ECR
- Provides consistent build environments for every build
When using this module with container images built via packer-pipeline, you should configure the Lambda function to use the ECR image:
module "template_automation" {
source = "github.e.it.census.gov/SCT-Engineering/terraform-aws-template-automation"
name_prefix = "template-repos"
# Lambda configuration using container image from ECR
lambda_config = {
# Use a container image from ECR built with packer-pipeline
image_uri = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${data.aws_region.current.name}.amazonaws.com/template-automation-lambda:latest"
# Other Lambda configuration...
}
# Other module configuration...
}For more information on building Lambda container images with packer-pipeline, see the packer-pipeline repository.
module "template_automation" {
source = "github.com/djaboxx/terraform-aws-template-automation"
name_prefix = "my-automation"
# GitHub configuration
github_api_url = "https://api.github.com"
github_org_name = "my-org"
template_repo_name = "my-template-repo"
template_config_file = "config.json"
github_commit_author_name = "Template Automation"
github_commit_author_email = "automation@example.com"
template_topics = "infrastructure,template"
# GitHub token configuration
github_token = {
secret_name = "github/token"
# token = "your-token-here" # Optional: Provide directly (not recommended for production)
}
# Lambda configuration options
# Option 1: Using a container image built with packer-pipeline
lambda_config = {
image_uri = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${data.aws_region.current.name}.amazonaws.com/template-automation-lambda:latest"
memory_size = 512
timeout = 300
}
# Option 2: Using a zip file deployment
# lambda_config = {
# create_zipfile = true
# source_path = "../template_automation" # Path to your Lambda source code
# runtime = "python3.9"
# memory_size = 256
# timeout = 300
# }
# Parameter Store configuration
parameter_store_prefix = "/template-automation"
# Additional custom parameters if needed
ssm_parameters = {
"ADDITIONAL_PARAM" = "custom-value"
}
environment_variables = {
SECRET_NAME = "github/token" # AWS Secrets Manager secret containing GitHub token
}
tags = {
Environment = "production"
Project = "template-automation"
}
}| Name | Version |
|---|---|
| terraform | >= 1.0.0 |
| aws | >= 4.0.0 |
| Name | Version |
|---|---|
| aws | >= 4.0.0 |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| name_prefix | Prefix to be used for resource names | string |
n/a | yes |
| parameter_store_prefix | Prefix for SSM parameters | string |
/template-automation |
no |
| ssm_parameters | Additional SSM parameters to create | map(string) |
{} |
no |
| github_api_url | URL for the GitHub Enterprise API | string |
https://api.github.com |
no |
| github_org_name | GitHub organization name | string |
n/a | yes |
| template_repo_name | GitHub repository name for the template | string |
n/a | yes |
| template_config_file | Name of the config file to write in new repositories | string |
config.json |
no |
| github_commit_author_name | Name for commit author | string |
Template Automation |
no |
| github_commit_author_email | Email for commit author | string |
automation@example.com |
no |
| template_topics | Topics to assign to new repositories (comma-separated string) | string |
infrastructure |
no |
| github_token | GitHub token configuration object with secret_name (required) and token (optional) | object |
n/a | yes |
| lambda_config | Lambda function configuration object | object |
n/a | yes |
| tags | Tags to be applied to all resources | map(string) |
{} |
no |
| Name | Description |
|---|---|
| lambda_function_arn | The ARN of the Lambda function |
| lambda_function_name | The name of the Lambda function |
| api_endpoint | The URL of the API Gateway endpoint |
| api_id | The ID of the API Gateway |
| lambda_role_arn | The ARN of the IAM role used by the Lambda function |
This module creates:
- An HTTP API Gateway endpoint
- A Lambda function to handle requests
- Necessary IAM roles and permissions
- API Gateway integration with the Lambda function
- CORS configuration for the API endpoint
This module supports optional IAM authentication for the API Gateway endpoint. When enabled, clients must sign their requests using AWS SigV4 signing process.
module "template_automation" {
source = "github.com/djaboxx/terraform-aws-template-automation"
name_prefix = "my-automation"
# Enable IAM authentication
enable_iam_auth = true
allowed_iam_arns = [
"arn:aws:iam::123456789012:role/my-role",
"arn:aws:iam::123456789012:user/my-user"
]
# ... rest of your configuration ...
}When IAM authentication is enabled, you'll need to sign your HTTP requests using AWS SigV4. Here are examples in different languages:
import boto3
import requests
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest
def invoke_api(url, payload):
# Create a boto3 session (will use your default credentials)
session = boto3.Session()
credentials = session.get_credentials()
# Prepare the request
request = AWSRequest(
method='POST',
url=url,
data=payload,
headers={
'Content-Type': 'application/json'
}
)
# Sign the request
SigV4Auth(credentials, 'execute-api', session.region_name).add_auth(request)
# Send the request using the signed headers
response = requests.post(
url,
headers=dict(request.headers),
data=payload
)
return response
# Example usage
api_url = 'https://your-api-id.execute-api.region.amazonaws.com/prod/template'
payload = '{"templateName": "example"}'
response = invoke_api(api_url, payload)aws apigateway test-invoke-method \
--rest-api-id your-api-id \
--resource-id your-resource-id \
--http-method POST \
--path-with-query-string /template \
--body '{"templateName": "example"}'import { SignatureV4 } from '@aws-sdk/signature-v4';
import { Sha256 } from '@aws-crypto/sha256-js';
import { defaultProvider } from '@aws-sdk/credential-provider-node';
async function invokeApi(url, payload) {
// Create signature
const signer = new SignatureV4({
credentials: defaultProvider(),
region: 'your-region',
service: 'execute-api',
sha256: Sha256
});
// Prepare request
const request = new Request(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload)
});
// Sign request
const signedRequest = await signer.sign(request);
// Send request
const response = await fetch(signedRequest);
return response;
}
// Example usage
const apiUrl = 'https://your-api-id.execute-api.region.amazonaws.com/prod/template';
const payload = { templateName: 'example' };
const response = await invokeApi(apiUrl, payload);When IAM authentication is enabled, the calling identity needs the following IAM permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:region:account-id:api-id/stage/POST/template"
}
]
}You can get the exact ARN from the module outputs:
output "api_execution_arn" {
value = module.template_automation.execution_arn
}Common issues when using IAM authentication:
-
403 Forbidden: Check that:
- Your IAM role/user ARN is in the
allowed_iam_arnslist - You have the correct execute-api:Invoke permissions
- Your request is properly signed with SigV4
- Your IAM role/user ARN is in the
-
401 Unauthorized: Verify that:
- Your AWS credentials are valid and not expired
- You're using the correct region in your signing process
- The date/time in your request is accurate
-
Missing Authentication Token: Ensure that:
- You're including all required SigV4 headers
- The Authorization header is properly formatted
For more detailed troubleshooting, enable CloudWatch logs in the API Gateway stage settings.
Contributions are welcome! Please feel free to submit a Pull Request.