···2121# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
2222RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/manager/main.go
2323RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o agent cmd/agent/main.go
2424+RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o discovery cmd/discovery/main.go
24252526FROM alpine:3.22 AS base
2627···5758WORKDIR /
5859COPY --from=builder /workspace/manager .
5960COPY --from=builder /workspace/agent .
6161+COPY --from=builder /workspace/discovery .
6262+COPY entrypoint.sh /entrypoint.sh
6363+RUN chmod +x /entrypoint.sh
6064USER 65532:65532
61656262-ENTRYPOINT ["/manager"]
6666+ENTRYPOINT ["/entrypoint.sh"]
-58
Dockerfile.discovery
···11-# Lightweight discovery agent - no HSM libraries needed
22-FROM golang:1.24-alpine AS builder
33-ARG TARGETOS
44-ARG TARGETARCH
55-66-WORKDIR /workspace
77-# Copy the Go Modules manifests
88-COPY go.mod go.mod
99-COPY go.sum go.sum
1010-# cache deps before building and copying source so that we don't need to re-download as much
1111-# and so that source changes don't invalidate our downloaded layer
1212-RUN go mod download
1313-1414-# Copy the go source (only what's needed for discovery)
1515-COPY cmd/discovery/ cmd/discovery/
1616-COPY api/ api/
1717-COPY internal/ internal/
1818-1919-# Build discovery binary only
2020-RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o discovery cmd/discovery/main.go
2121-2222-FROM alpine:3.22 AS base
2323-2424-# Update Alpine packages
2525-RUN apk update
2626-2727-# Install compilation tools
2828-RUN apk add --no-cache \
2929- git \
3030- gcc \
3131- g++ \
3232- make \
3333- cmake \
3434- pkgconfig \
3535- openssl-dev \
3636- pcsc-lite-dev \
3737- libusb-dev \
3838- autoconf \
3939- automake \
4040- libtool
4141-4242-RUN cd / && git clone https://github.com/CardContact/sc-hsm-embedded.git
4343-WORKDIR /sc-hsm-embedded
4444-RUN autoreconf -fi && ./configure
4545-RUN make && make install
4646-4747-FROM alpine:3.22
4848-RUN apk add --no-cache opensc-dev ccid pcsc-lite openssl libtool libusb
4949-5050-COPY --from=base /usr/lib/libssl.so* /usr/lib/
5151-COPY --from=base /usr/lib/libcrypto.so* /usr/lib/
5252-COPY --from=base /usr/local/ /usr/local/
5353-5454-WORKDIR /
5555-COPY --from=builder /workspace/discovery .
5656-USER 65532:65532
5757-5858-ENTRYPOINT ["/discovery"]
-128
Dockerfile.talos
···11-# Multi-stage Dockerfile for HSM Secrets Operator with PKCS#11 libraries
22-# Optimized for Talos Linux deployments
33-44-# Stage 1: Build PKCS#11 libraries
55-FROM alpine:3.18 AS pkcs11-builder
66-77-# Install build dependencies
88-RUN apk add --no-cache \
99- wget \
1010- tar \
1111- gzip \
1212- build-base \
1313- autoconf \
1414- automake \
1515- libtool \
1616- pkgconfig \
1717- openssl-dev \
1818- libusb-dev \
1919- pcsc-lite-dev \
2020- flex \
2121- help2man
2222-2323-# Build OpenSC (most common PKCS#11 library)
2424-ENV OPENSC_VERSION=0.24.0
2525-RUN wget https://github.com/OpenSC/OpenSC/releases/download/${OPENSC_VERSION}/opensc-${OPENSC_VERSION}.tar.gz && \
2626- tar -xzf opensc-${OPENSC_VERSION}.tar.gz && \
2727- cd opensc-${OPENSC_VERSION} && \
2828- ./configure \
2929- --prefix=/usr/local \
3030- --enable-pcsc \
3131- --enable-openssl \
3232- --disable-static \
3333- --enable-shared && \
3434- make -j$(nproc) && \
3535- make install
3636-3737-# Build YubiKey PKCS#11 library (optional but common)
3838-ENV YUBICO_PIV_VERSION=2.4.0
3939-RUN wget https://developers.yubico.com/yubico-piv-tool/Releases/yubico-piv-tool-${YUBICO_PIV_VERSION}.tar.gz && \
4040- tar -xzf yubico-piv-tool-${YUBICO_PIV_VERSION}.tar.gz && \
4141- cd yubico-piv-tool-${YUBICO_PIV_VERSION} && \
4242- ./configure --prefix=/usr/local && \
4343- make -j$(nproc) && \
4444- make install
4545-4646-# Build SoftHSM (useful for testing and dev environments)
4747-ENV SOFTHSM_VERSION=2.6.1
4848-RUN wget https://dist.opendnssec.org/source/softhsm-${SOFTHSM_VERSION}.tar.gz && \
4949- tar -xzf softhsm-${SOFTHSM_VERSION}.tar.gz && \
5050- cd softhsm-${SOFTHSM_VERSION} && \
5151- ./configure --prefix=/usr/local && \
5252- make -j$(nproc) && \
5353- make install
5454-5555-# Organize libraries for runtime stage
5656-RUN mkdir -p /pkcs11-libs && \
5757- cp /usr/local/lib/pkcs11/*.so /pkcs11-libs/ && \
5858- cp /usr/local/lib/libykcs11*.so /pkcs11-libs/ 2>/dev/null || true && \
5959- cp /usr/local/lib/libsofthsm2.so /pkcs11-libs/ 2>/dev/null || true && \
6060- chmod 755 /pkcs11-libs/*.so
6161-6262-# Create library configuration files
6363-RUN mkdir -p /pkcs11-config
6464-COPY <<EOF /pkcs11-config/opensc.conf
6565-# OpenSC Configuration for HSM Secrets Operator
6666-app default {
6767- card_drivers = piv, openpgp, sc-hsm;
6868- reader_drivers = pcsc, openct;
6969-}
7070-EOF
7171-7272-# Stage 2: Build Go application
7373-FROM golang:1.24-alpine AS go-builder
7474-7575-ARG TARGETOS
7676-ARG TARGETARCH
7777-7878-WORKDIR /workspace
7979-8080-# Copy the Go Modules manifests
8181-COPY go.mod go.mod
8282-COPY go.sum go.sum
8383-8484-# Cache deps before building and copying source so that we don't need to re-download as much
8585-# and so that source changes don't invalidate our downloaded layer
8686-RUN go mod download
8787-8888-# Copy the go source
8989-COPY cmd/main.go cmd/main.go
9090-COPY api/ api/
9191-COPY internal/ internal/
9292-9393-# Build
9494-# the GOARCH has not a default value to allow the binary be built according to the host where the command
9595-# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
9696-# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
9797-# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
9898-RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go
9999-100100-# Stage 3: Runtime image optimized for Talos
101101-FROM gcr.io/distroless/static:nonroot
102102-103103-# Labels for image metadata
104104-LABEL org.opencontainers.image.title="HSM Secrets Operator for Talos"
105105-LABEL org.opencontainers.image.description="Kubernetes operator for managing HSM-backed secrets on Talos Linux"
106106-LABEL org.opencontainers.image.vendor="HSM Secrets Operator"
107107-LABEL org.opencontainers.image.licenses="Apache-2.0"
108108-109109-# Copy PKCS#11 libraries from builder stage
110110-COPY --from=pkcs11-builder /pkcs11-libs/* /usr/local/lib/pkcs11/
111111-COPY --from=pkcs11-builder /pkcs11-config/* /etc/pkcs11/
112112-113113-# Copy runtime dependencies (minimal)
114114-COPY --from=pkcs11-builder /usr/local/lib/libopensc.so* /usr/local/lib/
115115-COPY --from=pkcs11-builder /usr/local/lib/libykcs11.so* /usr/local/lib/
116116-COPY --from=pkcs11-builder /usr/local/lib/libsofthsm2.so* /usr/local/lib/
117117-118118-# Copy the manager binary
119119-COPY --from=go-builder /workspace/manager .
120120-121121-# Set library path for PKCS#11 libraries
122122-ENV LD_LIBRARY_PATH="/usr/local/lib/pkcs11:/usr/local/lib"
123123-ENV PKCS11_MODULE_PATH="/usr/local/lib/pkcs11"
124124-ENV OPENSC_CONF="/etc/pkcs11/opensc.conf"
125125-126126-USER 65532:65532
127127-128128-ENTRYPOINT ["/manager"]
+5-19
Makefile
···5151OPERATOR_SDK_VERSION ?= v1.41.1
5252# Image URL to use all building/pushing image targets
5353IMG ?= controller:latest
5454-DISCOVERY_IMG ?= hsm-discovery:latest
55545655# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
5756ifeq (,$(shell go env GOBIN))
···187186docker-push: ## Push docker image with the manager.
188187 $(CONTAINER_TOOL) push ${IMG}
189188190190-.PHONY: docker-build-discovery
191191-docker-build-discovery: ## Build docker image for the discovery agent (native sysfs, distroless).
192192- $(CONTAINER_TOOL) build -f Dockerfile.discovery -t ${DISCOVERY_IMG} .
193193-194194-.PHONY: docker-push-discovery
195195-docker-push-discovery: ## Push docker image for the discovery agent.
196196- $(CONTAINER_TOOL) push ${DISCOVERY_IMG}
197197-198198-.PHONY: docker-build-all
199199-docker-build-all: docker-build docker-build-discovery ## Build both docker images.
200200-201201-.PHONY: docker-push-all
202202-docker-push-all: docker-push docker-push-discovery ## Push both docker images.
189189+.PHONY: docker-build-multiarch
190190+docker-build-multiarch: ## Build docker image for multiple architectures and push.
191191+ $(CONTAINER_TOOL) buildx build --platform linux/amd64,linux/arm64 --push -t ${IMG} .
203192204193# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
205194# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
···209198# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
210199PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
211200.PHONY: docker-buildx
212212-docker-buildx: ## Build and push docker image for the manager for cross-platform support
213213- # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
214214- sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
201201+docker-buildx: ## Build and push docker image for cross-platform support (linux/amd64,linux/arm64)
215202 - $(CONTAINER_TOOL) buildx create --name hsm-secrets-operator-builder
216203 $(CONTAINER_TOOL) buildx use hsm-secrets-operator-builder
217217- - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
204204+ - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} .
218205 - $(CONTAINER_TOOL) buildx rm hsm-secrets-operator-builder
219219- rm Dockerfile.cross
220206221207.PHONY: build-installer
222208build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.