diff --git a/.trivyignore.yaml b/.trivyignore.yaml new file mode 100644 index 0000000..93b6b2c --- /dev/null +++ b/.trivyignore.yaml @@ -0,0 +1,26 @@ +# Trivy misconfiguration exceptions — intentional, security-reviewed accepts. +# +# HIGH/CRITICAL findings are FIXED in-tree, never ignored: +# - DS-0029 : Dockerfile builder now uses `apt-get install --no-install-recommends`. +# - KSV-0014 : readOnlyRootFilesystem: true on the chart default + dev manifest. +# - KSV-0118 : explicit pod + container securityContext on the chart default + dev manifest. +# +# Only these MEDIUM, by-design findings are accepted, each scoped to its file with a rationale. +misconfigurations: + - id: KSV-0013 + paths: + - "go/authn/manifests/deploy.local.yaml" + statement: >- + Local-only dev manifest: authn:latest is built locally and run with imagePullPolicy: Never. + Not a shipped artifact — the Helm chart resolves a real, pinned image tag. + - id: KSV-0113 + paths: + - "go/authn/manifests/deploy.local.yaml" + statement: >- + authn's core function is issuing and persisting kubeconfigs as Kubernetes Secrets, so its + ServiceAccount must manage namespace secrets. This is a required capability, not a misconfig. + - id: KSV-0111 + paths: + - "go/authn/testdata/ldap-forumsys.yaml" + statement: >- + Test fixture exercising an admin-access user mapping. testdata only, never deployed. diff --git a/go/authn/Dockerfile b/go/authn/Dockerfile index 5efa768..804a58c 100644 --- a/go/authn/Dockerfile +++ b/go/authn/Dockerfile @@ -7,7 +7,7 @@ ARG DEBIAN_FRONTEND=noninteractive SHELL ["/bin/bash", "-o", "pipefail", "-c"] # hadolint ignore=DL3008 -RUN apt-get update && apt-get install -y ca-certificates openssl git tzdata && \ +RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates openssl git tzdata && \ update-ca-certificates && \ rm -rf /var/lib/apt/lists/* diff --git a/go/authn/manifests/deploy.local.yaml b/go/authn/manifests/deploy.local.yaml index 18e7430..6161334 100644 --- a/go/authn/manifests/deploy.local.yaml +++ b/go/authn/manifests/deploy.local.yaml @@ -73,6 +73,15 @@ spec: app: authn spec: serviceAccountName: authn + # Mirror the chart's hardened defaults so local dev matches prod posture. The image is + # distroless/static:nonroot (UID/GID 65532); authn writes kubeconfigs as Secrets via the API. + securityContext: + runAsNonRoot: true + runAsUser: 65532 + runAsGroup: 65532 + fsGroup: 65532 + seccompProfile: + type: RuntimeDefault volumes: # The RSA private key authn signs RS256 JWTs with. Create it first: # openssl genrsa -out private.pem 2048 @@ -89,6 +98,15 @@ spec: #image: kind.local/authn:latest image: authn:latest imagePullPolicy: Never + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsNonRoot: true + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault args: - --debug=true - --kubeconfig-server-url=https://127.0.0.1:57456 diff --git a/helm/authn/values.yaml b/helm/authn/values.yaml index f051e1f..45f0959 100644 --- a/helm/authn/values.yaml +++ b/helm/authn/values.yaml @@ -35,16 +35,27 @@ serviceAccount: podAnnotations: {} podLabels: {} -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 +# Hardened by default. The shipped image is gcr.io/distroless/static:nonroot (USER nonroot, +# UID/GID 65532); authn persists kubeconfigs as Kubernetes Secrets via the API (never the local +# filesystem) and listens on an unprivileged port, so runAsNonRoot + readOnlyRootFilesystem are +# safe. Override per-field if you run a custom image with a different user. +podSecurityContext: + runAsNonRoot: true + runAsUser: 65532 + runAsGroup: 65532 + fsGroup: 65532 + seccompProfile: + type: RuntimeDefault + +securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsNonRoot: true + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault service: annotations: {}