Grave brecha de Trivy en Github Actions amenaza tus secretos, tokens, credenciales e incluso tus artefactos, qué debes hacer y saber
la ironía de la seguridad: las github actions de trivy secuestradas (otra vez) En un giro del destino que haría
A complete, step-by-step guide to building multi-arch Docker images like a pro, using native GitHub Runners and leaving QEMU in the dust. Now go forth and conquer the world of multi-architecture deployments!
In the cutthroat world of DevOps, where speed and efficiency are the holy grail, building multi-architecture Docker images used to be a pain in the neck. But hold on tight! With the advent of native GitHub runners, you can finally ditch the quirky QEMU emulation and embrace the lightning speed of native builds. This guide will take you by the hand and lead you through the dark arts of setting up a multi-architecture build process using GitHub Actions.
This workflow is like a two-headed beast, split into two main jobs:
This two-step process results in a "fat" image – a monstrous creation that delivers the right binary for any user's architecture, no questions asked.
.github/workflows/multi-build.yaml as needed.Let's dissect this beast, shall we?
name: Build multi arch Docker Image with separate Github Runners
on:
workflow_dispatch:
push:
branches:
- main
paths:
- 'Dockerfile'
- '.github/workflows/multi-build.yaml'
env:
GHCR_IMAGE: ghcr.io/${{ github.repository }}
#(...)
GHCR_IMAGE: Defines the name of the Docker image to be built and pushed to GHCR. The image name is cleverly derived from the GitHub repository name and the GHCR URL, resulting in a format like ghcr.io/owner/repo.# (...)
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
#(...)
permissions: Sets global permissions for the workflow. These can be overridden at the job level if needed.concurrency: This ensures that only one job in the group runs at a time. If a new job is triggered, the previous one is mercilessly canceled.# (...)
jobs:
build:
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
permissions:
attestations: write
actions: read
checks: write
contents: write
deployments: none
id-token: write
issues: read
discussions: read
packages: write
pages: none
pull-requests: read
repository-projects: read
security-events: read
statuses: read
#(...)
build: This job is the workhorse, building the Docker image for each platform specified in the matrix.matrix: Defines the platforms: linux/amd64 and linux/arm64. The build job will run for each of these platforms.permissions: Sets specific permissions for the build job, allowing it to write to GHCR and read from the repository.# (...)
runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-latest' || matrix.platform == 'linux/arm64' && 'ubuntu-24.04-arm' }}
#(...)
runs-on: This cleverly selects the appropriate runner based on the platform:linux/amd64, it uses the latest Ubuntu runner.linux/arm64, it uses an Ubuntu 24.04 ARM runner.# (...)
name: Build Docker image for ${{ matrix.platform }}
steps:
-
name: Prepare environment for current platform
id: prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Docker meta default
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
with:
images: ${{ env.GHCR_IMAGE }}
#(...)
prepare step sets up the environment for the current platform. It replaces '/' in the platform name with '-' and sets it as an environment variable (PLATFORM_PAIR). This is useful for naming artifacts and other resources that can't handle '/'.Checkout: This step uses actions/checkout@v4.2.2 to clone the repository into the runner's workspace.Docker meta default: This step uses docker/metadata-action@v5.7.0 to generate metadata for the Docker image, including the image name, tags, and labels. This metadata will be used later for building and pushing the image.# (...)
- name: Set up Docker Context for Buildx
id: buildx-context
run: |
docker context create builders
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
with:
endpoint: builders
platforms: ${{ matrix.platform }}
- name: Login to GitHub Container Registry
# This step logs in to the GitHub Container Registry (GHCR) using the docker/login-action.
# It uses the GitHub actor's username and the GITHUB_TOKEN secret for authentication.
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
#(...)
Set up Docker Context for Buildx: Creates a new context named "builders" for Buildx, allowing it to use the Docker daemon for building images.Set up Docker Buildx: Configures Buildx (docker/setup-buildx-action@v3.10.0) with the specified context and platforms.Login to GitHub Container Registry: Logs in to GHCR using docker/login-action@v3.4.0 with the GitHub actor's username and the GITHUB_TOKEN secret.# (...)
- name: Build and push by digest
id: build
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
env:
DOCKER_BUILDKIT: 1
with:
context: .
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
outputs: type=image,name=${{ env.GHCR_IMAGE }},push-by-digest=true,name-canonical=true,push=true,oci-mediatypes=true
cache-from: type=gha,scope=${{ github.repository }}-${{ github.ref_name }}-${{ matrix.platform }}
cache-to: type=gha,scope=${{ github.repository }}-${{ github.ref_name }}-${{ matrix.platform }}
#(...)
Build and push by digest: This is where the magic happens. It uses docker/build-push-action@v6.15.0 to build the image with the specified context and platforms. The image is built with the labels and annotations generated earlier.outputs: Configures the action to push the image by digest, enabling better caching and versioning.cache-from and cache-to: Enable caching for the build process, storing the cache in GitHub Actions cache and scoping it to the repository, branch, and platform.# (...)
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
#(...)
Export digest: Creates a directory /tmp/digests and saves the digest of the built image to a file. The digest uniquely identifies the built image.Upload digest: Uploads the digest file to GitHub Actions artifact storage using actions/upload-artifact@v4.6.1. The artifact is named digests-${{ env.PLATFORM_PAIR }} and is retained for 1 day.# (...)
merge:
name: Merge Docker manifests
runs-on: ubuntu-latest
permissions:
attestations: write
actions: read
checks: read
contents: read
deployments: none
id-token: write
issues: read
discussions: read
packages: write
pages: none
pull-requests: read
repository-projects: read
security-events: read
statuses: read
needs:
- build
steps:
- name: Download digests
uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
merge: This job merges the Docker manifests for the different platforms built in the previous job.needs: - build: Ensures that the build job completes successfully before starting.Download digests: Downloads the digest files uploaded in the build job using actions/download-artifact@v4.1.9. The files are merged into the /tmp/digests directory. - name: Docker meta
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
with:
images: ${{ env.GHCR_IMAGE }}
annotations: |
type=org.opencontainers.image.description,value=${{ github.event.repository.description || 'No description provided' }}
tags: |
type=raw,value=main,enable=${{ github.ref_name == 'main' }}
type=raw,value=latest,enable=${{ github.ref_name == 'main' }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
with:
driver-opts: |
network=host
- name: Login to GitHub Container Registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get execution timestamp with RFC3339 format
id: timestamp
run: |
echo "timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT
Docker meta: Generates metadata for the Docker image using docker/metadata-action@v5.7.0.Set up Docker Buildx: Sets up Buildx again (docker/setup-buildx-action@v3.10.0).Login to GitHub Container Registry: Logs in to GHCR (docker/login-action@v3.4.0).Get execution timestamp with RFC3339 format: Gets the current UTC time in RFC3339 format for annotating the Docker manifest list. - name: Create manifest list and pushs
working-directory: /tmp/digests
id: manifest-annotate
continue-on-error: true
run: |
docker buildx imagetools create \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
--annotation='index:org.opencontainers.image.description=${{ github.event.repository.description }}' \
--annotation='index:org.opencontainers.image.created=${{ steps.timestamp.outputs.timestamp }}' \
--annotation='index:org.opencontainers.image.url=${{ github.event.repository.url }}' \
--annotation='index:org.opencontainers.image.source=${{ github.event.repository.url }}' \
$(printf '${{ env.GHCR_IMAGE }}@sha256:%s ' *)
- name: Create manifest list and push without annotations
if: steps.manifest-annotate.outcome == 'failure'
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.GHCR_IMAGE }}@sha256:%s ' *)
- name: Inspect image
id: inspect
run: |
docker buildx imagetools inspect '${{ env.GHCR_IMAGE }}:${{ steps.meta.outputs.version }}'
Create manifest list and push: Creates a manifest list for the Docker images built for different platforms using docker buildx imagetools create. The manifest list is annotated with metadata and pushed to GHCR.Create manifest list and push without annotations: If the previous step fails, this step creates the manifest list without annotations and pushes it to GHCR.Inspect image: Inspects the created manifest list using docker buildx imagetools inspect to verify its contents.There you have it! A complete, step-by-step guide to building multi-arch Docker images like a pro, using native GitHub Runners and leaving QEMU in the dust. Now go forth and conquer the world of multi-architecture deployments!
la ironía de la seguridad: las github actions de trivy secuestradas (otra vez) En un giro del destino que haría
Una campaña de ataque autónoma, rastreada como "hackerbot-claw", está acechando actualmente repositorios públicos. ¿Su misión? Encontrar workflows de GitHub Actions inseguros y convertirlos en puertas de enlace para la ejecución de código arbitrario y la exfiltración de credenciales.