AWS Builder Center

I Let an LLM Write My CloudFormation, Then Built 4 Guardrails So It Could Never Deploy Anything Dangerous

LLMs can turn plain English into CloudFormation in seconds, but they also hallucinate resource properties and happily open security groups to the world. Here is a practical 4-layer guardrail pipeline that catches bad templates before they ever reach your account.

The idea

"Create a private S3 bucket with versioning and a Lambda that triggers on upload."
An LLM can turn that sentence into a CloudFormation template in seconds. The scary part is not that it fails. It is that it sometimes looks right while quietly doing something wrong:
  • Inventing a property that does not exist
  • Using Principal: "*" in a bucket policy
  • Opening port 22 to 0.0.0.0/0
  • Attaching AdministratorAccess "to make it work"
So instead of trusting the model, I treat its output as untrusted input and push it through four guardrails.

The 4-layer pipeline

1
Plain English -> LLM -> Template -> [1 Syntax] -> [2 Lint] -> [3 Security policy] -> [4 Change set preview] -> Human approval -> Deploy

Layer 1: Syntax validation

The cheapest check. It catches malformed templates immediately.
1
aws cloudformation validate-template --template-body file://template.yaml

Layer 2: Linting for hallucinated properties

validate-template does not catch everything, such as wrong property names or invalid values for a resource type. cfn-lint checks templates against the resource specifications.
1
2
pip install cfn-lint
cfn-lint template.yaml
If the model invents a property, this layer flags it. I feed the error message back to the LLM and let it fix its own mistake (max 2 retries).

Layer 3: Security rules as code

Here I block patterns that should never ship. cfn-guard lets you write rules in a readable policy language.
1
2
3
4
5
rule s3_no_public_access {
Resources.*[ Type == 'AWS::S3::Bucket' ] {
Properties.PublicAccessBlockConfiguration exists
}
}
Example rules worth having:
  • No 0.0.0.0/0 on SSH or RDP
  • No wildcard Principal or Action: "*" in IAM policies
  • Encryption enabled on storage resources
  • No AdministratorAccess managed policy

Layer 4: Change set preview

Never go straight to "create stack". Create a change set and show the human exactly what will be added, modified or deleted.
1
2
3
4
5
6
7
aws cloudformation create-change-set \
--stack-name demo-stack \
--change-set-name preview \
--template-body file://template.yaml \
--change-set-type CREATE
aws cloudformation describe-change-set \
--stack-name demo-stack --change-set-name preview
I render this as a plain-English summary: "This will create 1 S3 bucket, 1 Lambda function and 1 IAM role."

The self-healing loop

The best part is that failures are not dead ends. Any error from layers 1 to 3 goes back to the model:
1
2
3
4
5
6
for attempt in range(3):
template = generate_template(prompt, previous_errors)
errors = run_guardrails(template)
if not errors:
break
previous_errors = errors
The model gets concrete feedback ("Property X is not valid for AWS::Lambda::Function") and usually corrects it on the next try.

What I learned

  1. Never trust model output, verify it. Treat it like user input.
  2. Deterministic tools beat prompt engineering for safety. Telling the model "be secure" in the prompt is a suggestion. A policy rule is a guarantee.
  3. Human approval stays in the loop. The change set preview is the final safety net.
  4. Error messages are great prompts. Feeding linter output back makes the model surprisingly good at fixing itself.

Try it yourself

Start small: take any LLM-generated template and run it through cfn-lint and one cfn-guard rule. You will be surprised how often something gets flagged.
If you are building something similar, I would love to hear which guardrails you would add.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article