Skip to content

Docker hardening: non-root user, build attestations, and runtime lockdown #467

Open

Description

@irvingpop

Summary

A Docker Scout scan of pybot:staging (built from PR #466, commit ee8800a) failed 3 of 7 policies. None of these come from PR #466, and none block it. Fix them in one follow-up PR, together with the general hardening items below.

docker scout quickview 633607774026.dkr.ecr.us-east-2.amazonaws.com/pybot:staging

 !  Image runs as the root user
 !  Copyleft licensed packages found              400 packages
 ✓  No fixable critical or high vulnerabilities   0C 0H 0M 0L
 ✓  No high-profile vulnerabilities
 ✓  No outdated base images
 ✓  No unapproved base images
 !  Required supply chain attestations missing    2 deviations

Policy findings

1. The image runs as root (fix)

docker/Dockerfile has no USER instruction, so python -m pybot runs as UID 0. The app listens on port 5000 and does not need root.

  • In the prod stage, create a system user with a fixed UID (for example useradd --system --uid 10001 --no-create-home pybot) and add USER pybot before CMD.
  • Keep /app owned by root and not writable by the app user (COPY --from=builder without --chown). Check that nothing writes to /app at runtime: logging config and __pycache__ (the venv is compiled at build time with --compile).
  • Use a numeric USER 10001:10001 so platforms that check runAsNonRoot can verify it.

2. Build attestations are missing (fix)

build-push-action in the CI workflow sets provenance: false, and SBOM generation is not turned on. Scout reports that the image has no SLSA provenance and no SBOM attestation.

  • Set provenance: mode=max and sbom: true.
  • Find out why provenance: false was set first. It was often a workaround for ECS or ECR failing on the image index that attestations create. ECR supports OCI referrers and ECS handles image indexes now, but test a staging deploy before you merge.

3. Copyleft licensed packages (accept)

There are 400 packages, almost all from the Debian python:3.14.10-slim-trixie base image (GPL and LGPL system packages). This is expected for a Debian image, and pybot is not distributed as a binary. No action is needed unless we move to a distroless or Chainguard base (see below). Record the decision in the PR.

Known unfixed CVEs (track only)

Debian has not released fixes for these. A rebuild picks up patches when Debian publishes them (the Dockerfile already runs apt-get upgrade).

Package CVE Severity
zlib 1.3.1-1+deb13u1 CVE-2026-85091 High
zlib 1.3.1-1+deb13u1 CVE-2026-76844 High
tar 1.35+dfsg-3.1 CVE-2025-45582 Medium

General hardening (same PR)

  • Pin the base image by digest: FROM python:3.14.10-slim-trixie@sha256:.... Dependabot's docker ecosystem updates digests.
  • Remove wget from the runtime image. It is used only by HEALTHCHECK. Use python -c "import urllib.request; urllib.request.urlopen('http://localhost:5000/health', timeout=4)" instead. Check whether the ECS task definition has its own health check that calls wget.
  • Remove tar and other unused tools from the runtime stage if possible, or evaluate a distroless or Chainguard Python base. That also removes most of the copyleft packages and base-image CVEs.
  • Signal handling: confirm that python -m pybot as PID 1 shuts down cleanly on SIGTERM during ECS deploys. If not, add --init or enable initProcessEnabled in the task definition.
  • ECS task definition (infrastructure repo): readonlyRootFilesystem: true (add a tmpfs mount if anything needs /tmp), user: "10001", and linuxParameters.capabilities.drop: ["ALL"].
  • Add a Scout gate to CI: run docker/scout-action with command: cves and only-fixed: true, so that fixable critical and high CVEs fail the build.

Done when

  • docker scout quickview shows the "root user" and "supply chain attestations" policies as met.
  • A staging deploy is healthy with the new image (the ECS health check passes and the bot answers Slack events).
  • The copyleft decision is recorded in the PR.

Found during the review of #466.

🤖 Generated with Claude Code

Activity

  1. added
    problem: securityIssue is related to application or infrastructure security
    priority: mediumThis is an issue that has some urgency but isn't an emergency
    type: infrastructureIssue involves a change to current infrastructure
    on Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: mediumThis is an issue that has some urgency but isn't an emergencyproblem: securityIssue is related to application or infrastructure securitytype: infrastructureIssue involves a change to current infrastructure

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions