FROM golang:1.27.4-alpine@sha256:0a5f7fe796599ff487605987432e7619ae45beeb2fba4c2ce0b907879932aebf AS curl-build ARG TARGETARCH COPY dockerscripts/build-static-curl.sh /build/build-static-curl RUN /bin/sh /build/build-static-curl # Exercise the exact shipped curl without a dynamic loader or shared libraries. FROM scratch AS curl-runtime COPY --from=curl-build /go/bin/curl /curl COPY --from=curl-build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt ENTRYPOINT ["/curl"] FROM golang:1.27.4-alpine@sha256:0a5f7fe796599ff487605987432e7619ae45beeb2fba4c2ce0b907879932aebf AS build ARG TARGETARCH ENV GOPATH=/go ENV CGO_ENABLED=0 ARG MC_REPO=pgsty/mc ARG MC_VERSION=RELEASE.2026-11-12T00-00-00Z ARG MC_AMD64_SHA256=68875c7fdd06a76af12b74753506df65226d1bec65a405d2617d76448c229ba2 ARG MC_ARM64_SHA256=4ea59d2f278c96b25e380289fd2ee9bc49faa342687074f031805cb7b34fbe1a RUN apk add -U --no-cache \ ca-certificates \ bash \ curl \ jq && \ case "${TARGETARCH}" in \ amd64) MC_ARCH=amd64; MC_PINNED_SHA256="${MC_AMD64_SHA256}" ;; \ arm64) MC_ARCH=arm64; MC_PINNED_SHA256="${MC_ARM64_SHA256}" ;; \ *) echo "Unsupported TARGETARCH=${TARGETARCH}"; exit 1 ;; \ esac && \ if [ "${MC_VERSION}" = "latest" ]; then \ MC_RELEASE_URL="https://api.github.com/repos/${MC_REPO}/releases/latest"; \ else \ MC_RELEASE_URL="https://api.github.com/repos/${MC_REPO}/releases/tags/${MC_VERSION}"; \ fi && \ curl -fsSL "${MC_RELEASE_URL}" -o /tmp/mc-release.json && \ MC_ARCHIVE_URL=$(jq -r --arg arch "${MC_ARCH}" \ '.assets[] | select(.name | endswith("_linux_" + $arch + ".tar.gz")) | .browser_download_url' \ /tmp/mc-release.json | head -n 1) && \ MC_CHECKSUM_URL=$(jq -r \ '.assets[] | select(.name | endswith("_checksums.txt")) | .browser_download_url' \ /tmp/mc-release.json | head -n 1) && \ [ -n "${MC_ARCHIVE_URL}" ] || { echo "Cannot find mcli archive for linux/${MC_ARCH}"; exit 1; } && \ [ -n "${MC_CHECKSUM_URL}" ] || { echo "Cannot find mcli checksums file"; exit 1; } && \ ARCHIVE_NAME=$(basename "${MC_ARCHIVE_URL}") && \ echo "Downloading ${ARCHIVE_NAME} ..." && \ curl -fsSL "${MC_ARCHIVE_URL}" -o /tmp/mcli.tar.gz && \ curl -fsSL "${MC_CHECKSUM_URL}" -o /tmp/mcli_checksums.txt && \ EXPECTED=$(grep " ${ARCHIVE_NAME}$" /tmp/mcli_checksums.txt | awk '{print $1}') && \ ACTUAL=$(sha256sum /tmp/mcli.tar.gz | awk '{print $1}') && \ [ -n "${EXPECTED}" ] || { echo "Checksum entry not found for ${ARCHIVE_NAME}"; exit 1; } && \ [ "${EXPECTED}" = "${MC_PINNED_SHA256}" ] || { echo "Published checksum drift for ${ARCHIVE_NAME}"; exit 1; } && \ [ "${MC_PINNED_SHA256}" = "${ACTUAL}" ] || { echo "Checksum mismatch: expected ${MC_PINNED_SHA256}, got ${ACTUAL}"; exit 1; } && \ echo "Checksum OK: ${ACTUAL}" && \ mkdir -p /tmp/mcli-extract && \ tar -xzf /tmp/mcli.tar.gz -C /tmp/mcli-extract/ && \ if [ -f /tmp/mcli-extract/mcli ]; then \ cp /tmp/mcli-extract/mcli /go/bin/mcli; \ elif [ -f /tmp/mcli-extract/mc ]; then \ cp /tmp/mcli-extract/mc /go/bin/mcli; \ else \ echo "No mc or mcli binary found in archive:"; ls -la /tmp/mcli-extract/; exit 1; \ fi && \ chmod +x /go/bin/mcli && \ ln -sf mcli /go/bin/mc && \ mkdir -p /go/share/mcli && \ cp /tmp/mcli-extract/LICENSE /tmp/mcli-extract/NOTICE /tmp/mcli-extract/CREDITS /go/share/mcli/ FROM registry.access.redhat.com/ubi9/ubi:latest@sha256:8b212f75a0e5a156ac28b1c5c030d2e8a07715254e19d522286118279399af81 AS certs # Native root blocklist mitigation: https://access.redhat.com/security/vulnerabilities/RHSB-2026-012 RUN dnf -y install ca-certificates && \ if [ -d /etc/pki/ca-trust/source/blocklist ]; then \ blocklist=/etc/pki/ca-trust/source/blocklist; \ else \ blocklist=/etc/pki/ca-trust/source/blacklist; \ fi && \ trust extract --overwrite --format=pem-bundle \ --filter='pkcs11:object=Comodo%20AAA%20Services%20root;type=cert' \ "$blocklist/Comodo_AAA_Services_root.pem" && \ trust extract --overwrite --format=pem-bundle \ --filter='pkcs11:object=emSign%20ECC%20Root%20CA%20-%20G3;type=cert' \ "$blocklist/emSign_ECC_Root_CA_-_G3.pem" && \ update-ca-trust && \ cp /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /tmp/ca-certificates.crt && \ dnf clean all && \ rm -rf /var/cache/dnf FROM registry.access.redhat.com/ubi9/ubi-micro:latest@sha256:b59ac4f291d86027c2681f7a7b1cbf7448972fc55a6cb8e25cab5aa5eef5ce5f LABEL org.opencontainers.image.title="Silo" \ org.opencontainers.image.description="S3-Interface Libre Object Storage" \ org.opencontainers.image.url="https://silo.pgsty.com" \ org.opencontainers.image.source="https://github.com/pgsty/silo" \ org.opencontainers.image.licenses="AGPL-3.0-or-later" \ maintainer="PGSTY " ENV MINIO_ACCESS_KEY_FILE=access_key \ MINIO_SECRET_KEY_FILE=secret_key \ MINIO_ROOT_USER_FILE=access_key \ MINIO_ROOT_PASSWORD_FILE=secret_key \ MINIO_KMS_SECRET_KEY_FILE=kms_master_key \ MINIO_CONFIG_ENV_FILE=config.env \ HOME=/tmp \ MC_CONFIG_DIR=/tmp/.mc COPY --from=certs /tmp/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY silo /usr/bin/silo COPY --from=build /go/bin/mcli /usr/bin/mcli # mcli's own legal files, from the same verified archive as the binary. COPY --from=build /go/share/mcli /licenses/mcli COPY --from=curl-build /go/bin/curl /usr/bin/curl COPY --from=curl-build /go/share/curl /licenses/curl COPY dockerscripts/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh COPY LICENSE /licenses/LICENSE COPY NOTICE /licenses/NOTICE COPY CREDITS /licenses/CREDITS RUN chmod +x /usr/bin/silo /usr/bin/mcli /usr/bin/docker-entrypoint.sh && \ ln -sf mcli /usr/bin/mc EXPOSE 9000 VOLUME ["/data"] ENTRYPOINT ["/usr/bin/docker-entrypoint.sh"] CMD ["silo"]