FerrisKey Operator

The operator manages FerrisKey instances declaratively, through a custom resource. You describe the cluster you want in a FerrisKeyCluster manifest, and the operator reconciles towards it.

The FerrisKeyCluster resource

The CRD is ferriskeyclusters.ferriskey.rs, API version ferriskey.rs/v1alpha1, namespaced, with the short name fkcl. kubectl get fkcl prints the version, the replica count, readiness, and the current phase.

apiVersion: ferriskey.rs/v1alpha1
kind: FerrisKeyCluster
metadata:
  name: my-ferriskey
  namespace: ferriskey
spec:
  name: my-ferriskey
  replicas: 3
  version: "0.7.0"
  api:
    apiUrl: "https://api.iam.yourorg.com"
    webappUrl: "https://iam.yourorg.com"
    allowedOrigins:
      - "https://iam.yourorg.com"
  database:
    secretRef:
      name: ferriskey-db-credentials
      namespace: ferriskey
    databaseName: ferriskey
    sslMode: require

Spec reference

Every field below is required unless the description says otherwise.

Root

FieldTypeDescription
namestringCluster name
replicasintegerNumber of API replicas
versionstringFerrisKey version to deploy
apiobjectAPI configuration
databaseobjectDatabase configuration

spec.api

FieldTypeDescription
apiUrlstringPublic URL of the API
webappUrlstringPublic URL of the console
allowedOriginsstring[]Optional. Browser origins allowed on every route

As with the standalone deployment, per-client web origins only cover realm-scoped routes. /config, the health probes, and the API documentation carry no realm, so a console served from a different origin than the API has to keep its origin in allowedOrigins.

spec.database

FieldTypeDescription
secretRef.namestringSecret holding the database credentials
secretRef.namespacestringOptional. Defaults to the resource’s namespace
databaseNamestringOptional. Overrides the database name from the Secret
sslModestringOptional. disable, prefer, require, verify-ca, or verify-full

Database Secret format

The referenced Secret must carry host, port, user, and password. database is optional and can be supplied through databaseName instead.

Status

The operator reports cluster status through the status subresource:

status:
  ready: true
  phase: Running
  databaseStatus:
    connected: true
    host: "postgres.database.svc.cluster.local"
    database: "ferriskey"
    lastCheck: "2026-03-17T10:30:00Z"
  conditions:
    - conditionType: Ready
      status: "True"
      lastTransitionTime: "2026-03-17T10:25:00Z"
    - conditionType: DatabaseConnected
      status: "True"
      lastTransitionTime: "2026-03-17T10:24:00Z"
FieldDescription
readyOverall cluster readiness
phaseCurrent phase (Pending, Running, Failed)
messageHuman-readable status message
databaseStatusDatabase connectivity information
conditionsStandard Kubernetes conditions

Deploying

Install the operator

The operator ships as its own Helm chart, which installs the CRD, the operator Deployment, and the RBAC it needs:

helm install ferriskey-operator oci://ghcr.io/ferriskey/charts/ferriskey-operator \
  --namespace ferriskey-system \
  --create-namespace

Create a database secret

kubectl create secret generic ferriskey-db-credentials \
  --namespace ferriskey \
  --from-literal=host=postgres.database.svc.cluster.local \
  --from-literal=port=5432 \
  --from-literal=user=ferriskey \
  --from-literal=password=your-db-password

Apply the FerrisKeyCluster manifest

kubectl apply -f ferriskey-cluster.yaml

Check status

kubectl get fkcl -n ferriskey

CRD and RBAC ownership

By default the chart installs the CRD and annotates it with helm.sh/resource-policy: keep, so helm uninstall leaves it, and your clusters, alone. It also creates a ClusterRole and ClusterRoleBinding letting the operator manage FerrisKeyCluster resources across namespaces.

If either is managed elsewhere, for example through GitOps or a dedicated CRD chart, turn the chart’s copy off:

crds:
  install: false

rbac:
  create: false

Keep the CRD on uninstall

Leave crds.keep at true in production. Deleting the CRD deletes every FerrisKeyCluster in the cluster along with it.