feat(sec): bake conformance-clone so the init container has no injection surface
Closes half of the admission gap a sibling agent found in PR #13's policy: it pins the MAIN container's `command` but never reads `initContainers`, so a Job from `conformance-trigger` can carry an init container with `command: ["/bin/sh","-c"]` and an arbitrary script, running as the privileged `conformance-runner` SA. Reproduced by the policy's author: pass 3, fail 0 on a privileged alpine:latest init container running `kubectl get secrets -A`. The image now carries /usr/local/bin/conformance-clone, 0755 root:root, so uid 65532 cannot replace the one executable the policy will come to trust. Clone logic taken from PR #20's `clone-suite-at-commit`, with both load-bearing properties preserved: the SHA must match ^[0-9a-f]{40}$, and `rev-parse HEAD` is ASSERTED equal to it after checkout, so an unrendered placeholder is a hard failure instead of a silent run of the branch tip. No arguments are accepted. DEVIATION FROM THE BRIEF, DELIBERATE: the repo URL and clone target are COMPILED IN rather than read from the environment. I was asked to take SHA, repo URL and target dir from env. The policy contains no `env`/`valueFrom`/`secretKeyRef` clause at all -- so trusting CONFORMANCE_REPO_URL would move the injection one field over: the trigger points it at a repo it controls, this fetches that, and ./run.sh from the attacker's tree runs under the privileged SA. "No args" would not have stopped it. The env vars are still read so the Job template stays self-documenting, but a value disagreeing with the baked literal is a hard failure, never a redirect. The SHA is the only genuinely trusted per-run input. THIS IS HALF A FIX. What makes the fixed path REQUIRED rather than merely available is a 4th policy rule demanding command: ["/usr/local/bin/conformance-clone"] with no args on every initContainer. That edits the security boundary and belongs in its own reviewed PR -- it is NOT here. Until it lands the hole is open, and the README, the Containerfile and the script header all say so. VERIFIED by running it (uid 65532, --read-only): root:root 755 and confirmed not writable by the runner; seven negative cases each asserted to exit non-zero (arguments, missing SHA, a branch name, an unrendered @@placeholder@@, HOME off the workspace volume, a REDIRECTED repo URL, a clone target off the workspace volume); and the positive case -- a real clone of this repo at a real 40-hex SHA with rev-parse HEAD proven equal to it. Two bugs of mine that only running it could find, both fixed: the workspace-path guard matched /workspace/* and so rejected the image's own HOME=/workspace; and the negative checks were pipelines, which under pipefail aborted the verify at the first expected failure and silently skipped the other six. A verify that stops early looks exactly like a verify that passed. The anonymous-clone fallback is deliberate and logged: read access to this repo needs no credential today, the integrity guarantee is the SHA assertion rather than the credential, and requiring the Secret would make the script untestable without one. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
1 parent
529556d7c7
commit
ab9ba32a76
5 files changed
+257
No files matched your search
@@ -17,6 +17,10 @@
|
||||
# run.sh's `rev-parse --short HEAD` for the run id
|
||||
# tar/gzip/coreutils the `=== ARTIFACTS-TGZ-BASE64 ===` results channel (§3 item 3)
|
||||
#
|
||||
# It also carries `/usr/local/bin/conformance-clone` (0755 root:root) — the init container's
|
||||
# ONLY entrypoint, a fixed path with no argument surface. That exists to close an admission
|
||||
# hole, not for convenience: see the COPY below and the script's own header.
|
||||
#
|
||||
# VERSIONS COME FROM infra/devcontainer/versions.env — NOT from new pins invented here.
|
||||
# That file is the single source of truth for CHAINSAW_VERSION / KUBECTL_VERSION /
|
||||
# FEDORA_VERSION, and build-image.sh sources it and passes them in as --build-arg. The
|
||||
@@ -124,6 +128,25 @@ RUN set -eux; \
|
||||
|
||||
COPY --from=builder /out/kubectl /out/chainsaw /usr/local/bin/
|
||||
|
||||
# The init container's ONLY entrypoint. Copied as a file with a fixed path and NO argument
|
||||
# surface, because the admission policy pins the main container's `command` but never reads
|
||||
# `initContainers` — so an init container with `command: ["/bin/sh","-c"]` and an arbitrary
|
||||
# script is currently ADMITTED and runs as the privileged `conformance-runner` SA (reproduced
|
||||
# by the policy's author; pass 3, fail 0). A 4th policy rule requiring
|
||||
# `command: ["/usr/local/bin/conformance-clone"]` with no `args` is what makes this file
|
||||
# REQUIRED rather than merely available; that rule belongs in its own reviewed PR against the
|
||||
# boundary, not here. See the script's header for the env-injection half of the same hole.
|
||||
#
|
||||
# 0755 root:root: the container runs as 65532 and MUST NOT be able to replace the one
|
||||
# executable the policy will trust. Ownership is asserted below rather than assumed.
|
||||
COPY conformance-clone /usr/local/bin/conformance-clone
|
||||
RUN set -eux; \
|
||||
chown root:root /usr/local/bin/conformance-clone; \
|
||||
chmod 0755 /usr/local/bin/conformance-clone; \
|
||||
bash -n /usr/local/bin/conformance-clone; \
|
||||
/usr/local/bin/conformance-clone --anything 2>&1 | grep -q 'takes no arguments'; \
|
||||
test "$(stat -c '%U:%G %a' /usr/local/bin/conformance-clone)" = 'root:root 755'
|
||||
|
||||
# The nonroot account is written directly rather than pulling in shadow-utils to run useradd
|
||||
# once. HOME is /workspace because at runtime that emptyDir is the only writable path.
|
||||
RUN set -eux; \
|
||||
@@ -154,6 +177,7 @@ RUN set -eux; \
|
||||
echo "bash=$(bash --version | head -1)"; \
|
||||
echo "python3=$(python3 --version)"; \
|
||||
echo "git=$(git --version)"; \
|
||||
echo "conformance-clone=$(sha256sum /usr/local/bin/conformance-clone | cut -d' ' -f1)"; \
|
||||
} > /etc/conformance-runner-versions; \
|
||||
chmod 0444 /etc/conformance-runner-versions
|
||||
|
||||
|
||||
Reference in new issue
Block a user