GitHub Actions Integration
GitHub Actions Integration
GitHub Actions provides native CI/CD capabilities that integrate seamlessly with container scanning tools. Here's a comprehensive workflow that implements multi-stage security validation:
name: Secure Container Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
dockerfile-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Lint Dockerfile
uses: hadolint/[email protected]
with:
dockerfile: Dockerfile
failure-threshold: warning
- name: Check for secrets in code
uses: trufflesecurity/[email protected]
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
build-and-scan:
needs: dockerfile-lint
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
security-events: write
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Log in to Container Registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=sha,prefix={{branch}}-
- name: Build Docker image
uses: docker/build-push-action@v4
with:
context: .
push: false
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
outputs: type=docker,dest=/tmp/image.tar
- name: Load image for scanning
run: |
docker load --input /tmp/image.tar
echo "IMAGE_TAG=$(echo ${{ steps.meta.outputs.tags }} | head -n1)" >> $GITHUB_ENV
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.IMAGE_TAG }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy scan results to GitHub Security
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
- name: Run Snyk scan
uses: snyk/actions/docker@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
image: ${{ env.IMAGE_TAG }}
args: --severity-threshold=high --file=Dockerfile
- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
image: ${{ env.IMAGE_TAG }}
format: cyclonedx-json
output-file: sbom.json
- name: Security gate decision
run: |
# Parse Trivy results
CRITICAL_COUNT=$(docker run --rm -v $(pwd):/src aquasec/trivy:latest \
image --format json --severity CRITICAL ${{ env.IMAGE_TAG }} | \
jq '[.Results[]?.Vulnerabilities[]? | select(.Severity=="CRITICAL")] | length')
if [ "$CRITICAL_COUNT" -gt "0" ]; then
echo "❌ Found $CRITICAL_COUNT critical vulnerabilities"
exit 1
else
echo "✅ No critical vulnerabilities found"
fi
- name: Push image if secure
if: success() && github.event_name != 'pull_request'
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
policy-validation:
needs: build-and-scan
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v3
- name: Validate Kubernetes manifests
run: |
# Install tools
curl -LO https://github.com/kubesec/kubesec/releases/download/v2.11.5/kubesec_linux_amd64.tar.gz
tar -xzf kubesec_linux_amd64.tar.gz
# Scan manifests
./kubesec scan k8s/*.yaml
- name: OPA Policy check
uses: open-policy-agent/opa-action@v2
with:
path: k8s/
policy: .github/policies/