- Dockerfile: optional ARG PKG_CACHE; the apt RUN (dist-upgrade + pinned haproxy) rewrites sources via scripts/pkg-cache-repos.sh apt and restores them before the RUN ends. Without PKG_CACHE: upstream Debian, as before. - coraza-spoa/Dockerfile: same for the build stage's apt RUN; go mod download / go build (build + catalog stages) use go-env (GOPROXY via the cache with proxy.golang.org fallback; GOSUMDB unchanged) and restore. Build context is ./coraza-spoa, so coraza-spoa/scripts/pkg-cache-repos.sh and coraza-spoa/keys/pkg-cache/ are byte-identical copies of the root ones. - build-push.yaml / build-push-coraza.yaml: "Probe package cache" step (TLS with the pinned CA), PKG_CACHE build-arg. Bases come from repo.anhonesthost.net / gcr.io, not docker.io: registry mirror not used. - mirror-base-image.yaml: resolve the tag's digest directly at Docker Hub (.gitea/scripts/resolve-base-image.sh) and pull docker.io/library/<img>@sha256 so the mirrored content is exactly the digest Docker Hub reported; same destination tags. Values reach run: via env only. - Canonical copies (byte-identical) of scripts/pkg-cache-repos.sh, .gitea/scripts/resolve-base-image.sh and keys/pkg-cache/ from cloud-apache-container. - VERSION 2026.10.7 so the rebuild does not overwrite the 2026.10.6 tag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
95 lines
4.9 KiB
Docker
95 lines
4.9 KiB
Docker
# Coraza-SPOA sidecar for haproxy-manager.
|
|
#
|
|
# Layout: built from upstream source. main.go is at the repo root; CRS rules
|
|
# are bundled into the binary at build time (referenced as @owasp_crs/), so
|
|
# the CRS version is whatever ships with the pinned coraza-spoa tag.
|
|
#
|
|
# Pin: review the upstream CHANGELOG (https://github.com/corazawaf/coraza-spoa/releases)
|
|
# before bumping. New tags can ship newer CRS, which can introduce new rules
|
|
# whose IDs fall into the "enforce day-one" ranges in overrides.conf — verify
|
|
# those are still high-confidence before promoting a new tag to prod.
|
|
|
|
ARG CORAZA_SPOA_VERSION=v0.7.1
|
|
|
|
# golang:1.25 from the in-house mirror. The 2026-05-12 Cloudflare incident
|
|
# took out docker.io blob pulls TWICE in one day (first for python:3.12-slim,
|
|
# then for this image's golang:1.25), so both are mirrored at
|
|
# repo.anhonesthost.net via the .gitea/workflows/mirror-base-image.yaml
|
|
# weekly job.
|
|
FROM repo.anhonesthost.net/cloud-hosting-platform/golang:1.25 AS build
|
|
ARG CORAZA_SPOA_VERSION
|
|
# OPTIONAL internal package cache, e.g. --build-arg PKG_CACHE=https://192.168.1.40
|
|
# (CT130 pkg-cache, https only; CI sets it only after probing the cache with the
|
|
# pinned CA). Unset = upstream Debian repositories and the default GOPROXY,
|
|
# exactly as before. Go modules stay verified against go.sum / sum.golang.org
|
|
# (GOSUMDB unchanged). Every RUN that rewrites ends with `restore`, which FAILS
|
|
# the build if any reference to the cache is left. Only build stages use it;
|
|
# nothing from here reaches the distroless runtime image except the binaries.
|
|
# scripts/ + keys/pkg-cache/ in this directory are byte-identical copies of the
|
|
# repo-root ones (this image's build context is ./coraza-spoa); canonical
|
|
# source: cloud-apache-container (scripts/pkg-cache-repos.sh, docs/pkg-cache.md).
|
|
ARG PKG_CACHE=
|
|
COPY ./scripts/pkg-cache-repos.sh /usr/local/sbin/pkg-cache-repos.sh
|
|
COPY ./keys/pkg-cache/ /usr/local/share/pkg-cache/
|
|
WORKDIR /src
|
|
RUN /usr/local/sbin/pkg-cache-repos.sh apt \
|
|
&& apt-get update \
|
|
&& apt-get install -y --no-install-recommends git \
|
|
&& /usr/local/sbin/pkg-cache-repos.sh restore \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
# The source itself is cloned from GitHub over HTTPS (not proxied).
|
|
RUN git clone --depth 1 --branch "${CORAZA_SPOA_VERSION}" \
|
|
https://github.com/corazawaf/coraza-spoa.git . \
|
|
&& eval "$(/usr/local/sbin/pkg-cache-repos.sh go-env)" \
|
|
&& go mod download \
|
|
&& CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o /out/coraza-spoa . \
|
|
&& /usr/local/sbin/pkg-cache-repos.sh restore
|
|
|
|
# Catalog extractor: walks the bundled CRS at build time and emits
|
|
# rules-catalog.json so WHP's UI can render rule metadata without parsing
|
|
# .conf files at runtime. Uses the SAME coraza-coreruleset version pin as
|
|
# the coraza-spoa binary above (drift between the two would mislabel rules).
|
|
FROM repo.anhonesthost.net/cloud-hosting-platform/golang:1.25 AS catalog
|
|
# Same optional package cache as the build stage (module downloads only).
|
|
ARG PKG_CACHE=
|
|
COPY ./scripts/pkg-cache-repos.sh /usr/local/sbin/pkg-cache-repos.sh
|
|
COPY ./keys/pkg-cache/ /usr/local/share/pkg-cache/
|
|
WORKDIR /src
|
|
COPY catalog-extractor/ .
|
|
RUN eval "$(/usr/local/sbin/pkg-cache-repos.sh go-env)" \
|
|
&& go build -trimpath -o /out/catalog-extractor . \
|
|
&& /usr/local/sbin/pkg-cache-repos.sh restore \
|
|
&& /out/catalog-extractor > /out/rules-catalog.json
|
|
|
|
# Distroless runtime: no shell, no package manager, no /tmp by default —
|
|
# smallest attack surface for an exposed service. Audit log directory is
|
|
# bind-mounted; coraza-spoa writes to it via direct file I/O (no shell needed).
|
|
FROM gcr.io/distroless/static-debian12:nonroot
|
|
|
|
LABEL org.opencontainers.image.title="coraza-spoa-whp" \
|
|
org.opencontainers.image.description="Coraza WAF SPOA agent configured for WHP haproxy-manager integration" \
|
|
org.opencontainers.image.source="https://github.com/shadowdao/haproxy-manager-base" \
|
|
org.opencontainers.image.licenses="MIT"
|
|
|
|
COPY --from=build /out/coraza-spoa /coraza-spoa
|
|
COPY config.yaml /etc/coraza-spoa/config.yaml
|
|
COPY overrides.conf /etc/coraza/overrides.conf
|
|
COPY pre-overrides.conf /etc/coraza/pre-overrides.conf
|
|
COPY local-overrides.conf /etc/coraza/local-overrides.conf
|
|
COPY host-exceptions/ /etc/coraza/host-exceptions/
|
|
COPY --from=catalog /out/rules-catalog.json /etc/coraza/rules-catalog.json
|
|
|
|
# Audit log directory — bind-mount /var/log/coraza:/var/log/coraza from host
|
|
# so logs persist across container restarts and AI Monitor can tail them.
|
|
# Distroless nonroot user has UID 65532; the host directory must be writable
|
|
# by that UID (install script will chown it appropriately).
|
|
VOLUME ["/var/log/coraza"]
|
|
|
|
# SPOE TCP port — bound on 0.0.0.0:9000 inside the container. The host-side
|
|
# port mapping is controlled by `docker run -p` (typically not exposed beyond
|
|
# the internal docker network, since haproxy-manager reaches it by container
|
|
# name on client-net).
|
|
EXPOSE 9000
|
|
|
|
ENTRYPOINT ["/coraza-spoa", "--config", "/etc/coraza-spoa/config.yaml"]
|