This GitHub Actions workflow template (docker-build.yml) provides a comprehensive solution for building, pushing, and securing Docker images. The workflow includes Dockerfile linting, multi-architecture builds, security scanning, and supports both OIDC and traditional AWS authentication methods for ECR.
- Dockerfile Linting: Uses Hadolint to check Dockerfile best practices and catch common mistakes
- Multi-Architecture Builds: Supports both AMD64 and ARM64 architectures using Docker Buildx
- Security Scanning: Integrates Trivy for container vulnerability scanning with SARIF upload to GitHub Security
- ECR Integration: Seamless integration with Amazon ECR for image storage
- OIDC Authentication: Secure authentication using OpenID Connect (recommended)
- Build Caching: Leverages Docker layer caching for faster builds
- BuildKit Support: Optional BuildKit support for improved build performance
- Dockerfile Linting: Runs Hadolint to validate Dockerfile syntax and best practices
- Docker Build: Builds the Docker image using Buildx with multi-architecture support
- ECR Authentication: Authenticates with AWS ECR using either OIDC or access keys
- Image Push: Pushes the built image to ECR with appropriate tags
- Security Scanning: Scans the built image for vulnerabilities using Trivy
- Results Upload: Uploads security scan results to GitHub Security tab
- Build Summary: Generates a comprehensive summary of the build process
Create a new workflow file in your repository (e.g., .github/workflows/docker.yml) with the following contents:
name: Build and Push Docker Image
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
docker:
uses: appvia/appvia-cicd-workflows/.github/workflows/docker-build.yml@main
with:
registry: docker.io
image-name: myimage
image-tag: v0.0.1
aws-account-id: 123456789012
aws-role: my-docker-build-role
enable-oidc: truename: Build and Push Docker Image
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
docker:
uses: appvia/appvia-cicd-workflows/.github/workflows/docker-build.yml@main
secrets:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
with:
registry: 123456789012.dkr.ecr.eu-west-2.amazonaws.com
image-name: myapplication
enable-oidc: falsename: Build and Push Docker Image
on:
push:
branches:
- main
tags:
- 'v*'
pull_request:
branches:
- main
jobs:
docker:
uses: appvia/appvia-cicd-workflows/.github/workflows/docker-build.yml@main
with:
aws-account-id: 123456789012
aws-region: eu-west-2
aws-role: my-docker-build-role
build-args: "NODE_ENV=production,BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
context-path: .
dockerfile-path: ./docker/Dockerfile
enable-buildkit: true
enable-oidc: true
enable-push: true
fail-on-vulnerabilities: true
registry: 123456789012.dkr.ecr.eu-west-2.amazonaws.com
image-name: myapplication
image-tag: v0.0.1
trivy-severity: "CRITICAL,HIGH"registry: Name of the registry (e.g.,123456789012.dkr.ecr.eu-west-2.amazonaws.com)image-name: The name of the image (e.g.,myapplication)
image-tag: Docker image name (defaults to the gitsha)
dockerfile-path: Path to Dockerfile (default:Dockerfile)context-path: Build context path (default:.)build-args: Docker build arguments as comma-separatedkey=valuepairscache-from: Cache from image tag (e.g.,latestor previous build tag)working-directory: Working directory for build (default:.)image-platforms: Platforms to build the image for (default:linux/amd64,linux/arm64)
aws-region: AWS region for ECR (default:eu-west-2)aws-account-id: AWS account ID (required ifenable-oidcistrue)aws-role: AWS IAM role name to assume (required ifenable-oidcistrue)enable-oidc: Use OIDC authentication (default:false)
enable-buildkit: Enable Docker BuildKit (default:true)enable-push: Push image to registry (default:true; automatically disabled for pull requests)
trivy-severity: Severity levels to fail on (default:CRITICAL,HIGH)trivy-version: Trivy version to use (default:latest)fail-on-vulnerabilities: Fail build if vulnerabilities found (default:true)
runs-on: GitHub runner to use (default:ubuntu-latest)
When using OIDC authentication (enable-oidc: true), no secrets are required. The workflow uses GitHub's OIDC provider to authenticate with AWS.
Prerequisites:
- AWS OIDC provider configured in your AWS account
- IAM role with trust policy allowing GitHub Actions to assume it
- IAM role with permissions to push/pull from ECR
Example IAM trust policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:your-org/your-repo:*"
}
}
}
]
}When using access keys (use-oidc: false), provide the following secrets:
aws-access-key-id: AWS Access Key IDaws-secret-access-key: AWS Secret Access Key
When not using OIDC or AWS credentials, you can also pass docker username and password credentials
docker-username: The username to use to logindocker-password: The password to use to authenticate to the registry
The workflow automatically generates tags based on:
- Branch name (for branch builds)
- Pull request number (for PR builds)
- Semantic version (for tag pushes matching
v*pattern) - Commit SHA (for default branch)
- Custom tag (if provided via
image-taginput)
Example tags:
main-abc1234(branch + SHA)pr-123(pull request)v1.2.3(semantic version)1.2(major.minor)
The workflow uses Trivy to scan built images for vulnerabilities. Results are:
- Displayed in the workflow summary
- Uploaded to GitHub Security tab as SARIF
- Can fail the build if critical/high vulnerabilities are found (configurable)
Create a .trivyignore file in your repository root to ignore specific vulnerabilities:
CVE-2021-12345
CVE-2021-67890
The workflow uses Hadolint to lint Dockerfiles. Common rules are automatically ignored:
DL3008: Pin versions in apt-get installDL3009: Delete the apt-get lists after installing
To customize ignored rules, you can create a .hadolint.yaml file in your repository.
The workflow supports Docker layer caching to speed up builds:
- Uses ECR as the cache backend
- Caches from a specified tag (via
cache-frominput) - Defaults to
latesttag if not specified
- Use OIDC Authentication: Prefer OIDC over access keys for better security
- Enable Security Scanning: Always enable security scanning in production
- Pin Versions: Use specific Trivy versions in production
- Review Vulnerabilities: Regularly review and address security findings
- Use Build Caching: Leverage caching for faster builds
- Multi-Architecture: The workflow builds for both AMD64 and ARM64 by default
OIDC Authentication:
- Verify the IAM role trust policy allows your repository
- Check that the OIDC provider is correctly configured
- Ensure the role has ECR permissions
Access Key Authentication:
- Verify secrets are correctly set in repository settings
- Check that the access key has ECR permissions
- Check Dockerfile syntax with Hadolint locally
- Verify build context includes all necessary files
- Review build logs for specific error messages
- Review vulnerabilities in the GitHub Security tab
- Add false positives to
.trivyignoreif needed - Update base images to resolve vulnerabilities
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload"
],
"Resource": "*"
}
]
}This workflow is distributed under the Apache License, Version 2.0.