Skip to content

Periodic Security Scan #1146

Periodic Security Scan

Periodic Security Scan #1146

Workflow file for this run

name: Periodic Security Scan
# Periodically scan production images for security vulnerabilities
on:
schedule:
# Once a day at midnight
- cron: '0 0 * * *'
# Once an hour
# - cron: '0 * * * *'
env:
# Name of image
IMAGE_NAME: foo-app
# Name of org in GHCR Docker repository (must be lowercase)
IMAGE_OWNER: ${{ github.repository_owner }}
# ECR Docker repo org name (may be blank, otherwise must have trailing slash)
ECR_IMAGE_OWNER: cogini/
# Tag for release images
# IMAGE_TAG: ${{ (github.ref == 'refs/heads/main' && 'staging') || (github.ref == 'refs/heads/qa' && 'qa') }}
IMAGE_TAG: latest
IMAGE_VER: ${{ github.sha }}
# Registry for test images
REGISTRY: ghcr.io/
# Registry for public images, default is docker.io
PUBLIC_REGISTRY: ''
# Give GitHub Actions access to AWS
AWS_ENABLED: 1
# AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
# AWS_ROLE_TO_ASSUME: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/cogini-foo-dev-app-github-action
# AWS_REGION: us-east-1
# S3_BUCKET_ASSETS: cogini-foo-app-dev-app-assets
# CLOUDFRONT_CDN_DISTRIBUTION_ID: XXXX
# S3_BUCKET_CI: cogini-prod-foo-ci
# Health check port for app
APP_PORT: 4000
# Datadog
# DD_API_KEY: ${{ secrets.ACTIONS_DD_API_KEY }}
# DD_ENV: ci
# DD_TAGS: "environment:ci"
# MIX_ENV: foo
ELIXIR_MODULE: PhoenixContainerExample
ECS_CLUSTER: foo
ECS_SERVICE: foo-app
ECS_CONTAINER: foo-app
CODEDEPLOY_APPLICATION: foo-app
CODEDEPLOY_DEPLOYMENT_GROUP: foo-app-ecs
TASKDEF: ecs/task-definition.json
ECS_SERVICE_WORKER: foo-worker
ECS_CONTAINER_WORKER: foo-worker
TASKDEF_WORKER: ecs/task-definition.worker.json
APPSPEC: ecs/appspec.yml
# AWS SSM Parameter Store name prefix
# AWS_PS_PREFIX: cogini/foo/dev
# Name of environment for resources created by Terraform
# TERRAFORM_ENV: dev
# TASK_ROLE_ARN: "arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/foo-app"
# EXECUTION_ROLE_ARN: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/foo-ecs-task-execution-role
# GitHub Advanced Security, free for open source, otherwise a paid feature
# https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security
# https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning
# https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github
GITHUB_ADVANCED_SECURITY: 0
DEPLOY_DOCKER_HUB: 0
# Docker
DOCKER_BUILDKIT: '1'
COMPOSE_DOCKER_CLI_BUILD: '1'
COMPOSE_FILE: docker-compose.gha.yml
DOCKER_FILE: deploy/debian.Dockerfile
jobs:
setup-matrix:
name: Set up build matrix
runs-on: ubuntu-latest
outputs:
test-matrix: ${{ steps.common-matrix.outputs.result }}
prod-matrix: ${{ steps.prod-matrix.outputs.result }}
deploy-matrix: ${{ steps.deploy-matrix.outputs.result }}
assets-matrix: ${{ steps.assets-matrix.outputs.result }}
steps:
- uses: actions/github-script@v7
id: common-matrix
# Specify versions of Erlang, Elixir, and base OS
# in a combination supported by https://hub.docker.com/r/hexpm/elixir/tags
with:
script: |
return {
include: [
{
elixir: "1.17.1",
otp: "27.0",
build_os_ver: "bookworm-20240612",
prod_os_ver: "bookworm-slim",
os: "debian"
},
{
elixir: "1.16.3",
otp: "26.2.5",
build_os_ver: "bullseye-20240513",
prod_os_ver: "bullseye-slim",
os: "debian"
}
]
}
# druzan/setup-matrix is slow, taking about 15 seconds to initialize
# - name: Define matrix for test containers
# id: test-matrix
# uses: druzsan/setup-matrix@v2
# with:
# matrix: |
# include:
# - elixir: 1.16.3
# otp: 26.2.5
# build_os_ver: bullseye-20240513
# prod_os_ver: bullseye-slim
# os: debian
- uses: actions/github-script@v7
id: prod-matrix
with:
script: |
return {
include: [
{
elixir: "1.17.1",
otp: "27.0",
build_os_ver: "bookworm-20240612",
prod_os_ver: "bookworm-slim",
os: "debian"
},
{
elixir: "1.17.1",
otp: "27.0",
build_os_ver: "bookworm-20240612",
prod_os_ver: "bookworm-slim",
os: "distroless"
}
]
}
- uses: actions/github-script@v7
id: deploy-matrix
with:
script: |
return {
include: [
{
elixir: "1.17.1",
otp: "27.0",
build_os_ver: "bookworm-20240612",
prod_os_ver: "bookworm-slim",
os: "debian"
}
]
}
- uses: actions/github-script@v7
id: assets-matrix
# Specify versions of Erlang, Elixir, and base OS
# in a combination supported by https://hub.docker.com/r/hexpm/elixir/tags
with:
script: |
return {
include: [
{
elixir: "1.17.1",
otp: "27.0",
build_os_ver: "bookworm-20240612",
prod_os_ver: "bookworm-slim",
os: "debian"
}
]
}
scan:
name: Security scan prod image
needs: [setup-matrix]
permissions:
# Interact with GitHub OIDC Token endpoint for AWS
id-token: write
contents: read
# Read from ghcr.io repository
packages: read
# Upload JUnit report files
# https://github.com/EnricoMi/publish-unit-test-result-action#permissions
checks: write
pull-requests: write
issues: read
# Upload SARIF report files
security-events: write
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup-matrix.outputs.prod-matrix) }}
env:
DOCKER_FILE: deploy/${{ matrix.os }}.Dockerfile
VAR: ${{ matrix.elixir }}-erlang-${{ matrix.otp }}-${{ matrix.os }}-${{ matrix.build_os_ver }}
steps:
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Pull image
run: docker pull ghcr.io/${{env.IMAGE_OWNER}}/${{env.IMAGE_NAME}}:${{ env.VAR }}${{ env.IMAGE_VER }}
- name: Scan image with Trivy
uses: aquasecurity/trivy-action@master
# https://github.com/aquasecurity/trivy-action
# https://github.com/marketplace/actions/aqua-security-trivy#inputs
with:
image-ref: ghcr.io/${{env.IMAGE_OWNER}}/${{env.IMAGE_NAME}}:${{ env.VAR }}${{ env.IMAGE_VER }}
# exit-code: '1' # fail build
# ignore-unfixed: true
# vuln-type: 'os,library'
# severity: 'CRITICAL,HIGH'
# cache-dir: /var/cache
# format: 'sarif'
format: 'table'
# format: ${{ env.GITHUB_ADVANCED_SECURITY == 1 && 'sarif' || 'table' }}
output: 'trivy.sarif'
- name: Display scan results
if: ${{ always() && env.GITHUB_ADVANCED_SECURITY == 1 }}
run: cat trivy.sarif | jq .
- name: Upload Trivy scan results to GitHub Security tab
if: ${{ always() && env.GITHUB_ADVANCED_SECURITY == 1 }}
uses: github/codeql-action/upload-sarif@v3
# Requires GitHub Advanced Security
# https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security
# https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning
# https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github
with:
sarif_file: 'trivy.sarif'
category: trivy
- name: Scan image with Grype
uses: anchore/scan-action@v3
# https://github.com/marketplace/actions/anchore-container-scan
id: scan-grype
with:
image: ghcr.io/${{env.IMAGE_OWNER}}/${{env.IMAGE_NAME}}:${{ env.VAR }}${{ env.IMAGE_VER }}
# severity-cutoff: critical
fail-build: false
# output-format: 'sarif'
output-format: table
# output-format: ${{ env.GITHUB_ADVANCED_SECURITY == 1 && 'sarif' || 'table' }}
- name: Display scan results
if: ${{ always() && env.GITHUB_ADVANCED_SECURITY == 1 }}
run: cat ${{ steps.scan-grype.outputs.sarif }} | jq .
- name: Upload Grype scan results to GitHub Security tab
if: ${{ always() && env.GITHUB_ADVANCED_SECURITY == 1 }}
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: ${{ steps.scan-grype.outputs.sarif }}
category: grype
# - name: Scan image with snyk
# # if: github.event_name != 'pull_request'
# uses: snyk/actions/docker@master
# continue-on-error: true
# env:
# SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
# with:
# command: test
# image: ghcr.io/${{ env.IMAGE_OWNER }}/${{ env.IMAGE_NAME }}:${{ env.VAR }}${{ env.IMAGE_VER }}
# args: --file=${{ env.DOCKER_FILE }} --project-name=api