Files
egress/k8s/deployment.yaml
zooqueen 9b41c95886 a grant names a kind, and locking memory checks its allowance first
Buying inference and reading the account behind it were one grant, so the
service that answers prompts also reached the balance, the key's limits and the
usage record. That service is the one carrying /exec, which makes those exactly
the things an attacker inside it would want next. Each operation now carries its
kind and a grant names one, so cloud buys completions and learns nothing about
the account. What mints and revokes keys is still absent under every kind.

Locking memory now reads RLIMIT_MEMLOCK first and skips when the allowance
cannot cover the container. MCL_FUTURE charges every later allocation against
that ceiling, so locking a small heap under a 64 MiB default means an allocation
fails once traffic grows - arriving as a death under load that reads like a
random out-of-memory. The logged skip is the better failure.
2026-08-14 22:56:00 -07:00

85 lines
3.7 KiB
YAML

apiVersion: apps/v1
kind: Deployment
metadata:
name: egress
namespace: hanzo-egress
labels: {app: egress}
spec:
# Stateless: a replica resolves its credentials from KMS at boot and refreshes
# them on a timer, so every replica is identical and interchangeable and none
# is authoritative. Two so a node drain is not an outage on the money path.
replicas: 2
selector:
matchLabels: {app: egress}
strategy:
rollingUpdate: {maxUnavailable: 0, maxSurge: 1}
template:
metadata:
labels: {app: egress}
spec:
serviceAccountName: egress
# Mounted because egress asks the API server to authenticate its callers.
automountServiceAccountToken: true
securityContext:
runAsNonRoot: true
runAsUser: 65532
runAsGroup: 65532
fsGroup: 65532
seccompProfile: {type: RuntimeDefault}
containers:
- name: egress
image: ghcr.io/hanzoai/egress:v0.1.0
imagePullPolicy: IfNotPresent
ports:
- {name: http, containerPort: 8080}
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
privileged: false
capabilities:
drop: ["ALL"]
env:
# KMS is reached in-cluster, not at its public name: the public host
# is fronted by a CDN that refuses a server-side POST, so brokering
# a machine credential against it fails in a way that looks like a
# bad credential.
- {name: EGRESS_KMS, value: "http://cloud.hanzo.svc.cluster.local:8000"}
- {name: EGRESS_KMS_ENV, value: "prod"}
- {name: EGRESS_CLUSTER, value: "https://kubernetes.default.svc"}
# Callers must have their token minted FOR this service. A token
# addressed to anything else is refused, which is what stops one
# workload replaying another's.
- {name: EGRESS_AUDIENCE, value: "egress"}
# Who may spend, on what, and in what way. Written out so it can be
# read. `inference` buys completions; `account` reads the balance and
# key metadata. cloud is the pod that also runs /exec and sandboxes,
# so it is granted inference and NOT account: a compromise there
# cannot read our float, the key's limits, or the usage record.
- name: EGRESS_GRANTS
value: >-
system:serviceaccount:hanzo:cloud=openrouter:inference;
system:serviceaccount:zen:zen=openrouter:inference;
system:serviceaccount:enso:enso=openrouter:inference
- {name: EGRESS_REFRESH, value: "60s"}
# The identity egress reads its own credentials with. It is a MEMBER
# of the org holding them: the secrets plane requires admin scope to
# write, so this identity can read the credential and cannot change
# it. Rotation is a superadmin act, not this pod's.
- name: EGRESS_KMS_ID
valueFrom: {secretKeyRef: {name: egress-kms, key: clientId}}
- name: EGRESS_KMS_SECRET
valueFrom: {secretKeyRef: {name: egress-kms, key: clientSecret}}
livenessProbe:
httpGet: {path: /healthz, port: http}
periodSeconds: 10
timeoutSeconds: 3
readinessProbe:
# False until a credential is actually held, so a replica that
# cannot reach KMS is never sent a call it would have to refuse.
httpGet: {path: /readyz, port: http}
periodSeconds: 10
timeoutSeconds: 3
resources:
requests: {cpu: 50m, memory: 64Mi}
limits: {memory: 256Mi}