diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index df1f78b5..a0d7fff7 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -318,6 +318,7 @@ screenshots searchbot searx sebest +seccomp secretplans selfsigned Semrush diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml index bcf9b6f9..d733c18c 100644 --- a/.github/workflows/docs-deploy.yml +++ b/.github/workflows/docs-deploy.yml @@ -52,6 +52,15 @@ jobs: platforms: linux/amd64 push: true + - name: Pin docs image to built digest + working-directory: docs/manifest + env: + DIGEST: ${{ steps.build.outputs.digest }} + run: | + KUSTOMIZE_VERSION=v5.4.3 + curl -fsSL "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/${KUSTOMIZE_VERSION}/kustomize_${KUSTOMIZE_VERSION}_linux_amd64.tar.gz" | tar -xz + ./kustomize edit set image "ghcr.io/techarohq/anubis/docs=ghcr.io/techarohq/anubis/docs@${DIGEST}" + - name: Apply k8s manifests to limsa lominsa uses: actions-hub/kubectl@934aaa4354bbbc3d2176ae8d7cae92d515032dff # v1.35.3 env: diff --git a/docs/Dockerfile b/docs/Dockerfile index 298b3777..898204cd 100644 --- a/docs/Dockerfile +++ b/docs/Dockerfile @@ -1,11 +1,11 @@ -FROM docker.io/library/node:lts AS build +FROM docker.io/library/node:22.22.3-alpine AS build WORKDIR /app COPY . . RUN npm ci && npm run build -FROM ghcr.io/xe/nginx-micro +FROM ghcr.io/xe/nginx-micro:v1.29.0 COPY --from=build /app/build /www COPY ./manifest/cfg/nginx/nginx.conf /conf LABEL org.opencontainers.image.source="https://github.com/TecharoHQ/anubis" \ No newline at end of file diff --git a/docs/docs/CHANGELOG.md b/docs/docs/CHANGELOG.md index 98b40b3f..0aea81d0 100644 --- a/docs/docs/CHANGELOG.md +++ b/docs/docs/CHANGELOG.md @@ -36,6 +36,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix an obscure case where Anubis in subrequest mode could allow redirects to invalid domains with strange instructions. - Fix `path_regex` and CEL `path` rules not matching when using Traefik `forwardAuth` middleware. Anubis now checks `X-Forwarded-Uri` (Traefik) in addition to `X-Original-URI` (nginx) when resolving the request path in subrequest mode ([#1628](https://github.com/TecharoHQ/anubis/issues/1628)). - Validate bounds in the CEL `randInt` helper so non-positive or platform-overflowing arguments surface a typed CEL error instead of an evaluator panic. +- Harden the public docs deployment: add a pod-level security context to the nginx container (non-root uid 101, dropped capabilities, read-only root filesystem, `RuntimeDefault` seccomp) and rebind it to unprivileged port `8080`. +- Pin docs deployment images to immutable digests with `imagePullPolicy: IfNotPresent`, and have the docs-deploy workflow overlay the just-built digest via `kustomize edit set image` so each rollout references an auditable artifact instead of a floating `:main` tag. The docs `Dockerfile` now pins `node` and `nginx-micro` base images to specific versions. ## v1.25.0: Necron diff --git a/docs/manifest/cfg/nginx/nginx.conf b/docs/manifest/cfg/nginx/nginx.conf index 8ff13af7..1ea97dee 100644 --- a/docs/manifest/cfg/nginx/nginx.conf +++ b/docs/manifest/cfg/nginx/nginx.conf @@ -1,7 +1,7 @@ user nginx; worker_processes 2; error_log /dev/stdout warn; -pid /nginx.pid; +pid /tmp/nginx.pid; events { worker_connections 1024; @@ -12,11 +12,17 @@ http { default_type application/octet-stream; access_log /dev/stdout; + client_body_temp_path /tmp/client_body; + proxy_temp_path /tmp/proxy; + fastcgi_temp_path /tmp/fastcgi; + uwsgi_temp_path /tmp/uwsgi; + scgi_temp_path /tmp/scgi; + sendfile on; keepalive_timeout 65; server { - listen 80 default_server; + listen 8080 default_server; server_name _; error_page 404 /404.html; diff --git a/docs/manifest/deployment.yaml b/docs/manifest/deployment.yaml index 4e357cec..68aea0f5 100644 --- a/docs/manifest/deployment.yaml +++ b/docs/manifest/deployment.yaml @@ -20,10 +20,12 @@ spec: name: nginx-cfg - name: temporary-data emptyDir: {} + - name: nginx-tmp + emptyDir: {} containers: - name: anubis-docs - image: ghcr.io/techarohq/anubis/docs:main - imagePullPolicy: Always + image: ghcr.io/techarohq/anubis/docs@sha256:f13a7c862bbcba8e19feba9f157120c6f03e23b03367ace4ca55da69dc894e12 + imagePullPolicy: IfNotPresent resources: limits: memory: "128Mi" @@ -34,23 +36,36 @@ spec: volumeMounts: - name: nginx mountPath: /conf + - name: nginx-tmp + mountPath: /tmp ports: - - containerPort: 80 + - containerPort: 8080 readinessProbe: httpGet: path: / - port: 80 + port: 8080 initialDelaySeconds: 1 periodSeconds: 10 livenessProbe: httpGet: path: / - port: 80 + port: 8080 initialDelaySeconds: 10 periodSeconds: 20 + securityContext: + runAsUser: 101 + runAsGroup: 101 + runAsNonRoot: true + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault - name: anubis - image: ghcr.io/techarohq/anubis:main - imagePullPolicy: Always + image: ghcr.io/techarohq/anubis@sha256:533e57956ae3afd1612dab16f02dd4db937ca14fad5399208f403686e14feed5 + imagePullPolicy: IfNotPresent env: - name: "BIND" value: ":8081" @@ -65,7 +80,7 @@ spec: - name: "SERVE_ROBOTS_TXT" value: "false" - name: "TARGET" - value: "http://localhost:80" + value: "http://localhost:8080" # - name: "SLOG_LEVEL" # value: "debug" volumeMounts: diff --git a/docs/manifest/service.yaml b/docs/manifest/service.yaml index 1acdc45d..615fe5f6 100644 --- a/docs/manifest/service.yaml +++ b/docs/manifest/service.yaml @@ -7,7 +7,7 @@ spec: app: anubis-docs ports: - port: 80 - targetPort: 80 + targetPort: 8080 name: http - port: 8081 targetPort: 8081