CtrlK
BlogDocsLog inGet started
Tessl Logo

pantheon-ai/cfn-template-compare

Compares deployed CloudFormation templates with locally synthesized CDK templates to detect drift, validate changes, and ensure consistency before deployment. Use when the user wants to compare CDK output with a deployed stack, check for infrastructure drift, run a pre-deployment validation, audit IAM or security changes, investigate a failing deployment, or perform a 'cdk diff'-style review. Triggered by phrases like 'compare templates', 'check for drift', 'cfn drift', 'stack comparison', 'infrastructure drift detection', 'safe to deploy', or 'what changed in my CDK stack'.

Does it follow best practices?

Evaluation100%

1.09x

Agent success when using this tile

Validation for skill structure

Overview
Skills
Evals
Files
name:
cfn-template-compare
description:
Compares deployed CloudFormation templates with locally synthesized CDK templates to detect drift, validate changes, and ensure consistency before deployment. Use when the user wants to compare CDK output with a deployed stack, check for infrastructure drift, run a pre-deployment validation, audit IAM or security changes, investigate a failing deployment, or perform a 'cdk diff'-style review. Triggered by phrases like 'compare templates', 'check for drift', 'cfn drift', 'stack comparison', 'infrastructure drift detection', 'safe to deploy', or 'what changed in my CDK stack'.

CloudFormation Template Comparison Skill

Quick Start

# 1. Retrieve the deployed template
aws cloudformation get-template \
  --stack-name <stack-name> \
  --region <region> \
  --profile <profile> \
  --query TemplateBody \
  --output json > deployed.json

# 2. Synthesize the local CDK template
make synth
cp cdk.out/<stack-name>.template.json local.json

# 3. Compare structure
jq 'keys' deployed.json
jq 'keys' local.json

# 4. Compare resource counts
jq '.Resources | length' deployed.json
jq '.Resources | length' local.json

# 5. Find added/removed resource IDs
diff <(jq -r '.Resources | keys[]' deployed.json | sort) \
     <(jq -r '.Resources | keys[]' local.json | sort)

# 6. Deep diff of a specific resource
diff <(jq '.Resources.<ResourceId>' deployed.json) \
     <(jq '.Resources.<ResourceId>' local.json)

Expected Workflow

Step 1: Preparation — verify prerequisites

# Check AWS credentials
aws sts get-caller-identity --profile <profile>
# → If this fails: verify AWS_PROFILE or --profile value before proceeding

# Confirm stack exists
aws cloudformation describe-stacks \
  --stack-name <stack-name> --region <region> --profile <profile> \
  --query 'Stacks[0].StackStatus'
# → If StackNotFoundException: check stack name and region

# Confirm CDK project synthesises cleanly
make synth
# → If synth fails: fix missing env vars in env-local.mk / env.mk before proceeding

Step 2: Retrieval

# Deployed template
aws cloudformation get-template \
  --stack-name <stack-name> --region <region> --profile <profile> \
  --query TemplateBody --output json > deployed.json
# → Validate: jq '.' deployed.json >/dev/null || echo "ERROR: invalid JSON"

# Local template
cp cdk.out/<stack-name>.template.json local.json
# → Validate: jq '.' local.json >/dev/null || echo "ERROR: invalid JSON"

Step 3: Hierarchical Analysis

# 1. Structure (top-level keys)
diff <(jq 'keys' deployed.json) <(jq 'keys' local.json)

# 2. Resource count
echo "Deployed: $(jq '.Resources | length' deployed.json)"
echo "Local:    $(jq '.Resources | length' local.json)"

# 3. Added / removed resources
comm -3 \
  <(jq -r '.Resources | keys[]' deployed.json | sort) \
  <(jq -r '.Resources | keys[]' local.json | sort)

# 4. Security — CDK Nag suppressions
diff \
  <(jq '[.Resources[].Metadata."cdk_nag" // empty]' deployed.json) \
  <(jq '[.Resources[].Metadata."cdk_nag" // empty]' local.json)

# 5. IAM roles and policies
diff \
  <(jq '[.Resources | to_entries[] | select(.value.Type | startswith("AWS::IAM"))]' deployed.json) \
  <(jq '[.Resources | to_entries[] | select(.value.Type | startswith("AWS::IAM"))]' local.json)

Step 4: Risk Assessment

Categorise each difference before reporting:

CategoryExamplesAction
ExpectedEnvironmental tags, GitRef, stack-name in resource IDsAuto-approve
Low riskDisplay names, cosmetic metadataNote and approve
Medium riskAlarm thresholds, EventBridge schedules, Lambda configReview and approve
High riskIAM policies, encryption settingsRequire explicit sign-off
CriticalCDK Nag suppressions, public access flags, resource removalBlock — get InfoSec/stakeholder approval

Step 5: Save Artifacts

# Timestamped directory for audit trail
BRANCH=$(git rev-parse --abbrev-ref HEAD)
DIR="cfn-compare-results/$(date +%Y-%m-%d-%H%M%S)_deployed-main_local-${BRANCH}"
mkdir -p "$DIR"

cp deployed.json "$DIR/"
cp local.json    "$DIR/"
jq -r '.Resources | keys[]' deployed.json | sort > "$DIR/deployed-resources.txt"
jq -r '.Resources | keys[]' local.json    | sort > "$DIR/local-resources.txt"

# Write report
cat > "$DIR/comparison-report.md" <<EOF
# CloudFormation Template Comparison

## Summary
- Deployed: <stack-name> ($(jq '.Resources|length' deployed.json) resources)
- Local:    <stack-name> ($(jq '.Resources|length' local.json) resources)
- Status: ✅ Safe to deploy | ⚠️ Review required | ❌ Critical issues

## Differences
<!-- Populate from Step 3 output -->

## Recommendations
<!-- List required actions -->

## Deployment Decision
<!-- Approve | Reject | Conditional — reasoning -->
EOF

Error Recovery

ErrorCauseFix
Stack not foundWrong name/regionVerify --stack-name, --region, --profile
CDK synth failedMissing env varCheck env-local.mk and env.mk
jq: parse errorInvalid JSON from CLIUse --output json and --query TemplateBody
Diff > 5000 linesTemplate too largeSwitch to hierarchical comparison (Step 3) instead of line diff

Required Tools

  • aws CLI — configured with appropriate profile
  • jq — JSON query and transformation
  • make — CDK synthesis via make synth
  • bash — shell scripting
  • diff / comm — comparison utilities

Common Scenarios

  • Clean deployment: identical resource counts, only expected environmental differences → approve
  • Drift detected: deployed threshold differs from local → revert console change or update CDK
  • New CDK Nag suppression: requires documented justification and InfoSec approval
  • Resource removal: block deployment, data-loss risk — review with stakeholders first

References

  • Automated script: scripts/compare-cfn-templates.sh
  • Real-world examples: references/compare-cfn-templates.md
  • CI/CD integration: .gitlab-ci.yml validate-template stage

Install with Tessl CLI

npx tessl i pantheon-ai/cfn-template-compare@0.1.2
Workspace
pantheon-ai
Visibility
Public
Created
Last updated