Files
ingress/k8s/lux/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

129 lines
4.3 KiB
YAML

# Hanzo Ingress — L7 reverse proxy for lux-k8s (DaemonSet, all nodes)
# TLS: ACME DNS challenge via Cloudflare
# Routes: K8s Ingress + CRD providers (no file provider)
# hostNetwork=true: pods bind directly to node ports 80/443 (no LB needed)
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: hanzo-ingress
namespace: lux-system
labels:
app: hanzo-ingress
app.kubernetes.io/name: hanzo-ingress
app.kubernetes.io/part-of: lux-network
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-secret
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
terminationGracePeriodSeconds: 30
containers:
- name: ingress
image: ghcr.io/hanzoai/ingress:latest
imagePullPolicy: Always
args:
# Providers
- --providers.kubernetesingress=true
- --providers.kubernetesingress.allowemptyservices=true
- --providers.kubernetesingress.allowexternalnameservices=true
- --providers.kubernetesingress.disableingressclasslookup=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
# 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
- name: CF_API_KEY
valueFrom:
secretKeyRef:
name: cloudflare-api-credentials
key: apiKey
ports:
- name: web
containerPort: 80
hostPort: 80
protocol: TCP
- name: websecure
containerPort: 443
hostPort: 443
protocol: TCP
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
livenessProbe:
httpGet:
path: /ping
port: 80
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ping
port: 80
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
hostPath:
path: /var/lib/hanzo-ingress
type: DirectoryOrCreate