Skill v1.0.1
currentAutomated scan100/1001 files
version: "1.0.1" name: infrastructure-validation description: Use when working with Terraform (.tf, .tfvars), Ansible (playbooks, roles, inventory), Docker (Dockerfile, docker-compose.yml), Kubernetes (manifests, Helm charts), CloudFormation, or any infrastructure-as-code files. Also use when running terraform plan/apply, building Docker images, writing Helm templates, or when IaC changes touch security groups, IAM policies, or secrets. Provides validation workflows, tool chains, and common mistake prevention.
<!-- TOKEN BUDGET: 140 lines / ~420 tokens -->
Infrastructure Validation
<activation>
Activation Triggers
- Files matching:
*.tf,*.tfvars,Dockerfile,docker-compose.yml,playbook*.yml,roles/,inventory/ - Config:
.shipyard/config.jsonhasiac_validationset to"auto"ortrue - Templates with
AWSTemplateFormatVersion(CloudFormation) - YAML with
apiVersion:(Kubernetes)
Natural Language Triggers
- "validate terraform", "check docker", "lint ansible", "IaC validation", "infrastructure check"
</activation>
Overview
IaC mistakes don't cause test failures -- they cause outages, breaches, and cost overruns. Validate before every change.
Core principle: Never apply without plan review. Like TDD requires tests before code, IaC requires validation before apply.
<instructions>
Terraform Workflow
Run in order. Each step must pass before proceeding.
terraform fmt -check # 1. Format (auto-fix with fmt if needed)terraform validate # 2. Syntax validationterraform plan -out=tfplan # 3. Review every change -- NEVER skiptflint --recursive # 4. Lint (if installed)tfsec . OR checkov -d . # 5. Security scan (if installed)
Drift detection: terraform plan -detailed-exitcode -- exit code 2 means drift. Document what drifted and why before overwriting.
Ansible Workflow
yamllint . # 1. YAML syntaxansible-lint # 2. Best practicesansible-playbook --syntax-check *.yml # 3. Playbook syntaxansible-playbook --check *.yml # 4. Dry run (where supported)molecule test # 5. Role tests (if configured)
Docker Workflow
hadolint Dockerfile # 1. Lint (if installed)docker build -t test-build . # 2. Buildtrivy image test-build # 3. Security scan (if installed)docker compose config # 4. Validate compose (if applicable)
Kubernetes Workflow
kubectl --dry-run=client -f manifest.yml # 1. Client-side validationkubectl --dry-run=server -f manifest.yml # 2. Server-side validation (if cluster access)kubeval --strict manifest.yml # 3. Schema validation (if installed)kubeconform -strict manifest.yml # 4. Schema validation alternativekube-linter lint . # 5. Best practices (if installed)helm template . | kubeval --strict # 6. Helm chart validation (if applicable)
</instructions>
Common Mistakes
Terraform
| Mistake | Fix | |
|---|---|---|
| Local state file | Use remote backend (S3+DynamoDB, GCS) | |
| No state locking | Enable lock table | |
| Hardcoded secrets | Use variables + secret manager | |
* in security groups | Restrict to specific CIDRs | |
| Unpinned provider version | Pin in required_providers | |
| Missing tags | Require via policy or module defaults |
Ansible
| Mistake | Fix | |
|---|---|---|
| Plaintext secrets | ansible-vault encrypt | |
shell instead of modules | Use native modules (apt, copy, etc.) | |
| Everything as root | become: false by default, escalate only when needed |
Docker
| Mistake | Fix | |
|---|---|---|
FROM ubuntu:latest | Pin to digest: FROM ubuntu:22.04@sha256:... | |
| Running as root | Add USER nonroot | |
COPY . . | Use .dockerignore, copy specific files | |
| Secrets in ENV/ARG | Use build secrets or runtime injection | |
| No health check | Add HEALTHCHECK instruction | |
| Single-stage build | Use multi-stage builds |
Kubernetes
| Mistake | Fix | |
|---|---|---|
| No resource limits | Set resources.requests and resources.limits | |
| Running as root | securityContext.runAsNonRoot: true | |
latest image tag | Pin exact version or digest | |
| No liveness/readiness probes | Add probes matching app health endpoints | |
| Default namespace for workloads | Use dedicated namespaces with RBAC | |
| No network policies | Restrict pod-to-pod traffic with NetworkPolicy |
<rules>
Red Flags -- STOP
terraform apply -auto-approvewithout prior plan review- Security group with
0.0.0.0/0on non-HTTP ports - IAM policy with
*action or*resource - Secrets in
.tf,.yml, orDockerfile - State file committed to git
latesttag on any base image- Container running as root in production
</rules>
<examples>
Validation Finding Examples
Good Finding -- specific, shows the problem, gives the fix
**IaC-Critical: Overly permissive security group in modules/network/main.tf**Resource: aws_security_group_rule.allow_all (line 34)Problem: Ingress rule allows 0.0.0.0/0 on port 22 (SSH).This exposes SSH to the entire internet.Fix: Restrict to bastion host CIDR or VPN range:cidr_blocks = [var.vpn_cidr]Validation: `tfsec .` flagged this as HIGH severity (AWS018).
Bad Finding -- vague, no location, no evidence
**Security Issue: Network configuration may be too open.**Review the security groups for potential issues.
</examples>
Integration
Referenced by: shipyard:builder (detects IaC files, follows appropriate workflow), shipyard:verifier (IaC validation mode), shipyard:auditor (IaC security checks)
Pairs with: shipyard:security-audit (security lens for IaC), shipyard:shipyard-verification (IaC claims need validation evidence)