A GitHub Action that processes CloudFormation deployment configurations, merges parameter and tag files with environment-specific overrides, and generates outputs for CloudFormation stack deployment. Features include parameter and tag processing, dynamic stack naming with CI build integration, automatic GitHub metadata tagging, GitHub Action summaries, and deployment artifact creation.
- 📁 Flexible Configuration: Reads CloudFormation configurations from customizable folder structures
- 🔄 Parameter Merging: Automatically merges default parameters with environment-specific overrides
- 🏷️ Dynamic Stack Naming: Generates appropriate stack names for both CI builds and environment deployments
- 🎲 CI Build Identifiers: Creates unique identifiers for CI builds to enable parallel deployments
- 🏷️ Tag Management: Merges default and environment-specific tags with automatic GitHub metadata
- ✅ Comprehensive Validation: Validates JSON files and required fields with clear error messages
- 📊 GitHub Action Summary: Displays processed parameters, tags, and configuration in the workflow summary
- 📦 Deployment Artifacts: Creates and uploads deployment JSON files for reuse and audit trails
- 🧪 Well Tested: Extensive unit and integration test coverage
- name: Process CloudFormation Configuration
uses: subhamay-bhattacharyya-gha/cfn-stack-params-action@main
with:
cfn-directory: 'infrastructure'
ci-build: 'false'
environment: 'sb-prod-us-east-1'
id: cfn-config
- name: Deploy CloudFormation Stack
uses: subhamay-bhattacharyya/cfn-create-stack-action@main
with:
name: ${{ steps.cfn-config.outputs.stack-name }}
template: infrastructure/template.yaml
parameter-overrides: ${{ steps.cfn-config.outputs.parameters }}- Inputs
- Outputs
- Configuration Structure
- Usage Examples
- Error Scenarios
- Troubleshooting
- Workflow Examples
- Contributing
- License
| Name | Description | Required | Default | Example |
|---|---|---|---|---|
cfn-directory |
Folder containing CloudFormation configuration files | No | cfn |
infrastructure |
ci-build |
Whether this is a CI build (true/false) | No | false |
true |
environment |
Target environment name | No | '' |
sb-prod-us-east-1 |
retention-days |
Number of days to retain the deployment artifact | No | 7 |
30 |
Specifies the folder path (relative to repository root) containing your CloudFormation configuration files. The folder must contain:
cloudformation.json- Main configuration fileparams/- Subfolder with parameter files
Boolean flag that determines the stack naming strategy:
true: Uses current Git branch name in stack name (for feature branch deployments)false: Uses environment name in stack name (for environment deployments)
Environment identifier used for:
- Loading environment-specific parameter files (
params/{environment}.json) - Stack naming when
ci-buildisfalse
Specifies how many days to retain the deployment artifact in GitHub Actions. The deployment JSON file containing parameters and stack name will be uploaded as an artifact and retained for the specified number of days. Useful for audit trails and debugging deployment issues.
| Name | Description | Type | Example |
|---|---|---|---|
parameters |
CloudFormation parameters in JSON array format | String | [{"ParameterName":"VpcId","ParameterValue":"vpc-123"}] |
stack-name |
Generated CloudFormation stack name | String | myproject-api-sb-prod-us-east-1 |
template |
CloudFormation template filename from configuration | String | infrastructure.yaml |
tags |
CloudFormation tags in JSON array format | String | [{"Key":"Environment","Value":"production"}] |
JSON string containing an array of CloudFormation parameters in the format:
[
{
"ParameterName": "ParameterKey",
"ParameterValue": "ParameterValue"
}
]CloudFormation template filename as specified in the cloudformation.json configuration file.
JSON string containing an array of CloudFormation tags in the format:
[
{
"Key": "TagKey",
"Value": "TagValue"
}
]Tags include user-defined tags from the tags/ directory plus automatically added GitHub metadata tags.
Generated stack name following these patterns:
- CI Build:
{project}-{stack-prefix}-{sanitized-branch-name}-{ci-build-id}(automatically includes CI build ID suffix) - Environment:
{project}-{stack-prefix}-{environment}
For CI builds, the stack name automatically includes a unique CI build identifier suffix and is trimmed to 128 characters if needed to comply with CloudFormation limits.
Your CloudFormation configuration should follow this directory structure:
{cfn-directory}/
├── cloudformation.json # Main configuration
├── params/
│ ├── default.json # Default parameters (required)
│ ├── sb-devl-us-east-1.json # Environment-specific parameters
│ ├── sb-test-us-east-1.json # Environment-specific parameters
│ └── sb-prod-us-east-1.json # Environment-specific parameters
└── tags/ # Tags directory (optional)
├── default.json # Default tags
├── sb-devl-us-east-1.json # Environment-specific tags
├── sb-test-us-east-1.json # Environment-specific tags
└── sb-prod-us-east-1.json # Environment-specific tags
Main configuration file with required fields:
{
"project": "my-application",
"template": "infrastructure.yaml",
"stack-prefix": "api"
}| Field | Description | Required | Example |
|---|---|---|---|
project |
Project identifier used in stack naming | Yes | my-application |
template |
CloudFormation template filename | Yes | infrastructure.yaml |
stack-prefix |
Stack prefix used in stack naming | Yes | api |
Contains default parameter values that apply to all environments:
{
"VpcId": "vpc-default",
"InstanceType": "t3.micro",
"Environment": "default",
"EnableLogging": true,
"BackupRetention": 7
}Environment-specific parameters that override defaults:
{
"VpcId": "vpc-prod-123456",
"InstanceType": "t3.large",
"Environment": "sb-prod-us-east-1",
"BackupRetention": 30,
"AlarmEmail": "alerts@company.com"
}Contains default tag values that apply to all environments:
{
"Environment": "default",
"Project": "my-application",
"Owner": "DevOps",
"CostCenter": "Engineering"
}Environment-specific tags that override defaults:
{
"Environment": "production",
"CostCenter": "Production",
"BackupRequired": "true",
"Compliance": "SOX"
}The action automatically adds these GitHub metadata tags to every deployment:
| Tag Name | Description | Example Value |
|---|---|---|
GitCommit |
Short commit hash (8 characters) | a1b2c3d4 |
GitLastModifiedBy |
GitHub actor who triggered the workflow | john.doe |
GitLastModifiedAt |
ISO timestamp of action execution | 2025-08-01T01:30:45.123Z |
GitFile |
Workflow name | Deploy to Production |
GitOrg |
GitHub organization name | my-company |
GitRepo |
Repository name | my-application |
These tags are automatically added and cannot be overridden by user-defined tags.
Parameter Merging Rules:
- Default parameters are loaded first
- Environment-specific parameters override matching keys
- Environment-specific parameters can add new keys
- For CI builds, a
CiBuildIdparameter is automatically added with value-{ci-build-id} - Final output contains merged parameters in CloudFormation format
Tag Merging Rules:
- Default tags are loaded first from
tags/default.json(optional) - Environment-specific tags override matching keys from
tags/{environment}.json(optional) - GitHub metadata tags are automatically added:
GitCommit: Short commit hash (8 characters)GitLastModifiedBy: GitHub actor who triggered the workflowGitLastModifiedAt: ISO timestamp of action executionGitFile: Workflow nameGitOrg: GitHub organization nameGitRepo: Repository name
- Final output contains merged tags in CloudFormation format
Deployment Artifacts:
The action automatically creates a deployment.json file containing:
- Processed CloudFormation parameters
- Processed CloudFormation tags
- Generated stack name
- Template path
- Uploaded as a GitHub Actions artifact for the specified retention period
name: Deploy to Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Process CloudFormation Configuration
uses: subhamay-bhattacharyya-gha/cfn-stack-params-action@main
with:
cfn-directory: 'infrastructure'
ci-build: 'false'
environment: 'sb-prod-us-east-1'
id: cfn-config
- name: Deploy Stack
run: |
aws cloudformation deploy \
--stack-name ${{ steps.cfn-config.outputs.stack-name }} \
--template-file infrastructure/template.yaml \
--parameter-overrides '${{ steps.cfn-config.outputs.parameters }}' \
--tags '${{ steps.cfn-config.outputs.tags }}'name: Feature Branch Deployment
on:
pull_request:
branches: [main]
jobs:
deploy-feature:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Process CloudFormation Configuration
uses: subhamay-bhattacharyya-gha/cfn-stack-params-action@main
with:
cfn-directory: 'cfn'
ci-build: 'true'
environment: 'sb-devl-us-east-1'
id: cfn-config
- name: Deploy Feature Stack
run: |
echo "Stack Name: ${{ steps.cfn-config.outputs.stack-name }}"
echo "Parameters: ${{ steps.cfn-config.outputs.parameters }}"
echo "Tags: ${{ steps.cfn-config.outputs.tags }}"name: Multi-Environment Deployment
on:
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
strategy:
matrix:
environment:
- sb-devl-us-east-1
- sb-test-us-east-1
- sb-prod-us-east-1
steps:
- uses: actions/checkout@v4
- name: Process CloudFormation Configuration
uses: subhamay-bhattacharyya-gha/cfn-stack-params-action@main
with:
cfn-directory: 'infrastructure'
ci-build: 'false'
environment: ${{ matrix.environment }}
id: cfn-config
- name: Deploy to ${{ matrix.environment }}
run: |
aws cloudformation deploy \
--stack-name ${{ steps.cfn-config.outputs.stack-name }} \
--template-file infrastructure/template.yaml \
--parameter-overrides '${{ steps.cfn-config.outputs.parameters }}' \
--tags '${{ steps.cfn-config.outputs.tags }}'- name: Process CloudFormation Configuration
uses: subhamay-bhattacharyya-gha/cfn-stack-params-action@main
with:
cfn-directory: 'aws/cloudformation'
ci-build: 'false'
environment: 'production'
retention-days: '30' # Keep artifacts for 30 days
id: cfn-config- name: Process CloudFormation Configuration
uses: subhamay-bhattacharyya-gha/cfn-stack-params-action@main
with:
cfn-directory: 'infrastructure'
ci-build: 'false'
environment: 'production'
retention-days: '90' # Long retention for production
id: cfn-config
- name: Download Deployment Artifact (in another job)
uses: actions/download-artifact@v4
with:
name: deployment-parameters
path: ./deployment
- name: Use Deployment Configuration
run: |
STACK_NAME=$(jq -r '.["stack-name"]' deployment/deployment.json)
TEMPLATE_PATH=$(jq -r '.["template-path"]' deployment/deployment.json)
PARAMETERS=$(jq -r '.parameters' deployment/deployment.json)
TAGS=$(jq -r '.tags' deployment/deployment.json)
echo "Deploying to stack: $STACK_NAME"
aws cloudformation deploy \
--stack-name "$STACK_NAME" \
--template-file "$TEMPLATE_PATH" \
--parameter-overrides "$PARAMETERS" \
--tags "$TAGS"The action provides clear error messages for common issues:
Error: Configuration directory not found
Error: Configuration directory 'cfn' does not exist
Error: Missing cloudformation.json
Error: cloudformation.json not found in cfn directory
Error: Missing default parameters
Error: default.json not found in cfn/params directory
Error: Malformed JSON
Error: Invalid JSON in cloudformation.json: Unexpected token } in JSON at position 45
Error: Missing required fields
Error: Missing required field 'project' in cloudformation.json
Error: Unable to determine branch
Error: Unable to determine current branch name for CI build
Error: Not a Git repository
Error: Current directory is not a Git repository
Warning: Missing environment parameters (non-fatal)
Warning: Environment parameter file 'sb-test-us-east-1.json' not found, using default parameters only
Error: Invalid parameter JSON
Error: Invalid JSON in params/default.json: Unexpected token ] in JSON at position 23
Cause: The specified cfn-directory path doesn't exist in your repository.
Solutions:
- Verify the directory path is correct relative to repository root
- Ensure the directory is committed to your repository
- Check for typos in the
cfn-directoryinput
# Correct
cfn-directory: 'infrastructure' # Directory exists at repo root
# Incorrect
cfn-directory: 'infrastucture' # Typo in directory nameCause: The cloudformation.json file is missing required fields.
Solution: Ensure your cloudformation.json contains all required fields:
{
"project": "your-project-name", // Required
"template": "template.yaml", // Required
"stack-prefix": "api" // Required
}Cause: Git operations failed when ci-build is set to true.
Solutions:
- Ensure you're using
actions/checkout@v4before this action - Verify the repository has Git history
- Check that the workflow has proper Git access
steps:
- uses: actions/checkout@v4 # Required for Git operations
- name: Process CloudFormation Configuration
uses: subhamay-bhattacharyya-gha/cfn-stack-params-action@main
with:
ci-build: 'true'Cause: Parameter files have incorrect structure or naming.
Solutions:
- Verify
default.jsonexists in theparams/subdirectory - Ensure environment parameter files are named exactly
{environment}.json - Check that all JSON files have valid syntax
cfn/
├── cloudformation.json
└── params/
├── default.json ✅ Correct
├── sb-prod-us-east-1.json ✅ Correct
├── prod.json ❌ Won't match environment 'sb-prod-us-east-1'
└── sb-prod-us-east-1.JSON ❌ Wrong file extension case
Cause: Branch names or environment names contain characters not allowed in CloudFormation stack names.
Solution: The action automatically sanitizes branch names, but ensure environment names follow CloudFormation naming rules:
- Only alphanumeric characters and hyphens
- Must start with a letter
- Maximum 128 characters
Cause: Insufficient permissions to read files or execute Git commands.
Solutions:
- Ensure the workflow has proper repository permissions
- Check that files are not in
.gitignore - Verify file permissions in the repository
Enable debug logging by setting the ACTIONS_STEP_DEBUG secret to true in your repository settings. This will provide detailed logs of the action's execution.
For detailed troubleshooting information, see the Troubleshooting Guide.
If you encounter issues not covered in the guides:
- Check the Issues page for similar problems
- Review the action logs for detailed error messages
- Ensure your configuration follows the documented structure
- Test your JSON files with a JSON validator
When using this action in production environments:
- Parameter Encryption: Store sensitive parameters in AWS Systems Manager Parameter Store or AWS Secrets Manager
- IAM Permissions: Use least-privilege IAM roles for CloudFormation deployments
- Environment Isolation: Keep environment-specific configurations in separate branches or repositories
- Secrets Management: Never commit sensitive values to parameter files
- Parameter File Size: Keep parameter files small and focused to reduce processing time
- CI Build Strategy: Use
ci-build: truefor feature branches to enable parallel deployments - Caching: Consider caching CloudFormation configuration files in multi-step workflows
- Stack Drift Detection: Regularly check for configuration drift between your parameter files and deployed stacks
- Deployment Tracking: Use the generated
ci-build-idfor correlating logs across deployment steps - Error Handling: Implement proper error handling in your workflows to catch configuration issues early
This action maintains backward compatibility. No changes required for existing workflows.
If you're migrating from custom parameter processing scripts:
- Create Configuration Structure: Set up the required
cloudformation.jsonandparams/directory - Update Workflow: Replace custom scripts with this action
- Test Environment Mapping: Verify environment parameter files are correctly named
- Validate Outputs: Ensure the generated parameters work with your CloudFormation deployment actions
We welcome contributions! Please see our Contributing Guide for details.
- Clone the repository
- Install dependencies:
npm install - Run tests:
npm test - Run linting:
npm run lint
# Run all tests
npm test
# Run unit tests only
npm run test:unit
# Run integration tests only
npm run test:integration
# Run with coverage
npm run test:coverageThis project is licensed under the MIT License - see the LICENSE file for details.