Skip to content

Commit

Permalink
feat: Define reusable workflow for building images and signing
Browse files Browse the repository at this point in the history
  • Loading branch information
neumachen committed Jan 22, 2025
1 parent 5cb0295 commit fc5c253
Show file tree
Hide file tree
Showing 9 changed files with 813 additions and 2 deletions.
9 changes: 9 additions & 0 deletions .actrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
--rm
--reuse
--container-options=--privileged
--pull=false
--platform=ubuntu-latest=catthehacker/ubuntu:custom-20.04
--container-architecture=linux/amd64
--workflows=./.github/workflows
--secret-file=./.act.secrets
--eventpath=./.act.event.json
190 changes: 190 additions & 0 deletions .github/actions/build-container-image/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Copyright 2024 Specter Ops, Inc.
#
# Licensed under the Apache License, Version 2.0
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
---
name: Build and Publish Container Image

description: |-
This composite action builds a container image based on the specified Dockerfile and metadata.
It can optionally push the built image to a container registry.
Ensure you have the necessary Docker and QEMU setup steps in your workflow for cross-platform builds.
inputs:
dockerhub_account:
required: true
description: |-
The DockerHub username or account name used for authentication.
This account must have permissions to push images to the specified repositories.
Example: 'organization_name' or 'username'
dockerhub_token:
required: true
description: |-
The authentication token or password for the DockerHub account.
Use a personal access token or deploy token for enhanced security.
This token must have appropriate permissions for pulling and pushing images.
ghcr_account:
required: true
description: |-
The GitHub Container Registry (GHCR) username or account name.
Usually this is your GitHub username or organization name.
Must have permissions to push containers to the specified GHCR repositories.
Example: 'github_username' or 'organization_name'
ghcr_token:
required: true
description: |-
The GitHub personal access token (PAT) for authenticating with GitHub Container Registry.
Token must have the necessary permissions:
- read:packages
- write:packages
- delete:packages (if image overwriting is needed)
build_platforms:
required: true
default: "linux/amd64,linux/arm64"
description: |-
Comma-separated list of target platforms for the container build.
Specifies the CPU architectures and operating systems for which
the container image should be built.
Examples:
- "linux/amd64" for x86_64 Linux only
- "linux/amd64,linux/arm64" for both x86_64 and ARM64 Linux
- "linux/amd64,linux/arm64,linux/arm/v7" for additional ARM support
image_labels:
required: true
default: "false"
description: |-
A JSON object containing image labels and metadata.
These labels help describe the image and can include information like
version, author, and licenses.
image_tags:
required: true
default: "false"
description: |-
A comma-separated list of tags to assign to the built image.
These tags help identify different versions or variants of the image.
image_provenance:
required: true
default: "false"
description: |-
Whether to include image provenance information in the image metadata.
Provenance information provides details about how the image was built and can be useful for auditing.
image_sbom:
required: true
default: "false"
description: |-
Whether to include a Software Bill of Materials (SBOM) in the image metadata.
An SBOM lists all the software components used in the image, enhancing transparency and security.
dockerfile:
default: Dockerfile
description: |-
The name of the Dockerfile used for building the container image.
If not specified, it defaults to 'Dockerfile' in the repository root.
Example: 'Dockerfile.prod' for a production-specific Dockerfile.
build_context:
default: "{{defaultContext}}"
description: |-
Build's context is the set of files located in the specified PATH or URL (default Git context)
build_target:
description: |-
The build stage target for multi-stage Docker builds, if applicable.
Specify this if your Dockerfile has multiple stages, and you want to build a specific one.
Example: 'production' for a multi-stage Dockerfile with a 'production' stage.
build_args:
description: |-
Additional build arguments to pass to the Docker build process.
These arguments can be used to customize the build based on your requirements.
Example: 'MY_VARIABLE=value' to set an environment variable during the build.
build_contexts:
description: |-
Additional build contexts to pass to Docker build process.
Define additional build context with specified contents. In Dockerfile the
context can be accessed when FROM name or --from=name is used. When
Dockerfile defines a stage with the same name it is overwritten.
Example: 'name=path'
build_outputs:
required: true
description: |-
Set build outputs.
cache_from:
description: |-
The source image repository from which to cache layers during the build.
This can help improve build speed by reusing layers from a previously built image.
Default: type=gha
Example: 'docker.io/my-app:cache' to cache from a specific image.
default: |-
type=gha
cache_to:
description: |-
The destination image cache settings to optimize the caching strategy during the build.
This input specifies where to store cached layers and how they are scoped.
Default: type=gha,mode=max
Example: "type=gha,mode=max,scope=\$\{\{ github.workflow \}\}"
default: |-
type=gha,mode=max
runs:
using: composite
steps:
- uses: docker/login-action@v3
name: Authenticate with DockerHub Registry
with:
registry: docker.io
username: ${{ inputs.dockerhub_account }}
password: ${{ inputs.dockerhub_token }}

- uses: docker/login-action@v3
name: Authenticate with GitHub Container Registry
with:
registry: ghcr.io
username: ${{ inputs.ghcr_account }}
password: ${{ inputs.ghcr_token }}

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: ${{ inputs.build_platforms }}

- name: Set up buildx
id: buildx
uses: docker/setup-buildx-action@v3
with:
platforms: ${{ inputs.build_platforms }}

- name: Build
uses: docker/build-push-action@v6
with:
build-args: ${{ inputs.build_args }}
build-contexts: ${{ inputs.build_contexts }}
cache-from: ${{ inputs.cache_from }}
cache-to: ${{ inputs.cache_to }}
context: ${{ inputs.build_context }}
file: ${{ inputs.dockerfile }}
labels: ${{ inputs.image_labels }}
outputs: ${{ inputs.build_outputs }}
provenance: ${{ inputs.image_provenance }}
sbom: ${{ inputs.image_sbom }}
tags: ${{ inputs.image_tags }}
target: ${{ inputs.build_target }}
99 changes: 99 additions & 0 deletions .github/actions/container-image-metadata/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Copyright 2024 Specter Ops, Inc.
#
# Licensed under the Apache License, Version 2.0
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
---
name: Generate Container Image Metadata

description: |-
This composite action generates metadata for a container image and extracts useful information,
such as JSON data, tags, labels, revision, version, and the container image reference.
The metadata is essential for tracking and managing container images effectively.
inputs:
container_image_repository_name:
required: true
description: |-
TBD ...
image_flavor:
description: |-
See: https://github.com/docker/metadata-action#flavor-input
image_tags:
description: |-
See: https://github.com/docker/metadata-action#tags-input
outputs:
json:
value: ${{ steps.generate-metadata.outputs.json }}
description: |-
The JSON metadata for the container image, including details about the image and its layers.
tags:
value: ${{ steps.generate-metadata.outputs.tags }}
description: |-
A list of tags associated with the container image, which may include version and branch information.
labels:
value: ${{ steps.generate-metadata.outputs.labels }}
description: |-
Custom labels associated with the container image, providing additional information and metadata.
revision:
value: ${{ fromJSON(steps.generate-metadata.outputs.json).labels['org.opencontainers.image.revision'] }}
description: |-
The revision of the container image, if available, typically extracted from metadata labels.
version:
value: ${{ steps.generate-metadata.outputs.version }}
description: |-
The version of the container image, often derived from tags or other versioning patterns.
image_reference:
value: ${{ steps.set-image-reference.outputs.image_reference }}
description: |-
The full image reference, including registry, repository, and tag.
This fully qualified name is used to pull or locate a specific image
from a particular registry (e.g., docker.io/myrepo/myimage:tag).
image_name:
value: ${{ steps.set-image-reference.outputs.image_name }}
description: |-
The image name with repository and tag, typically used locally or
with the default registry. This shorthand version omits the registry
and assumes the default registry if unspecified (e.g., myimage:tag).
runs:
using: composite
steps:
- name: Generate metadata
id: generate-metadata
uses: docker/metadata-action@v5
with:
images: ${{ inputs.container_image_repository_name }}
flavor: ${{ inputs.image_flavor }}
tags: |-
type=raw,value=sha-{{sha}}-{{date 'YYYYMMDD-HHmmss'}},priority=1500
type=sha,format=long,priority=1450
${{ inputs.image_tags }}
- name: Set Container Image Reference
id: set-image-reference
shell: bash
run: |-
image_reference=${{ fromJSON(steps.generate-metadata.outputs.json).tags[0] }}
echo "image_reference=$image_reference" >> $GITHUB_OUTPUT
image_name=$(echo "$image_reference" | sed 's/.*\///')
echo "image_name=$image_name" >> $GITHUB_OUTPUT
65 changes: 65 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
# Copyright 2024 Specter Ops, Inc.
#
# Licensed under the Apache License, Version 2.0
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
name: Continuous Deployment (CD)

on:
push:
branches:
- main
- develop
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+rc[0-9]+'

jobs:
bloodhound-container-image:
name: Build and Publish BloodHound Container Image
uses: ./.github/workflows/reusable.build-container-image.yml
with:
container_image_repository_name: docker.io/specterops/bloodhound
image_sbom: true
image_provenance: mode=max
build_target: bloodhound
build_outputs: type=image,push=true
dockerfile: dockerfiles/bloodhound.Dockerfile
image_cache_from: |-
type=registry,ref=docker.io/specterops/bloodhound:buildcache
type=registry,ref=ghcr.io/specterops/bloodhound:buildcache
image_cache_to: |-
type=registry,ref=docker.io/specterops/bloodhound:buildcache,mode=max
type=registry,ref=ghcr.io/specterops/bloodhound:buildcache,mode=max
secrets:
dockerhub_account: ${{ secrets.DOCKERHUB_USERNAME }}
dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }}
ghcr_account: ${{ github.actor }}
ghcr_token: ${{ secrets.GITHUB_TOKEN }}
gh_access_token: ${{ secrets.GITHUB_TOKEN }}

docker-content-trust-sign-image:
needs: bloodhound-container-image
name: Sign Docker Image using Docker Content Trust
uses: ./.github/workflows/reusable.docker-content-trust.yml
with:
dockerhub_image_reference: ${{ needs.bloodhound-container-image.outputs.image_reference }}
secrets:
dockerhub_account: ${{ secrets.DOCKERHUB_USERNAME }}
dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }}
gh_access_token: ${{ secrets.GITHUB_TOKEN }}
docker_content_trust_repository_key_id: ${{ secrets.DOCKER_CONTENT_TRUST_REPOSITORY_KEY_ID }}
docker_content_trust_repository_passphrase: ${{ secrets.DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE }}
docker_content_trust_repository_key: ${{ secrets.DOCKER_CONTENT_TRUST_REPOSITORY_KEY }}
docker_content_trust_repository_public_key: ${{ secrets.DOCKER_CONTENT_TRUST_REPOSITORY_PUBLIC_KEY }}
Loading

0 comments on commit fc5c253

Please sign in to comment.