rabbit-automation-action
Deploy Your Cloud from YAML
10K+
Declare cloud infrastructure in YAML. Deploy with git push.
A GitHub Marketplace composite action that discovers YAML configuration from your .rabbit/ directory and deploys cloud infrastructure across AWS, GCP, and Kubernetes using Terraform — all from a single uses: step.
Create .github/workflows/infra-build.yaml in your repository:
name: Infrastructure Build
on:
pull_request:
branches: ["production", "staging", "develop-*"]
push:
branches: ["production", "staging", "develop-*"]
paths: [".rabbit/**"]
delete:
schedule:
- cron: "0 2 * * *"
workflow_dispatch:
inputs:
plan_only:
description: "Plan only (no apply)"
type: boolean
default: true
environment:
description: "Target environment"
type: choice
options: [development, staging, production]
default: development
terraform_action:
description: "Terraform action"
type: choice
options: [apply, destroy]
default: apply
permissions:
contents: read
pull-requests: write
id-token: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: udx/github-rabbit-action@v1
with:
project_id: ${{ vars.GCP_PROJECT_ID }}
gcp_auth_provider: ${{ vars.GCP_AUTH_PROVIDER }}
gcp_service_account: ${{ vars.GCP_SERVICE_ACCOUNT }}
aws_region: ${{ vars.AWS_REGION }}
aws_role_arn: ${{ secrets.AWS_GITHUB_ACTIONS_ROLE_ARN }}
slack_webhook: ${{ secrets.SLACK_WEBHOOK_ROUTINE }}
dockerhub_username: ${{ vars.DOCKERHUB_USER_LOGIN }}
dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN_PULL_R2A }}
r2a_version: "4.8.0"
terraform_action: ${{ inputs.terraform_action || 'apply' }}
Create YAML files inside .rabbit/<environment>/:
.rabbit/production/10-dns.yamlservices:
- module: aws-route53
id: my-domain
domain: example.com
records:
- type: A
name: ""
alias:
name: d1234.cloudfront.net
zone_id: Z2FDTNDATAQYW2
.rabbit/production/20-cdn.yamlservices:
- module: aws-cloudfront-distribution
id: my-cdn-#{Environment}
domain: example.com
origins:
- domain_name: my-app.example.com
origin_id: app-origin
.rabbit/production/30-app.yamlservices:
- module: k8s-namespace
id: my-app
- module: k8s-deployment
id: my-app
image: my-org/my-app:latest
replicas: 2
ports:
- containerPort: 8080
- module: k8s-http-gateway-route
id: my-app
hostname: my-app.example.com
service_port: 8080
┌─────────────────────────────────────────────────────┐
│ GitHub Action Trigger (push / PR / delete / manual) │
└──────────────────────┬──────────────────────────────┘
│
┌─────────────▼──────────────┐
│ 1. Merge Configs │
│ Discover .rabbit/ YAML │
│ Resolve lifecycle │
│ Deep merge by module::id │
└─────────────┬──────────────┘
│
┌─────────────▼──────────────┐
│ 2. Safety Checks │
│ Block production manual │
│ Block production destroy │
│ Auto plan-only for PRs │
└─────────────┬──────────────┘
│
┌─────────────▼──────────────┐
│ 3. Cloud Auth │
│ GCP Workload Identity │
│ AWS OIDC (optional) │
└─────────────┬──────────────┘
│
┌─────────────▼──────────────┐
│ 4. Terraform Engine │
│ Docker: r2a container │
│ Per-service init/plan/ │
│ apply in deploy order │
└─────────────┬──────────────┘
│
┌─────────────▼──────────────┐
│ 5. Reporting │
│ Plan summary table │
│ PR comment │
│ GitHub step summary │
│ Slack notification │
└────────────────────────────┘
The environment is automatically resolved from:
| Trigger | Environment Source |
|---|---|
push | Branch name (production, staging, develop-foo) |
pull_request | Base branch (github.base_ref) |
delete | Deleted branch ref |
workflow_dispatch | User-selected input |
schedule | Branch name (default branch) |
Infrastructure configs live in .rabbit/ directories organized by lifecycle:
.rabbit/
├── production/ # Protected branches → production lifecycle
│ ├── 10-infra.yaml
│ ├── 20-app.yaml
│ └── us-east-1/ # Environment-specific overrides (smart merged)
│ └── 10-infra.yaml
├── staging/ # Root-only (no subdirectories)
│ └── infra.yaml
└── development/ # Fallback lifecycle
├── infra.yaml
└── dev-andy/ # Per-developer environments
└── infra.yaml
10-infra.yaml before 20-monitoring.yaml)module::id are deep-merged across files.rabbit/ are ignored (must be in a lifecycle directory)| Trigger | Mode |
|---|---|
pull_request | Plan only (preview changes) |
schedule | Plan only (drift detection) |
push | Apply (deploy changes) |
workflow_dispatch | User choice |
delete | Destroy (remove environment) |
| Module | Description | Order |
|---|---|---|
aws-route53 | DNS zones and records | 5 |
aws-acm | SSL/TLS certificates | 8 |
aws-waf | Web Application Firewall rules | 125 |
aws-cloudfront-distribution | CDN distribution with origins, behaviors, cache | 130 |
| Module | Description | Order |
|---|---|---|
gcp-networking | VPC networks and firewall rules | 10 |
gcp-static-ip | Regional/global static IP addresses | 15 |
gcp-postgresql-instance | Cloud SQL PostgreSQL instances | 20 |
gcp-sql-instance | Cloud SQL MySQL instances | 20 |
gcp-gke-cluster | GKE cluster provisioning | 30 |
gcp-gke-nodepool | GKE node pool configuration | 40 |
gcp-iam | IAM roles and service accounts | — |
gcp-secret-manager | Secret Manager entries | — |
gcp-storage | Cloud Storage buckets | — |
gcp-monitoring | Monitoring alert policies | 140 |
| Module | Description | Order |
|---|---|---|
k8s-shared-http-gateway | Shared HTTP gateway for routing | 55 |
k8s-namespace | Namespace with labels and annotations | 60 |
k8s-secret | Kubernetes secrets from config or GCP Secret Manager | 70 |
k8s-access | RBAC roles and bindings | 80 |
k8s-service | ClusterIP/LoadBalancer/NodePort services | 90 |
k8s-http-health-check-policy | Health check policies for gateway routes | 92 |
k8s-http-gateway-route | HTTP routing rules for gateway | 93 |
k8s-configmap | ConfigMaps from inline data or files | 95 |
k8s-deployment | Deployments with rolling updates | 100 |
k8s-memcached | Memcached StatefulSet | 102 |
k8s-hpa | Horizontal Pod Autoscaler | 110 |
k8s-pdb | Pod Disruption Budget | 120 |
| Module | Description | Order |
|---|---|---|
newrelic-synthetic-monitors | New Relic synthetic monitoring | 150 |
Deployment Order — services are deployed in ascending order by their module's deployment order. Destroy operations reverse the order.
Each service in your YAML config follows this structure:
services:
- module: <module-name> # Required: Terraform module to use
id: <unique-id> # Required: Unique identifier for this service
# ... module-specific fields
Use #{Variable} syntax in YAML values — they're replaced at runtime:
| Placeholder | Value |
|---|---|
#{Environment} | Resolved environment name |
#{Lifecycle} | Resolved lifecycle (production/staging/development) |
#{GcpProject} | GCP project ID |
#{GitOwner} | GitHub repository owner |
#{GitRepository} | GitHub repository name |
#{Namespace} | Kubernetes namespace (derived from repo name) |
#{SharedProject} | Shared GCP project ID |
Example:
services:
- module: k8s-deployment
id: my-app-#{Environment}
namespace: #{Namespace}
image: gcr.io/#{GcpProject}/my-app:latest
Reference secrets directly in your YAML:
services:
- module: k8s-secret
id: app-secrets
data:
DATABASE_URL: gcp://projects/my-project/secrets/db-url/versions/latest
The action automatically resolves gcp:// prefixed values to actual secret values at deploy time.
Set these in your repository or organization settings → Variables:
| Variable | Description |
|---|---|
GCP_PROJECT_ID | Google Cloud project ID |
GCP_AUTH_PROVIDER | GCP Workload Identity Provider resource name |
GCP_SERVICE_ACCOUNT | GCP Service Account email |
| Variable | Description |
|---|---|
AWS_REGION | AWS region (e.g., us-east-1) |
DOCKERHUB_USER_LOGIN | Docker Hub username for image pulls |
K8S_CLUSTER_NAME | GKE cluster name |
NEWRELIC_ACCOUNT_ID | New Relic account ID |
SHARED_PROJECT | Shared GCP project for cross-project access |
| Secret | Description |
|---|---|
SLACK_WEBHOOK_ROUTINE | Slack incoming webhook for notifications |
| Secret | Description |
|---|---|
AWS_GITHUB_ACTIONS_ROLE_ARN | AWS IAM OIDC role for Route53/CloudFront/WAF/ACM |
DOCKERHUB_TOKEN_PULL_R2A | Docker Hub token (paired with DOCKERHUB_USER_LOGIN) |
DOCKERHUB_HELM_TOKEN | Docker Hub token for Helm OCI charts |
NEWRELIC_API_KEY | New Relic API key |
permissions:
contents: read
pull-requests: write # For PR comments with plan summary
id-token: write # For GCP Workload Identity & AWS OIDC
Override specific values per environment using subdirectories:
.rabbit/
└── production/
├── 10-infra.yaml # Base production config
└── us-east-1/
└── 10-infra.yaml # Overrides for us-east-1 environment
Files in subdirectories are deep-merged on top of the parent directory files. Services with matching module::id pairs are merged, not duplicated.
For monorepo or multi-repo setups where multiple repositories share infrastructure:
- uses: udx/github-rabbit-action@v1
with:
multi_repo: "true"
shared_project: "shared-infra-project"
# ... other inputs
This isolates Terraform state per repository while allowing shared GCP project access.
Always pin to a specific version for reproducible builds:
- uses: udx/github-rabbit-action@v1
with:
r2a_version: "4.8.0"
Add delete to your workflow triggers and matching feature branches:
on:
delete: # Triggers destroy when branch is deleted
push:
branches: ["production", "staging", "develop-*"]
When a develop-* branch is deleted, the action automatically runs terraform destroy for that environment.
Enable detailed config output in logs:
- uses: udx/github-rabbit-action@v1
with:
print_config: "true"
The workflow dispatch inputs provide safe manual control:
| Input | Required | Default | Description |
|---|---|---|---|
project_id | ✅ | — | GCP project ID |
gcp_auth_provider | ✅ | — | GCP Workload Identity Provider |
gcp_service_account | ✅ | — | GCP Service Account email |
aws_role_arn | — | — | AWS IAM OIDC role ARN |
aws_region | — | — | AWS region |
dockerhub_username | — | — | Docker Hub username |
dockerhub_token | — | — | Docker Hub pull token |
dockerhub_helm_token | — | — | Docker Hub Helm OCI token |
r2a_version | — | latest | R2A Docker image tag |
terraform_action | — | apply | apply or destroy |
plan_only | — | auto | Override plan mode |
environment | — | auto | Override environment |
print_config | — | true | Debug config output |
multi_repo | — | false | Per-repo state isolation |
shared_project | — | — | Shared GCP project |
k8s_cluster_name | — | — | GKE cluster name |
newrelic_account_id | — | — | New Relic account ID |
newrelic_api_key | — | — | New Relic API key |
slack_webhook | — | — | Slack webhook URL |
source_dir | — | .rabbit | Config source directory |
github_token | — | github.token | GitHub token for PR comments |
| Output | Description |
|---|---|
environment | Resolved environment name |
lifecycle | Resolved lifecycle (production/staging/development) |
plan_only | Whether run was plan-only |
terraform_action | Action executed (apply/destroy/skip) |
has_changes | Whether Terraform detected changes |
changes_msg | Human-readable change summary |
cloudfront_distribution_id | CloudFront distribution ID (if applicable) |
k8s_namespace | Kubernetes namespace |
config_path | Path to merged config file |
Every run writes a configuration summary and deployment results to the GitHub Actions step summary — visible directly on the Actions run page.
Pull requests get an automatically updated comment with a detailed Terraform plan breakdown:
## Terraform Plan Summary
| Module / Service | Add | Change | Destroy |
| --- | --- | --- | --- |
| **Total** | 5 | 2 | 0 |
| `aws-cloudfront-distribution/my-cdn` | 0 | 1 | 0 |
| `k8s-deployment/my-app` | 3 | 1 | 0 |
| `k8s-http-gateway-route/my-app` | 2 | 0 | 0 |
Notifications are sent when:
Notifications include environment, change counts, failure stage, and a link to the action run.
dockerhub_username + dockerhub_token) to prevent rate limits when pulling the R2A imager2a_version to a specific tag for reproducible deploys (e.g., 4.8.0 instead of latest)10-dns.yaml, 20-cdn.yaml, 30-app.yaml) for deterministic ordering#{Environment} placeholders in service IDs to keep configs environment-awarecron: "0 2 * * *") to detect infrastructure drift.rabbit/ configs small and focused — one concern per fileGPL-2.0
Content type
Image
Digest
sha256:23b5d07c0…
Size
433.4 MB
Last updated
9 days ago
docker pull usabilitydynamics/rabbit-automation-action