โ† All cheat sheets

IAC-SECURITY

Authorized use only. Offensive reference for systems you own or are explicitly permitted to test. You are responsible for staying within the law.

Security scanning, hardening, and best practices for Terraform,
Ansible, CloudFormation, Kubernetes, and policy-as-code frameworks.

TERRAFORM SECURITY#

Common Terraform Misconfigurations:

  1. Public S3 buckets:
     # BAD
     resource "aws_s3_bucket_acl" "example" {
       acl = "public-read"
     }
     # GOOD
     resource "aws_s3_bucket_public_access_block" "example" {
       bucket                  = aws_s3_bucket.example.id
       block_public_acls       = true
       block_public_policy     = true
       ignore_public_acls      = true
       restrict_public_buckets = true
     }

  2. Open security groups:
     # BAD
     ingress {
       from_port   = 0
       to_port     = 0
       protocol    = "-1"
       cidr_blocks = ["0.0.0.0/0"]
     }
     # GOOD
     ingress {
       from_port   = 443
       to_port     = 443
       protocol    = "tcp"
       cidr_blocks = ["10.0.0.0/8"]
     }

  3. Unencrypted resources:
     # BAD - no encryption
     resource "aws_ebs_volume" "example" {
       availability_zone = "us-east-1a"
       size              = 40
     }
     # GOOD
     resource "aws_ebs_volume" "example" {
       availability_zone = "us-east-1a"
       size              = 40
       encrypted         = true
       kms_key_id        = aws_kms_key.example.arn
     }

  4. Hardcoded secrets in .tf files:
     # BAD
     password = "SuperSecret123"
     # GOOD
     password = var.db_password  # from tfvars or vault

  5. Missing logging:
     # Ensure CloudTrail, VPC flow logs, S3 access logging enabled

tfsec (Aqua Security):
  Installation:
    brew install tfsec
    # or
    go install github.com/aquasecurity/tfsec/cmd/tfsec@latest

  Usage:
    tfsec .                                  # scan current directory
    tfsec . --format json                    # JSON output
    tfsec . --severity HIGH,CRITICAL         # filter by severity
    tfsec . --exclude-downloaded-modules     # skip modules
    tfsec . --config-file tfsec.yml          # custom config

  Ignore specific findings:
    resource "aws_s3_bucket" "example" {
      #tfsec:ignore:aws-s3-enable-versioning
      bucket = "my-bucket"
    }

  CI/CD (GitHub Actions):
    - name: tfsec
      uses: aquasecurity/tfsec-action@v1.0.3
      with:
        soft_fail: false

Checkov (Bridgecrew/Prisma Cloud):
  Installation:
    pip install checkov

  Usage:
    checkov -d .                             # scan directory
    checkov -f main.tf                       # scan specific file
    checkov -d . --framework terraform       # Terraform only
    checkov -d . --check CKV_AWS_18          # specific check
    checkov -d . --skip-check CKV_AWS_18     # skip check
    checkov -d . -o json                     # JSON output
    checkov -d . --compact                   # compact output

  Supported frameworks:
    terraform, cloudformation, kubernetes, arm, helm,
    dockerfile, serverless, bicep, openapi, github_actions

  CI/CD (GitHub Actions):
    - name: Checkov
      uses: bridgecrewio/checkov-action@master
      with:
        directory: terraform/
        framework: terraform

Terraform state security:
  - Store state in encrypted remote backend (S3 + DynamoDB)
  - Enable state locking
  - Restrict access to state files (contain secrets)
  - Use terraform plan output review before apply
  - Enable audit logging on state backend

  # Secure S3 backend
  terraform {
    backend "s3" {
      bucket         = "terraform-state-prod"
      key            = "infra/terraform.tfstate"
      region         = "us-east-1"
      encrypt        = true
      dynamodb_table = "terraform-locks"
      kms_key_id     = "arn:aws:kms:..."
    }
  }

ANSIBLE HARDENING#

Security best practices:

  1. Use Ansible Vault for secrets:
     ansible-vault create secrets.yml
     ansible-vault edit secrets.yml
     ansible-vault encrypt_string 'mypassword' --name 'db_password'
     ansible-playbook site.yml --ask-vault-pass

  2. Least privilege:
     - Use become only when needed
     - Don't run everything as root
     - Use become_method: sudo with specific commands

  3. Avoid shell/command modules when possible:
     # BAD
     - shell: "useradd -m {{ username }}"
     # GOOD
     - user:
         name: "{{ username }}"
         state: present
         create_home: yes

  4. Validate input:
     - assert:
         that:
           - username is match("^[a-zA-Z0-9_]+$")
           - port | int > 0
           - port | int < 65536

  5. Security-focused roles:
     - dev-sec.os-hardening (CIS benchmarks)
     - dev-sec.ssh-hardening
     - geerlingguy.firewall

  Ansible-lint security rules:
    pip install ansible-lint
    ansible-lint playbook.yml
    # Checks for: command/shell usage, become misuse,
    # hardcoded passwords, insecure permissions

CLOUDFORMATION SECURITY#

Common misconfigurations:
  1. IAM policies with wildcards:
     # BAD
     Statement:
       - Effect: Allow
         Action: "*"
         Resource: "*"
     # GOOD
     Statement:
       - Effect: Allow
         Action:
           - s3:GetObject
           - s3:PutObject
         Resource: "arn:aws:s3:::my-bucket/*"

  2. Unencrypted resources:
     # Ensure encryption on RDS, EBS, S3, SQS, SNS, etc.
     Properties:
       StorageEncrypted: true
       KmsKeyId: !Ref MyKmsKey

  3. Public access:
     # Check SecurityGroupIngress for 0.0.0.0/0
     # Check S3 bucket policies
     # Check RDS PubliclyAccessible: false

Scanning tools:
  cfn-lint:
    pip install cfn-lint
    cfn-lint template.yaml

  cfn-nag:
    gem install cfn-nag
    cfn_nag_scan --input-path template.yaml

  checkov:
    checkov -f template.yaml --framework cloudformation

KUBERNETES MANIFEST SECURITY#

Common misconfigurations:

  1. Running as root:
     # BAD
     securityContext: {}
     # GOOD
     securityContext:
       runAsNonRoot: true
       runAsUser: 1000
       allowPrivilegeEscalation: false
       readOnlyRootFilesystem: true
       capabilities:
         drop: ["ALL"]

  2. Missing resource limits:
     # GOOD
     resources:
       limits:
         memory: "256Mi"
         cpu: "500m"
       requests:
         memory: "128Mi"
         cpu: "250m"

  3. Missing network policies:
     # Default deny all ingress
     apiVersion: networking.k8s.io/v1
     kind: NetworkPolicy
     metadata:
       name: default-deny-ingress
     spec:
       podSelector: {}
       policyTypes:
         - Ingress

  4. Using latest tag:
     # BAD
     image: nginx:latest
     # GOOD
     image: nginx:1.25.3@sha256:abc123...

  5. Secrets in environment variables:
     # BAD
     env:
       - name: DB_PASSWORD
         value: "plaintext_password"
     # GOOD - use Secrets with mounted volumes
     env:
       - name: DB_PASSWORD
         valueFrom:
           secretKeyRef:
             name: db-secret
             key: password

kubesec:
  # Online
  curl -sSX POST --data-binary @deployment.yaml https://v2.kubesec.io/scan

  # Local
  docker run -i kubesec/kubesec:v2 scan /dev/stdin < deployment.yaml

  # Scores security posture of manifests (0-100+)

kube-bench (CIS Benchmarks):
  docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro \
    aquasec/kube-bench:latest run

kube-hunter (penetration testing):
  docker run -it --rm aquasec/kube-hunter --remote <cluster_ip>

Trivy for Kubernetes:
  trivy k8s --report=summary cluster          # scan running cluster
  trivy config ./k8s-manifests/               # scan manifest files

COMMON MISCONFIGURATIONS CHECKLIST#

AWS:
  [ ] S3 buckets public access blocked
  [ ] S3 bucket versioning enabled
  [ ] S3 bucket encryption enabled (SSE-S3 or SSE-KMS)
  [ ] EBS volumes encrypted
  [ ] RDS instances encrypted and not publicly accessible
  [ ] RDS automated backups enabled
  [ ] Security groups: no 0.0.0.0/0 on SSH (22) or RDP (3389)
  [ ] CloudTrail enabled in all regions
  [ ] VPC flow logs enabled
  [ ] IAM: no wildcard (*) policies
  [ ] IAM: MFA enforced for console access
  [ ] IAM: access keys rotated regularly
  [ ] ELB/ALB using TLS 1.2+
  [ ] Lambda functions not using admin IAM roles
  [ ] SNS/SQS encrypted
  [ ] Secrets in Secrets Manager or Parameter Store (not env vars)

Azure:
  [ ] Storage accounts: no public blob access
  [ ] Storage accounts: encryption enabled
  [ ] NSGs: no open management ports
  [ ] SQL Server: auditing enabled
  [ ] Key Vault: soft delete enabled
  [ ] Activity log alerts configured

GCP:
  [ ] Cloud Storage: no allUsers/allAuthenticatedUsers
  [ ] Compute: no default service account
  [ ] VPC: firewall rules reviewed
  [ ] Cloud SQL: no public IP
  [ ] Audit logging enabled

POLICY-AS-CODE#

Open Policy Agent (OPA):
  Concept: General-purpose policy engine using Rego language.

  Example Rego policy (deny public S3):
    package terraform.aws

    deny[msg] {
      resource := input.resource_changes[_]
      resource.type == "aws_s3_bucket_acl"
      resource.change.after.acl == "public-read"
      msg := sprintf("S3 bucket '%s' must not be public", [resource.name])
    }

  Usage with conftest:
    pip install conftest
    conftest test main.tf -p policy/
    conftest test deployment.yaml -p policy/

  Kubernetes admission control (OPA Gatekeeper):
    # Install Gatekeeper
    kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.14/deploy/gatekeeper.yaml

    # Create constraint template
    apiVersion: templates.gatekeeper.sh/v1
    kind: ConstraintTemplate
    metadata:
      name: k8srequiredlabels
    spec:
      crd:
        spec:
          names:
            kind: K8sRequiredLabels
          validation:
            openAPIV3Schema:
              type: object
              properties:
                labels:
                  type: array
                  items:
                    type: string

HashiCorp Sentinel:
  Concept: Policy-as-code for HashiCorp products (Terraform Cloud/Enterprise)

  Example policy:
    import "tfplan/v2" as tfplan

    main = rule {
      all tfplan.resource_changes as _, rc {
        rc.type is "aws_security_group_rule" implies
          rc.change.after.cidr_blocks not contains "0.0.0.0/0"
      }
    }

  Enforcement levels:
    - advisory:  warn but allow
    - soft-mandatory: can be overridden
    - hard-mandatory: cannot be overridden

Kyverno (Kubernetes-native):
  # Simpler alternative to OPA for Kubernetes
  apiVersion: kyverno.io/v1
  kind: ClusterPolicy
  metadata:
    name: disallow-latest-tag
  spec:
    validationFailureAction: Enforce
    rules:
      - name: require-image-tag
        match:
          any:
            - resources:
                kinds:
                  - Pod
        validate:
          message: "Using 'latest' tag is not allowed."
          pattern:
            spec:
              containers:
                - image: "!*:latest"

SCANNING PIPELINE SETUP#

Recommended IaC security pipeline:

  1. Pre-commit:
     - tflint (Terraform linting)
     - terraform fmt -check
     - checkov (quick scan)

  2. CI/CD Pipeline:
     - terraform plan (save plan file)
     - tfsec / checkov on plan file
     - conftest with OPA policies
     - Trivy config scan
     - Block deploy on critical findings

  3. Runtime:
     - AWS Config Rules / Azure Policy
     - Cloud Custodian (automated remediation)
     - Prisma Cloud / Wiz (CSPM)

  Example pre-commit config (.pre-commit-config.yaml):
    repos:
      - repo: https://github.com/antonbabenko/pre-commit-terraform
        rev: v1.86.0
        hooks:
          - id: terraform_fmt
          - id: terraform_validate
          - id: terraform_tflint
          - id: terraform_tfsec
          - id: terraform_checkov

  GitHub Actions full pipeline:
    jobs:
      iac-security:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - name: tfsec
            uses: aquasecurity/tfsec-action@v1.0.3
          - name: Checkov
            uses: bridgecrewio/checkov-action@master
            with:
              directory: terraform/
          - name: Trivy Config
            uses: aquasecurity/trivy-action@master
            with:
              scan-type: 'config'
              scan-ref: '.'

REFERENCES#

- tfsec: https://aquasecurity.github.io/tfsec/
- Checkov: https://www.checkov.io/
- OPA: https://www.openpolicyagent.org/
- Kyverno: https://kyverno.io/
- CIS Benchmarks: https://www.cisecurity.org/benchmark
- Trivy: https://aquasecurity.github.io/trivy/
- Cloud Custodian: https://cloudcustodian.io/