Kubernetes Deployment
Overview
Section titled “Overview”This guide provides complete Kubernetes manifests for deploying Authgent in production. The deployment includes:
- 2 replicas with rolling updates
- Resource limits and requests
- Health checks (liveness and readiness probes)
- TLS via Ingress
- Signing key stored as a Kubernetes Secret
- Non-sensitive configuration in a ConfigMap
- Horizontal Pod Autoscaler
All manifests use the authgent namespace. Create it first:
kubectl create namespace authgentSecret
Section titled “Secret”Store the signing key and database credentials as Kubernetes Secrets:
apiVersion: v1kind: Secretmetadata: name: authgent-secrets namespace: authgent labels: app.kubernetes.io/name: authgent app.kubernetes.io/component: auth-servertype: OpaquestringData: # Database password db-password: "your-secure-password-here"data: # Base64-encoded EC private key PEM # Generate with: cat ec-private.pem | base64 | tr -d '\n' ec-private.pem: LS0tLS1CRUdJTi4uLg==Create the secret from files instead of inline data:
# Generate the signing keyopenssl ecparam -genkey -name prime256v1 -noout -out ec-private.pem
# Create the secret from fileskubectl create secret generic authgent-secrets \ --namespace authgent \ --from-file=ec-private.pem=ec-private.pem \ --from-literal=db-password="your-secure-password-here"ConfigMap
Section titled “ConfigMap”Non-sensitive configuration:
apiVersion: v1kind: ConfigMapmetadata: name: authgent-config namespace: authgent labels: app.kubernetes.io/name: authgent app.kubernetes.io/component: auth-serverdata: AUTHGENT_ISSUER: "https://auth.yourcompany.com" AUTHGENT_SIGNING_KEY: "/keys/ec-private.pem" AUTHGENT_SIGNING_ALG: "ES256" AUTHGENT_PORT: "8080" AUTHGENT_LOG_LEVEL: "info" AUTHGENT_LOG_FORMAT: "json" AUTHGENT_TOKEN_TTL: "300" AUTHGENT_REFRESH_TTL: "86400" AUTHGENT_DCR_MODE: "constrained" AUTHGENT_DCR_ALLOWED_REDIRECTS: "https://*.yourcompany.com/*" AUTHGENT_KEY_ROTATION_DAYS: "30" AUTHGENT_CORS_ORIGINS: "https://app.yourcompany.com" AUTHGENT_RATE_LIMIT: "100"Deployment
Section titled “Deployment”apiVersion: apps/v1kind: Deploymentmetadata: name: authgent namespace: authgent labels: app.kubernetes.io/name: authgent app.kubernetes.io/component: auth-server app.kubernetes.io/version: "0.1.0"spec: replicas: 2 selector: matchLabels: app.kubernetes.io/name: authgent app.kubernetes.io/component: auth-server strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 0 maxSurge: 1 template: metadata: labels: app.kubernetes.io/name: authgent app.kubernetes.io/component: auth-server app.kubernetes.io/version: "0.1.0" annotations: prometheus.io/scrape: "true" prometheus.io/port: "9090" prometheus.io/path: "/metrics" spec: serviceAccountName: authgent securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 containers: - name: authgent image: authgent/authgent:0.1.0 ports: - name: http containerPort: 8080 protocol: TCP - name: metrics containerPort: 9090 protocol: TCP envFrom: - configMapRef: name: authgent-config env: - name: AUTHGENT_DB_DSN valueFrom: secretKeyRef: name: authgent-secrets key: db-password - name: AUTHGENT_METRICS_PORT value: "9090" # Override DB_DSN to include the password from the secret # In practice, use an init container or external-secrets-operator # to construct the full DSN resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 256Mi livenessProbe: httpGet: path: /health port: http initialDelaySeconds: 10 periodSeconds: 15 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /health port: http initialDelaySeconds: 5 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 3 startupProbe: httpGet: path: /health port: http initialDelaySeconds: 5 periodSeconds: 5 failureThreshold: 12 volumeMounts: - name: signing-key mountPath: /keys readOnly: true volumes: - name: signing-key secret: secretName: authgent-secrets items: - key: ec-private.pem path: ec-private.pem mode: 0400 topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app.kubernetes.io/name: authgentService
Section titled “Service”apiVersion: v1kind: Servicemetadata: name: authgent namespace: authgent labels: app.kubernetes.io/name: authgent app.kubernetes.io/component: auth-serverspec: type: ClusterIP selector: app.kubernetes.io/name: authgent app.kubernetes.io/component: auth-server ports: - name: http port: 8080 targetPort: http protocol: TCP - name: metrics port: 9090 targetPort: metrics protocol: TCPIngress
Section titled “Ingress”apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: authgent namespace: authgent labels: app.kubernetes.io/name: authgent app.kubernetes.io/component: auth-server annotations: cert-manager.io/cluster-issuer: letsencrypt-prod nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/proxy-body-size: "1m" nginx.ingress.kubernetes.io/rate-limit: "100" nginx.ingress.kubernetes.io/rate-limit-burst: "20"spec: ingressClassName: nginx tls: - hosts: - auth.yourcompany.com secretName: authgent-tls rules: - host: auth.yourcompany.com http: paths: - path: / pathType: Prefix backend: service: name: authgent port: name: httpHorizontalPodAutoscaler
Section titled “HorizontalPodAutoscaler”apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: name: authgent namespace: authgent labels: app.kubernetes.io/name: authgent app.kubernetes.io/component: auth-serverspec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: authgent minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 behavior: scaleUp: stabilizationWindowSeconds: 60 policies: - type: Pods value: 2 periodSeconds: 60 scaleDown: stabilizationWindowSeconds: 300 policies: - type: Pods value: 1 periodSeconds: 120ServiceAccount
Section titled “ServiceAccount”apiVersion: v1kind: ServiceAccountmetadata: name: authgent namespace: authgent labels: app.kubernetes.io/name: authgent app.kubernetes.io/component: auth-serverPostgreSQL
Section titled “PostgreSQL”For production, use a managed PostgreSQL service (AWS RDS, GCP Cloud SQL, Azure Database for PostgreSQL). If you need to run PostgreSQL in-cluster:
apiVersion: apps/v1kind: StatefulSetmetadata: name: postgres namespace: authgentspec: serviceName: postgres replicas: 1 selector: matchLabels: app.kubernetes.io/name: postgres app.kubernetes.io/component: database template: metadata: labels: app.kubernetes.io/name: postgres app.kubernetes.io/component: database spec: containers: - name: postgres image: postgres:16-alpine ports: - containerPort: 5432 env: - name: POSTGRES_DB value: authgent - name: POSTGRES_USER value: authgent - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: authgent-secrets key: db-password resources: requests: cpu: 250m memory: 256Mi limits: cpu: "1" memory: 512Mi livenessProbe: exec: command: - pg_isready - -U - authgent - -d - authgent initialDelaySeconds: 10 periodSeconds: 10 volumeMounts: - name: postgres-data mountPath: /var/lib/postgresql/data volumeClaimTemplates: - metadata: name: postgres-data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 10Gi---apiVersion: v1kind: Servicemetadata: name: postgres namespace: authgentspec: type: ClusterIP selector: app.kubernetes.io/name: postgres app.kubernetes.io/component: database ports: - port: 5432 targetPort: 5432When using in-cluster PostgreSQL, set the database DSN in the ConfigMap:
AUTHGENT_DB_DSN: "postgres://authgent:$(DB_PASSWORD)@postgres.authgent.svc.cluster.local:5432/authgent?sslmode=disable"Deploy all manifests
Section titled “Deploy all manifests”# Apply all manifestskubectl apply -f serviceaccount.yamlkubectl apply -f secret.yamlkubectl apply -f configmap.yamlkubectl apply -f postgres.yamlkubectl apply -f deployment.yamlkubectl apply -f service.yamlkubectl apply -f ingress.yamlkubectl apply -f hpa.yaml
# Or apply an entire directorykubectl apply -f k8s/
# Verify the deploymentkubectl -n authgent get podskubectl -n authgent get svckubectl -n authgent get ingress
# Check logskubectl -n authgent logs -l app.kubernetes.io/name=authgent --tail=50
# Verify Authgent is respondingkubectl -n authgent port-forward svc/authgent 8080:8080curl http://localhost:8080/.well-known/oauth-authorization-server | jq .Production checklist
Section titled “Production checklist”- Use a managed PostgreSQL — AWS RDS, GCP Cloud SQL, or Azure Database. Don’t run StatefulSets for databases in production unless you have a dedicated database team.
- Pin image tags — Use
authgent/authgent:0.1.0, neverlatestin production. - Enable TLS — Install cert-manager and use the Ingress TLS configuration above.
- Set resource limits — The defaults above are conservative. Monitor actual usage and adjust.
- Configure topology spread — The
topologySpreadConstraintsensure replicas run on different nodes. - External secrets — Use external-secrets-operator or Sealed Secrets instead of plain Kubernetes Secrets for the signing key.
- Network policies — Restrict traffic so only the Ingress controller and your MCP servers can reach Authgent.
- Backup — Configure automated PostgreSQL backups via your managed database service or Velero.
- Monitoring — Scrape the Prometheus metrics endpoint and set up alerts for error rates and latency.
- Pod Disruption Budget — Add a PDB to prevent all replicas from being evicted simultaneously during node maintenance:
apiVersion: policy/v1kind: PodDisruptionBudgetmetadata: name: authgent namespace: authgentspec: minAvailable: 1 selector: matchLabels: app.kubernetes.io/name: authgent