diff --git a/.github/workflows/scripts/load-oci-archives.sh b/.github/workflows/scripts/load-oci-archives.sh new file mode 100755 index 00000000..5c3489fd --- /dev/null +++ b/.github/workflows/scripts/load-oci-archives.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +## +## USAGE: __PROG__ +## +## "__PROG__" loads oci tarballs created with xbuild into docker. +## +## Usage example(s): +## ./__PROG__ +## PLATFORM=linux/arm64 ./__PROG__ +## +## Commands +## - ./__PROG__ loads the oci tarball into Docker. + +function usage { + grep '^##' "$0" | sed -e 's/^##//' -e "s/__PROG__/$me/" >&2 +} + +function normalize_path { + # Remove all /./ sequences. + local path=${1//\/.\//\/} + local npath + # Remove first dir/.. sequence. + npath="${path//[^\/][^\/]*\/\.\.\//}" + # Remove remaining dir/.. sequence. + while [[ $npath != "$path" ]] ; do + path=$npath + npath="${path//[^\/][^\/]*\/\.\.\//}" + done + echo "$path" +} + +me=$(basename "$0") +BASEDIR=$(dirname "$0") +ROOTDIR="$(normalize_path "$BASEDIR/../../../")" + +command -v regctl >/dev/null 2>&1 || { usage; echo -e "\n * The regctl cli is required to run this script." >&2 ; exit 1; } +command -v docker >/dev/null 2>&1 || { usage; echo -e "\n * The docker cli is required to run this script." >&2 ; exit 1; } + +# Takes the current platform architecture or plaftorm as defined externally in a platform variable. +# e.g.: +# linux/amd64 +# linux/arm64 +PLATFORM="${PLATFORM:-local}" +OCI_IMAGES=( + spiffe-helper +) + +org_name=$(echo "$GITHUB_REPOSITORY" | tr '/' "\n" | head -1 | tr -d "\n") +org_name="${org_name:-spiffe}" # default to spiffe in case ran on local +registry=ghcr.io/${org_name} + +echo "Importing ${OCI_IMAGES[*]} into docker". +for img in "${OCI_IMAGES[@]}"; do + oci_dir="ocidir://${ROOTDIR}oci/${img}" + platform_tar="${img}-${PLATFORM}-image.tar" + image_to_load="${registry}/${img}:devel" + + # regclient works with directories rather than tars, so import the OCI tar to a directory + regctl image import "$oci_dir" "${img}-image.tar" + dig="$(regctl image digest --platform "$PLATFORM" "$oci_dir")" + # export the single platform image using the digest + regctl image export "$oci_dir@${dig}" "${platform_tar}" + + docker load < "${platform_tar}" + docker image tag "localhost/oci/${img}:latest" "${image_to_load}" + docker image rm "localhost/oci/${img}:latest" +done diff --git a/.gitignore b/.gitignore index 8e2305b3..e9c76f81 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ rpm/*.rpm *.swp *.swo bootstrap.crt + +# oci image builds +oci/ +*-image.tar diff --git a/Dockerfile b/Dockerfile index 059a9c45..142ece63 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,40 @@ -FROM golang +# Build the spiffe-helper binary +ARG go_version +FROM --platform=$BUILDPLATFORM golang:${go_version}-alpine as base +WORKDIR /workspace -WORKDIR /build -COPY . /build -RUN CGO_ENABLED=0 go build -o spiffe-helper ./cmd/spiffe-helper +# Cache deps before building and copying source so that we don't need to re-download as much +# and so that source changes don't invalidate our downloaded layer +COPY go.* ./ +RUN --mount=type=cache,target=/go/pkg/mod go mod download + +# Copy the go source +COPY cmd/spiffe-helper/main.go cmd/spiffe-helper/main.go +COPY pkg/ pkg/ + +# xx is a helper for cross-compilation +# when bumping to a new version analyze the new version for security issues +# then use crane to lookup the digest of that version so we are immutable +# crane digest tonistiigi/xx:1.3.0 +FROM --platform=${BUILDPLATFORM} tonistiigi/xx@sha256:904fe94f236d36d65aeb5a2462f88f2c537b8360475f6342e7599194f291fb7e AS xx + +FROM --platform=${BUILDPLATFORM} base as builder +ARG TARGETPLATFORM +ARG TARGETARCH + +ENV CGO_ENABLED=0 +COPY --link --from=xx / / +RUN xx-go --wrap +RUN --mount=type=cache,target=/root/.cache/go-build \ + --mount=type=cache,target=/go/pkg/mod \ + go build -o bin/spiffe-helper cmd/spiffe-helper/main.go + +# Use distroless as minimal base image to package the manager binary +# Refer to https://github.com/GoogleContainerTools/distroless for more details +#FROM gcr.io/distroless/static:nonroot +FROM gcr.io/distroless/static AS spiffe-helper +WORKDIR / +COPY --link --from=builder /workspace/bin/spiffe-helper /spiffe-helper -FROM scratch -COPY --from=0 /build/spiffe-helper /spiffe-helper ENTRYPOINT ["/spiffe-helper"] -CMD ["-config", "/etc/spiffe-helper.conf"] +CMD [] diff --git a/Makefile b/Makefile index c2863cc9..33b183b8 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ export GO111MODULE=on DIR := ${CURDIR} +PLATFORMS ?= linux/amd64,linux/arm64 E:=@ ifeq ($(V),1) @@ -41,6 +42,15 @@ help: @echo "For verbose output set V=1" @echo " for example: $(cyan)make V=1 build$(reset)" +# Used to force some rules to run every time +.PHONY: FORCE +FORCE: ; + +# CONTAINER_TOOL defines the container tool to be used for building images. +# Be aware that the target commands are only tested with Docker which is +# scaffolded by default. However, you might want to replace it to use other +# tools. (i.e. podman) +CONTAINER_TOOL ?= docker ############################################################################ # OS/ARCH detection @@ -167,11 +177,27 @@ lint-code: $(golangci_lint_bin) | go-check # Build targets ############################################################################ -.PHONY: build test clean distclean artifact tarball rpm +.PHONY: build test clean distclean artifact tarball rpm docker-build container-builder load-images build: | go-check go build -o spiffe-helper${exe} ./cmd/spiffe-helper +docker-build: $(addsuffix -image.tar, spiffe-helper) ## Build docker image with spiffe-helper. + +container-builder: ## Create a buildx node to create crossplatform images. + $(CONTAINER_TOOL) buildx create --platform $(PLATFORMS) --name container-builder --node container-builder0 --use + +spiffe-helper-image.tar: Dockerfile FORCE | container-builder + $(CONTAINER_TOOL) buildx build \ + --platform $(PLATFORMS) \ + --build-arg go_version=$(go_version) \ + --target spiffe-helper \ + -o type=oci,dest=$@ \ + . + +load-images: $(addsuffix -image.tar,$(BINARIES)) ## Load the image for your current PLATFORM into docker from the cross-platform oci tar. + ./.github/workflows/scripts/load-oci-archives.sh + artifact: tarball rpm tarball: build