Skip to main content
Version: 1.0

Deploy to Kubernetes

Deployment topology

The Helm chart (deploy/charts/policyarc-server/) deploys the Authorization Server and OPA as separate Deployments in the same namespace. OPA pulls policy bundles from the AS over in-cluster HTTP.

Namespace: <release-namespace>

├── Deployment: <release>-authorization (1 replica, configurable)
│ └── Container: authorization-server Wolfi Java 17, Spring Boot JAR

├── Deployment: <release>-opa
│ └── Container: opa openpolicyagent/opa, bundle mode

├── Service: <release>-authorization ClusterIP :8080
├── Service: <release>-opa ClusterIP :8181 (internal, AS → OPA)

├── Ingress: <release>-authorization HTTPS termination, routes to AS Service

├── ConfigMap: <release>-opa-config OPA config (bundle source, polling, decision logs)
└── Secret: <release> SPRING_DATASOURCE_PASSWORD, PBAC_BUNDLE_API_KEY, PBAC_ADMIN_API_KEY

Environment variables (issuer, datasource URL, OPA URL, trusted proxy count, instance name) are injected directly into the AS Deployment spec — no separate ConfigMap for non-secret config.


Health checks

The AS exposes Spring Actuator health endpoints. The chart configures probes with conservative delays to allow for JVM startup and Flyway migrations:

livenessProbe:
httpGet:
path: /actuator/health/liveness
port: http
initialDelaySeconds: 60
periodSeconds: 10

readinessProbe:
httpGet:
path: /actuator/health/readiness
port: http
initialDelaySeconds: 30
periodSeconds: 10

OPA uses /health with shorter delays (initialDelaySeconds: 15 / 5).

The readiness probe depends on DB connectivity. A pod that cannot reach MySQL will be marked unready and removed from the Service endpoint set.


Database

MySQL 8 is the primary store. The chart expects an external MySQL instance — it does not deploy one.

  • Managed MySQL (recommended): Azure Database for MySQL Flexible Server, AWS RDS, or Cloud SQL. Pass the JDBC URL via authServer.datasource.url and credentials via secret.datasourcePassword.
  • In-cluster MySQL: Deploy separately (e.g. Bitnami MySQL chart) for dev/staging namespaces.

Schema migrations are applied by Flyway on AS startup (ddl-auto: validate). The DB user needs DDL permissions during initial deploy; tighten to DML-only for runtime.


Scaling

The AS is stateless — no sticky sessions, no local state. It can be scaled horizontally. The chart defaults to 1 replica (authServer.replicaCount). Enable the built-in HorizontalPodAutoscaler to scale on CPU:

authServer:
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70

When autoscaling.enabled is true, the chart omits replicas from the Deployment and creates an HPA resource. All pods share the same MySQL instance, so HikariCP connection pool sizing should account for the maximum pod count.


Secrets

With secret.create: true (the default), the chart creates a Kubernetes Secret containing SPRING_DATASOURCE_PASSWORD, PBAC_BUNDLE_API_KEY, and optionally PBAC_ADMIN_API_KEY. Values are passed via the values file or --set flags at install time.

For production, set secret.create: false and secret.existingName to reference a Secret you manage externally (same key names). This integrates with any secret management approach — External Secrets Operator, Sealed Secrets, or manual creation.


Tech stack

LayerTechnology
ApplicationJava 17, Spring Boot 3.x (Web, Security, Data JPA)
Policy engineOPA (Rego), separate Deployment in bundle mode
DatabaseMySQL 8.x (external, Flyway-managed schema)
Container imageWolfi-based Java 17 (wolfi-java:17)
Package managerHelm
ObservabilityStructured JSON logging to stdout (non-dev); Loki push in dev profile
TestingJUnit 5 + Mockito (unit); Python pytest (integration / E2E)

CI/CD

The project uses the parallelPipeline Jenkins shared library to build two components in parallel from a single repo:

  1. authorization-server (maven) — mvn package → Docker image → push to GitLab container registry
  2. policyarc-server (helm) — lint, template, version injection → package → push to JFrog Helm repository

After CI publishes artifacts, deployment to Kubernetes uses helm upgrade --install with an environment-specific values overlay. See docs/deployment-and-cicd.md for the full Jenkinsfile, overlay structure, and build-pipelines library details.


Next steps

  • Configuration — Environment variables and production hardening checklist
  • Observability — Structured logging, Grafana dashboards, and Loki integration
  • Troubleshooting — Diagnose common deployment and connectivity issues