Skip to main content

Deployment model

A self-hosted instance is the policyarc-server Helm chart installed in your Kubernetes cluster. The chart needs Kubernetes 1.24 or later. This page lists what the chart runs, what you run yourself, and the values you must set. It describes chart version 0.65.0. The hosted service is not described here.

What the chart runs​

These are the objects the chart renders with its default values, for a release named policyarc.

ObjectNameWhat it is
Deploymentpolicyarc-policyarc-server-authorizationThe authorization server. It serves the OAuth and OpenID Connect endpoints, the Admin API and admin UI, the managed gateway and the policy bundle. authServer.replicaCount sets its replicas, 1 by default.
Deploymentpolicyarc-policyarc-server-opaOPA, image openpolicyagent/opa at the tag in opa.image.tag, 1.10.0 by default. opa.replicaCount sets its replicas, 1 by default.
Servicepolicyarc-policyarc-server-authorization and policyarc-policyarc-server-opaCluster-internal addresses on ports 8080 and 8181
Ingresspolicyarc-policyarc-server-authorizationSends the host in ingress.hosts to the server, through the class in ingress.className, traefik by default
Secretpolicyarc-policyarc-server-credentialsWhen secret.create is true. It always holds the database password and the bundle key, and holds the admin key, the pepper, the credential key and the link secret only when their values are set.
ConfigMappolicyarc-policyarc-server-opa-configOPA's configuration, which points it at the server's bundle endpoint
NetworkPolicyOne for the server and one for OPAOn by default, networkPolicy.enabled
PodDisruptionBudgetOne for the server and one for OPAAt most one pod of each unavailable during a voluntary disruption such as a node drain

Every pod runs as a non-root user with a read-only root file system, drops all Linux capabilities and mounts no service account token. Each has a writable /tmp volume.

These are off by default: a HorizontalPodAutoscaler (authServer.autoscaling.enabled), a headless Service for addressing single pods (authServer.headlessService.enabled), a separate gateway process (gateway.enabled) and a telemetry collector (otelCollector.enabled).

What you run and operate​

You runWhat it needsRead more
PostgreSQL 16It holds all instance state. Each server replica opens up to 20 connections, 19 pooled and 1 for signals between replicas. That one needs a direct route, so a transaction-mode pooler cannot carry it. Keep sslmode=require and the TimeZone=UTC option in authServer.datasource.url.Replicas and upgrades
Database backupsThe chart and the server take no backupsAvailability and recovery
An ingress controller and TLSThe chart's ingress.tls is empty, so TLS is set up at your controller or in that valueReference architecture
The secretsThe server refuses to start without themHarden an instance
Log collectionThe server and OPA write to standard output. OPA's lines hold full decision inputs.Data handling
Metrics scraping/actuator/prometheus answers without a key, so block it at the ingressHarden an instance
UpgradesRun helm upgrade. Each replica runs database migrations at start. A new image does not replace the policy rules an instance already has.Replicas and upgrades
Image pullsSet imagePullSecrets if your registry needs credentials

Values you must set​

ValueWhat it is
authServer.datasource.urlThe JDBC URL of your database. The default points at a host named postgres.
secret.datasourcePasswordThe database password. authServer.datasource.username is pbac by default.
authServer.issuerThe public URL clients use. Tokens and discovery name it.
ingress.hostsThe host name your ingress serves
secret.adminApiKey, secret.adminPepper, secret.credentialKey, secret.bundleApiKey, secret.linkStateSecretThe five server secrets. Mint each one per install.

To keep secrets out of Helm values, set secret.create to false and secret.existingName to a Secret you manage. That Secret needs six keys, SPRING_DATASOURCE_PASSWORD, PBAC_BUNDLE_API_KEY, PBAC_ADMIN_API_KEY, PBAC_ADMIN_PEPPER, PBAC_CREDENTIAL_KEY and PBAC_GATEWAY_LINK_STATE_SECRET, because the chart then reads each one from it.

The chart renders with every secret blank, because its Secret template has no required checks. The server checks the values when it starts. A blank server secret stops the start with a message that names the setting, see Harden an instance. A blank database password stops it earlier. We started the server image with all six values blank, and it exited at its database migration with The server requested SCRAM-based authentication, but no password was provided, naming no Helm value.

Check what the chart renders​

Render the chart before you install it, and compare the objects with the table above. Set POLICYARC_CHART to the chart directory. The block needs helm.

export POLICYARC_CHART="path/to/policyarc-server"
rendered=$(helm template policyarc "$POLICYARC_CHART")
kinds=$(grep '^kind: ' <<<"$rendered" | sort | uniq -c | awk '{print $3 "=" $1}' | tr '\n' ' ')
echo "$kinds"
[ "$kinds" = "ConfigMap=1 Deployment=2 Ingress=1 NetworkPolicy=2 PodDisruptionBudget=2 Secret=1 Service=2 " ] ||
{ echo "Expected the objects in the table above, got: $kinds" >&2; false; }
deployments=$(awk '/^kind: Deployment/ {d = 1; next} d && /^ name:/ {print $2; d = 0}' <<<"$rendered" | sort | tr '\n' ' ')
[ "$deployments" = "policyarc-policyarc-server-authorization policyarc-policyarc-server-opa " ] ||
{ echo "Expected the authorization server and OPA Deployments, got: $deployments" >&2; false; }

With chart version 0.65.0 it lists one each of ConfigMap, Ingress and Secret, and two each of Deployment, NetworkPolicy, PodDisruptionBudget and Service. It renders no StatefulSet, because the chart runs no database.