Files
ingress/k8s/hanzo/deployment.yaml
zeekay cbd306e98b security: run as non-root user in runtime container
Add unprivileged ingress user (uid 1000) to Dockerfile runtime stage
and set USER directive. Change EXPOSE from 80 to 8080/8443 for safe
defaults in non-K8s usage. K8s deployments override via entrypoint
args and use NET_BIND_SERVICE capability for ports 80/443.

Update K8s deployment securityContext in both hanzo/ and lux/ manifests
to enforce runAsUser=1000, runAsNonRoot=true, and block privilege
escalation.
2026-03-25 01:27:29 -07:00

124 lines
4.0 KiB
YAML

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: hanzo-ingress
namespace: hanzo
labels:
app: hanzo-ingress
app.kubernetes.io/name: hanzo-ingress
app.kubernetes.io/part-of: hanzo-platform
spec:
selector:
matchLabels:
app: hanzo-ingress
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
template:
metadata:
labels:
app: hanzo-ingress
spec:
serviceAccountName: hanzo-ingress
imagePullSecrets:
- name: ghcr-pull-secret
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
# No cloud-specific nodeSelector — runs on any K8s cluster
containers:
- name: ingress
image: ghcr.io/hanzoai/ingress:latest
imagePullPolicy: Always
args:
# Providers — watches Ingress resources with class "ingress"
- "--providers.kubernetesingress=true"
- "--providers.kubernetesingress.ingressclass=ingress"
- "--providers.kubernetesingress.allowemptyservices=true"
- "--providers.kubernetesingress.allowexternalnameservices=true"
- "--providers.kubernetescrd=true"
- "--providers.kubernetescrd.allowcrossnamespace=true"
- "--providers.kubernetescrd.allowexternalnameservices=true"
- "--providers.kubernetescrd.allowemptyservices=true"
# Entrypoints
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entrypoint.to=:443"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.web.http.redirections.entrypoint.permanent=true"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.websecure.http.tls=true"
- "--entrypoints.websecure.http.tls.certresolver=letsencrypt"
# Default security headers on all HTTPS routes
- "--entrypoints.websecure.http.middlewares=security-headers@kubernetescrd"
# ACME / Let's Encrypt via Cloudflare DNS-01
- "[email protected]"
- "--certificatesresolvers.letsencrypt.acme.storage=/data/acme.json"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.resolvers=1.1.1.1:53,8.8.8.8:53"
# Health + observability
- "--ping=true"
- "--ping.entryPoint=web"
- "--api.dashboard=false"
- "--log.level=INFO"
- "--accesslog=true"
- "--accesslog.fields.defaultmode=keep"
- "--accesslog.fields.headers.defaultmode=drop"
env:
- name: CF_API_EMAIL
valueFrom:
secretKeyRef:
name: cloudflare-api-credentials
key: EMAIL
optional: true
- name: CF_API_KEY
valueFrom:
secretKeyRef:
name: cloudflare-api-credentials
key: APIKEY
optional: true
ports:
- name: web
containerPort: 80
hostPort: 80
- name: websecure
containerPort: 443
hostPort: 443
volumeMounts:
- name: data
mountPath: /data
livenessProbe:
httpGet:
path: /ping
port: 80
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ping
port: 80
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: "2"
memory: 512Mi
securityContext:
runAsUser: 1000
runAsGroup: 1000
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
add: ["NET_BIND_SERVICE"]
drop: ["ALL"]
volumes:
- name: data
hostPath:
path: /var/lib/hanzo-ingress
type: DirectoryOrCreate