Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions charts/praxis-gateway/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ AI image; these values may advance independently.
| `commonLabels` | object | `{}` | Labels added to all resources. |
| `podLabels` | object | `{}` | Additional pod labels. Selector labels cannot be overridden. |
| `podAnnotations` | object | `{}` | Pod annotations. |
| `podSecurityContext` | object | `{}` | Extra pod securityContext (`runAsUser`, `runAsGroup`, `fsGroup`, `supplementalGroups`). |
| `podSecurityContext` | object | `{runAsUser: 100, runAsGroup: 101}` | Pod-level securityContext matching the official Praxis AI 0.3.0 image; override the IDs for a compatible image or an OpenShift-assigned UID range. |
| `args` | list | `["--config", "/etc/praxis/praxis.yaml"]` | Container arguments. |
| `config.existingConfigMap` | string | **required** | Name of an existing ConfigMap with the Praxis config. |
| `config.key` | string | `praxis.yaml` | Key in the ConfigMap. |
Expand Down Expand Up @@ -103,15 +103,34 @@ AI image; these values may advance independently.

## Security

The chart enforces Kubernetes restricted security defaults:
The chart enforces Kubernetes restricted security defaults and defaults to the
numeric identity used by the official Praxis AI 0.3.0 image (`praxis:praxis`,
UID 100, GID 101). Numeric IDs are required because Kubernetes cannot verify
that a named image user is non-root when `runAsNonRoot: true` is set.

- `runAsNonRoot: true` (no fixed UID)
- `runAsNonRoot: true`
- `runAsUser: 100`, `runAsGroup: 101` (official AI 0.3.0 defaults)
- `readOnlyRootFilesystem: true`
- `allowPrivilegeEscalation: false`
- All Linux capabilities dropped
- `seccompProfile.type: RuntimeDefault`
- `automountServiceAccountToken: false`

For a compatible image with a different non-root identity, override
`podSecurityContext.runAsUser` and `podSecurityContext.runAsGroup`. On OpenShift,
allow the restricted SCC to assign IDs from the namespace range by clearing the
fixed defaults:

```yaml
podSecurityContext:
runAsUser: null
runAsGroup: null
```

The chart then omits those fields while retaining `runAsNonRoot` and the other
restricted controls. Do not disable `runAsNonRoot`, add capabilities, or enable
privilege escalation.

When overlay-sync is enabled, the pod uses a dedicated ServiceAccount, but
automatic token mounting remains disabled. A short-lived projected token is
mounted only into the overlay-sync init and sidecar containers. The Praxis
Expand Down
13 changes: 8 additions & 5 deletions charts/praxis-gateway/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ podLabels: {}
# -- Annotations on the gateway pod template.
podAnnotations: {}

# -- Extra pod-level securityContext fields (e.g. runAsUser, runAsGroup).
# runAsNonRoot and seccompProfile are always set by the chart.
podSecurityContext: {}
# runAsUser: 100
# runAsGroup: 101
# -- Pod-level securityContext fields. Defaults match the official Praxis AI
# 0.3.0 image (`praxis:praxis`, UID 100, GID 101) so Kubernetes can verify
# runAsNonRoot before creating the container. Override these IDs for a
# compatible image or a platform such as OpenShift that assigns a namespace
# UID range. runAsNonRoot and seccompProfile remain chart-owned.
podSecurityContext:
runAsUser: 100
runAsGroup: 101

# -- Container arguments. Defaults to the config file path.
args:
Expand Down
4 changes: 2 additions & 2 deletions docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ clusters and Docker networks whose names can otherwise collide.

| Area | Command | Topology/config path | Classification | Required when |
|---|---|---|---|---|
| Provider traffic selection and round-robin | `cargo xtask env run-grid-provider-traffic-qualification --forge-config tests/e2e/topologies/grid-provider-traffic/forge.yaml --full --teardown --evidence-dir "$EVIDENCE_DIR"` | `tests/e2e/topologies/grid-provider-traffic/forge.yaml` | Release qualification | Routing, provider candidates, overlay selection policy, provider attribution, or gateway compatibility changes |
| Provider traffic selection and round-robin | `cargo xtask env run-grid-provider-traffic-qualification --forge-config tests/e2e/topologies/grid-provider-traffic/forge.yaml --quick --teardown --evidence-dir "$EVIDENCE_DIR"` | `tests/e2e/topologies/grid-provider-traffic/forge.yaml` | Release qualification | Routing, provider candidates, overlay selection policy, provider attribution, or gateway compatibility changes |
| Distributed token quota | `cargo xtask env run-grid-token-rate-limit-qualification --forge-config tests/e2e/topologies/grid-token-rate-limit/forge.yaml --image-tag "$IMAGE_TAG" --evidence-dir "$EVIDENCE_DIR"` | `tests/e2e/topologies/grid-token-rate-limit/forge.yaml` | Experimental integration qualification | Quota, identity, Basic Auth, Valkey, gateway image, or shared-consumer changes |
| Single-cluster multi-gateway | `cargo xtask env run-grid-single-cluster-multi-gateway-qualification --forge-config tests/e2e/topologies/grid-single-cluster-multi-gateway/forge.yaml --evidence-dir "$EVIDENCE_DIR"` | `tests/e2e/topologies/grid-single-cluster-multi-gateway/forge.yaml` | Integration qualification | Same-site gateway lifecycle, overlay delivery, provider selection, concurrency, or NetworkPolicy behavior changes |
| Combined-site lifecycle | `cargo xtask env run-grid-combined-site-demo --forge-config tests/e2e/topologies/grid-combined-site/forge.yaml --full --teardown --evidence-dir "$EVIDENCE_DIR"` | `tests/e2e/topologies/grid-combined-site/forge.yaml` | Experimental lifecycle qualification | Combined-site routing, provider add/remove/re-add, session fallback, rollout, trust, or lifecycle changes |
Expand All @@ -85,7 +85,7 @@ topologies require the filters documented in their READMEs and may use the
official compatible AI image where applicable.

```console
cargo xtask env run-grid-provider-traffic-qualification --forge-config tests/e2e/topologies/grid-provider-traffic/forge.yaml --full --teardown --evidence-dir "$EVIDENCE_DIR"
cargo xtask env run-grid-provider-traffic-qualification --forge-config tests/e2e/topologies/grid-provider-traffic/forge.yaml --quick --teardown --evidence-dir "$EVIDENCE_DIR"
cargo xtask env run-grid-token-rate-limit-qualification --forge-config tests/e2e/topologies/grid-token-rate-limit/forge.yaml --image-tag "$IMAGE_TAG" --evidence-dir "$EVIDENCE_DIR"
cargo xtask env run-grid-single-cluster-multi-gateway-qualification --forge-config tests/e2e/topologies/grid-single-cluster-multi-gateway/forge.yaml --evidence-dir "$EVIDENCE_DIR"
cargo xtask env run-grid-combined-site-demo --forge-config tests/e2e/topologies/grid-combined-site/forge.yaml --full --teardown --evidence-dir "$EVIDENCE_DIR"
Expand Down
23 changes: 23 additions & 0 deletions scripts/verify-helm-chart.sh
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,29 @@ if grep -Fq "image: ${DEFAULT_GATEWAY_IMAGE}" /tmp/helm-rendered-gateway.yaml; t
else
fail "gateway default image is not ${DEFAULT_GATEWAY_IMAGE}"
fi
DEFAULT_SECURITY=$(helm template verify-gw-security "$GW_DIR" "${GW_REQ[@]}" \
--namespace grid-system --show-only templates/deployment.yaml 2>/dev/null)
if echo "$DEFAULT_SECURITY" | grep -q '^ runAsUser: 100$' && \
echo "$DEFAULT_SECURITY" | grep -q '^ runAsGroup: 101$' && \
echo "$DEFAULT_SECURITY" | grep -q '^ runAsNonRoot: true$' && \
echo "$DEFAULT_SECURITY" | grep -q '^ allowPrivilegeEscalation: false$' && \
echo "$DEFAULT_SECURITY" | grep -q '^ - ALL$'; then
pass "gateway default identity matches official AI 0.3.0 (100:101) with restricted controls"
else
fail "gateway default identity/security context does not match official AI 0.3.0"
fi
OPENSHIFT_SECURITY=$(helm template verify-gw-openshift "$GW_DIR" "${GW_REQ[@]}" \
--namespace grid-system \
--set podSecurityContext.runAsUser=null \
--set podSecurityContext.runAsGroup=null \
--show-only templates/deployment.yaml 2>/dev/null)
if ! echo "$OPENSHIFT_SECURITY" | grep -q '^ runAsUser:' && \
! echo "$OPENSHIFT_SECURITY" | grep -q '^ runAsGroup:' && \
echo "$OPENSHIFT_SECURITY" | grep -q '^ runAsNonRoot: true$'; then
pass "gateway fixed identity can be cleared for OpenShift-assigned IDs"
else
fail "gateway OpenShift identity override did not preserve the expected security context"
fi

# ── Variant renderings ──────────────────────────────────────────────
try_template "$GW_DIR" "edge gateway" "${GW_REQ[@]}" \
Expand Down
Loading