Skip to content

Security

Security #57

Workflow file for this run

# yaml-language-server: $schema=https://www.schemastore.org/github-workflow.json
#
# Security Review: This workflow does NOT use any untrusted user inputs in run commands.
# All GitHub context usage is limited to safe values: needs.*.result and secrets.
name: Security
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
# Manual trigger from GitHub UI (runs on selected branch, typically main)
schedule:
# Run weekly on Monday at 6am UTC for drift detection
- cron: "0 6 * * 1"
# Cancel in-progress runs when new commits are pushed
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
# Trivy IaC scanning for misconfigurations
trivy-iac:
name: Trivy IaC Scan
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Run Trivy IaC scanner (Terraform)
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
with:
scan-type: "config"
scan-ref: "terraform/"
format: "sarif"
output: "trivy-terraform.sarif"
severity: "CRITICAL,HIGH,MEDIUM"
exit-code: "0"
version: "v0.60.0" # Pin to stable version (v0.65.0 has panic bugs)
- name: Run Trivy IaC scanner (Kubernetes)
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
with:
scan-type: "config"
scan-ref: "flux/"
format: "sarif"
output: "trivy-kubernetes.sarif"
severity: "CRITICAL,HIGH,MEDIUM"
exit-code: "0"
version: "v0.60.0" # Pin to stable version (v0.65.0 has panic bugs)
- name: Upload Trivy Terraform results
uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
with:
sarif_file: "trivy-terraform.sarif"
category: "trivy-terraform"
- name: Upload Trivy Kubernetes results
uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
with:
sarif_file: "trivy-kubernetes.sarif"
category: "trivy-kubernetes"
# Checkov compliance scanning
checkov:
name: Checkov Compliance
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Run Checkov on Terraform
uses: bridgecrewio/checkov-action@8f61ce5b8a3afb4ca94d236b75201878ded6d2cd # v12.3077.0
with:
directory: terraform/
framework: terraform
output_format: sarif
output_file_path: checkov-terraform.sarif
soft_fail: true
compact: true
quiet: true
skip_check: CKV_TF_1
- name: Run Checkov on Kubernetes
uses: bridgecrewio/checkov-action@8f61ce5b8a3afb4ca94d236b75201878ded6d2cd # v12.3077.0
with:
directory: flux/
framework: kubernetes
output_format: sarif
output_file_path: checkov-kubernetes.sarif
soft_fail: true
compact: true
quiet: true
# Skip Flux-generated gotk-components, flux-system directories (vendor code),
# and auto-generated dev registry patches (local development only)
skip_path: flux/clusters/dev-local/flux-system,flux/clusters/staging/flux-system,flux/clusters/production/flux-system,flux/apps/dev/registry-patch.yaml
# Skip checks that are handled elsewhere or intentional design choices:
# - CKV_K8S_14/43: Image tags managed by Flux image automation
# - CKV2_K8S_6: NetworkPolicies are CiliumNetworkPolicy in policies/
# - CKV_K8S_22: Dashboard needs writable fs for Next.js
# - CKV_K8S_35: Secrets as env vars is acceptable for optional config
skip_check: CKV_K8S_14,CKV_K8S_43,CKV2_K8S_6,CKV_K8S_22,CKV_K8S_35
- name: Upload Checkov Terraform results
uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
if: always()
with:
sarif_file: checkov-terraform.sarif
category: "checkov-terraform"
- name: Upload Checkov Kubernetes results
uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
if: always()
with:
sarif_file: checkov-kubernetes.sarif
category: "checkov-kubernetes"
# KICS (Keeping Infrastructure as Code Secure) scanning
kics:
name: KICS Security Scan
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Run KICS scan
uses: Checkmarx/kics-github-action@00def9108246ec656aea725db2167522d26a99d2 # v2.1.3
with:
path: "terraform/,flux/,policies/"
output_path: kics-results/
output_formats: "sarif"
fail_on: high
enable_comments: true
continue-on-error: true
- name: Upload KICS results
uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
if: always()
with:
sarif_file: kics-results/results.sarif
category: "kics"
# Security scan summary
security-summary:
name: Security Summary
needs: [trivy-iac, checkov, kics]
runs-on: ubuntu-latest
if: always()
permissions:
contents: read
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit
- name: Check security scan results
env:
TRIVY_RESULT: ${{ needs.trivy-iac.result }}
CHECKOV_RESULT: ${{ needs.checkov.result }}
KICS_RESULT: ${{ needs.kics.result }}
run: |
echo "## Security Scan Results"
echo ""
echo "| Scanner | Status |"
echo "|---------|--------|"
echo "| Trivy IaC | $TRIVY_RESULT |"
echo "| Checkov | $CHECKOV_RESULT |"
echo "| KICS | $KICS_RESULT |"
echo ""
echo "Secret scanning is handled by GitHub's native push protection."
# Fail if any security job failed
failed=false
if [[ "$TRIVY_RESULT" != "success" && "$TRIVY_RESULT" != "skipped" ]]; then
echo "❌ Trivy IaC scan failed"
failed=true
fi
if [[ "$CHECKOV_RESULT" != "success" && "$CHECKOV_RESULT" != "skipped" ]]; then
echo "❌ Checkov compliance scan failed"
failed=true
fi
if [[ "$KICS_RESULT" != "success" && "$KICS_RESULT" != "skipped" ]]; then
echo "❌ KICS security scan failed"
failed=true
fi
if [[ "$failed" == "true" ]]; then
echo ""
echo "❌ One or more security checks failed"
exit 1
fi
echo "✅ All security checks passed!"