locket 0.17.3

Helper tool for secret injection as a process dependency
Documentation
# syntax=docker/dockerfile:1
# check=skip=SecretsUsedInArgOrEnv

ARG RUST_TAG=1.95-alpine3.22

FROM rust:${RUST_TAG} AS chef
USER root
RUN apk add --no-cache musl-dev build-base pkgconfig \
    && cargo install cargo-chef
WORKDIR /src

FROM chef AS planner

# Copy manifests only first to help put dependencies in cache
COPY Cargo.toml Cargo.lock ./
COPY locket_derive/Cargo.toml locket_derive/Cargo.toml
COPY xtask/Cargo.toml xtask/Cargo.toml

RUN mkdir -p src locket_derive/src xtask/src \
    && touch src/lib.rs src/main.rs \
    && touch locket_derive/src/lib.rs \
    && touch xtask/src/main.rs

RUN cargo chef prepare --recipe-path recipe.json

FROM chef AS builder
COPY --from=planner /src/recipe.json recipe.json

ARG CACHE_FEATURES="full"

RUN cargo chef cook --release \
       --recipe-path recipe.json \
       --no-default-features --features "${CACHE_FEATURES}"

ARG FEATURES="full"

COPY . .
RUN cargo build --release --locked \
       --no-default-features --features "${FEATURES}" \
    && strip target/release/locket \
    && cp target/release/locket /locket

FROM alpine:3.23 AS rootfs
RUN addgroup -g 65532 nonroot \
    && adduser -D -H -u 65532 -G nonroot nonroot

RUN grep -E '^(root|nonroot)' /etc/passwd > /etc/passwd.min \
    && grep -E '^(root|nonroot)' /etc/group > /etc/group.min

RUN install -d -m 0755 skeleton \
    && install -d -m 1777 /skeleton/tmp \
    && install -d -m 0755 /etc/ssl/certs \
    && install -d -m 0755 /usr/local/bin \
    && install -d -m 0755 /home/nonroot && chown nonroot:nonroot /home/nonroot \
    && install -d -m 0755 /templates && chown nonroot:nonroot /templates \
    && install -d -m 0755 /run/secrets && chown nonroot:nonroot /run/secrets \
    && install -d -m 0755 /etc/locket && chown nonroot:nonroot /etc/locket \
    && install -d -m 0700 /config/op && chown nonroot:nonroot /config/op \
    && apk add --no-cache ca-certificates

RUN install -d -m 0755 -o root -g root /plugin-fs/run/docker/plugins \
    && install -d -m 0755 -o root -g root /plugin-fs/var/lib/locket/state \
    && install -d -m 0755 -o root -g root /plugin-fs/var/lib/locket/mounts \
    && install -d -m 0755 -o root -g root /plugin-fs/etc/locket

COPY docker/locket.toml /staging/locket.toml

RUN install -m 644 -o nonroot -g nonroot /staging/locket.toml /etc/locket/locket.toml
RUN install -m 644 -o root -g root /staging/locket.toml /plugin-fs/etc/locket/locket.toml
RUN rm -rf /staging
RUN cp /etc/ssl/certs/ca-certificates.crt /ca-certificates.crt

FROM scratch AS runtime
LABEL org.opencontainers.image.title="locket"

ENV PATH=/usr/local/bin \
    HOME=/home/nonroot \
    TMPDIR=/tmp \
    XDG_CONFIG_HOME=/config \
    HOME=/home/nonroot

COPY --from=rootfs /skeleton /
COPY --from=rootfs /ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=rootfs /etc/passwd /etc/passwd
COPY --from=rootfs /etc/group /etc/group
COPY --from=rootfs --chown=nonroot:nonroot /home/nonroot /home/nonroot
COPY --from=rootfs --chown=nonroot:nonroot /templates /templates
COPY --from=rootfs --chown=nonroot:nonroot /run/secrets /run/secrets
COPY --from=rootfs --chmod=644 /etc/passwd.min /etc/passwd
COPY --from=rootfs --chmod=644 /etc/group.min /etc/group
COPY --from=rootfs --chown=nonroot:nonroot /etc/locket /etc/locket
COPY --from=builder /locket /usr/local/bin/locket

WORKDIR /
USER nonroot:nonroot
VOLUME ["/run/secrets/locket", "/templates"]
HEALTHCHECK --interval=5s --timeout=3s --retries=30 \
    CMD ["locket","healthcheck"]
ENTRYPOINT ["locket","inject", "--config", "/etc/locket/locket.toml"]

FROM alpine:3.23 AS opstage
ARG OP_VERSION=2.32.0
ARG TARGETARCH
RUN set -eux; \
    apk add --no-cache ca-certificates unzip; \
    wget -O /tmp/op.zip \
      "https://cache.agilebits.com/dist/1P/op2/pkg/v${OP_VERSION}/op_linux_${TARGETARCH}_v${OP_VERSION}.zip"; \
    unzip /tmp/op.zip -d /tmp/op; \
    install -m 755 /tmp/op/op /usr/bin/op; \
    rm -rf /tmp/op /tmp/op.zip

FROM runtime AS base
ARG DEFAULT_PROVIDER
ENV SECRETS_PROVIDER=${DEFAULT_PROVIDER}

FROM base AS op
LABEL org.opencontainers.image.title="locket (op)"
COPY --from=opstage /usr/bin/op /usr/local/bin/op
COPY --from=rootfs --chown=nonroot:nonroot --chmod=700 /config/op /config/op

FROM runtime AS aio
COPY --from=opstage /usr/bin/op /usr/local/bin/op
COPY --from=rootfs --chown=nonroot:nonroot --chmod=700 /config/op /config/op

FROM aio AS plugin
USER root

COPY --from=rootfs /plugin-fs /

# Debug image with full distro, extra tools, and shell access
FROM alpine:3.23 AS debug
LABEL org.opencontainers.image.title="locket (debug)"

RUN apk add --no-cache bash curl vim tree strace jq coreutils

ENV PATH="/usr/local/bin:${PATH}" \
    HOME=/root \
    TMPDIR=/tmp \
    XDG_CONFIG_HOME=/config

RUN mkdir -p /run/secrets /templates /config/op \
    && chmod 740 /run/secrets /templates /config/op

RUN addgroup -g 65532 nonroot \
    && adduser -D -H -u 65532 -G nonroot nonroot

COPY --from=opstage /usr/bin/op /usr/local/bin/op
COPY --from=rootfs --chown=nonroot:nonroot --chmod=700 /config/op /config/op
COPY --from=builder /locket /usr/local/bin/locket
VOLUME ["/run/secrets/locket", "/templates"]
ENTRYPOINT ["/bin/bash"]