Skip to content

Run an application with a Performance

A Performance is one application in one Cratis environment. It runs the application, its AuthProxy when the application has authentication, and its own Ante when the application has onboarding: exactly one Ante per Performance, not one per Chronicle or per Production.

apiVersion: showrunner.cratis.io/v1alpha1
kind: Performance
metadata:
name: crm
namespace: apps
spec:
# Either the Production whose Chronicle the application uses ...
productionRef:
name: ledger
# ... or a connection Secret you already have. This takes precedence.
chronicle:
connectionSecretRef:
name: chronicle-connection # key defaults to connectionString
application:
image: registry.example.com/crm:1.0.0
eventStores: [Crm] # the first one is the store Ante observes
environment:
name: production
configMapRef:
name: crm-environment # holds production.yaml, the environment file
passphraseSecretRef: # only for a passphrase environment
name: crm-passphrase
authProxy:
enabled: true
providers:
- kind: EntraId
identity: EntraId
- kind: GitHub
identity: GitHub
onboarding:
enabled: true
signUp: CreateTenant
personas: [Administrator, Member]
legal:
configMapRef:
name: crm-legal # terms.md and privacy.md
ingress:
enabled: true
className: nginx
hosts: [crm.example.com]
tlsIssuer:
name: letsencrypt # a cert-manager ClusterIssuer

productionRef reads the connection Secret name from the Production’s status, which the Production reconciliation fills in once it exists. Until then, or when you run your own Chronicle, name an existing Secret with chronicle.connectionSecretRef. Either way the Secret is mounted into the workloads as a file; it is never copied.

For a Performance named crm:

ResourceNameNotes
Deployment and Servicecrm-appThe application. ClusterIP
Deployment and Servicecrm-authproxyWhen authProxy.enabled. ClusterIP
Deployment and Servicecrm-anteWhen onboarding.enabled. One replica, ClusterIP
NetworkPolicycrm-appFor a published Stage application: only AuthProxy of the Performance may connect to the application
IngresscrmWhen ingress.enabled. Every host routes to AuthProxy and nothing else, with a certificate from cert-manager
Secretscrm-app-environment, crm-authproxy-environment, crm-ante-secrets, crm-signing-keysWhat is mounted into each workload, and the generated keys

AuthProxy is the only public entry point. The application and Ante are ClusterIP Services behind it.

Ante gets its own event store, ante-<name> by default, so two Performances on one Production never share one. Its MongoDB server comes from the environment key ante.mongodb.server.

Nothing is created or changed until everything the Performance needs is in hand: a valid spec, the Chronicle connection, the resolved environment and every environment key the providers and onboarding need. When something is missing the phase is Blocked, the missing keys are listed in status.missingEnvironmentKeys, a condition says why, and the Deployments that already run are left as they are.

The keys needed per provider kind are the ones AuthProxy’s application contract requires: tenantId, clientId and clientSecret for EntraId; authority, clientId and clientSecret for OpenId; clientId and clientSecret for GitHub, Google and Apple. Each is addressed as authentication.providers.<identity>.<key>.

FieldMeaning
phasePending, Blocked, Progressing, Ready or Expired
publicUrlhttps:// and the first ingress host
missingEnvironmentKeysThe keys the environment lacks, while the phase is Blocked
conditionsSpecValid, ChronicleConnection, EnvironmentResolved, EnvironmentComplete, and ApplicationReady, AuthProxyReady, AnteReady per component
signingKeysThe key ids in use, the rotation counter applied and how many previous public keys are pinned
runningVersion, versions, rolloutThe version of a published Stage application that runs, its history and the rollout under way
expiresAt, dataRetainedUntilWhen a lifetime ends, and until when the publisher should keep the data
resourceUsage, currentPeriodUsage, lastPeriodUsageCPU and memory of the pods, accumulated from metrics.k8s.io

Conditions and the status never contain a secret value.

application.published runs the application as a published Stage application instead of an image you built; see Run a published Stage application. lifetime (permanent: true, or until) applies to every Performance: at until the workloads are scaled to zero, the Ingress is removed and the phase is Expired. Usage is sampled from the metrics API on every reconciliation, which is every 30 seconds for a published application.

The operator generates the key Ante signs invitations with and the key AuthProxy signs attestations with, and keeps them in crm-signing-keys. Raise spec.signingKeys.rotation to rotate both. The public half of each replaced key stays pinned (signingKeys.retainPrevious, two by default): Ante verifies invitations signed with a previous key, and Ante’s attestation trust lists every pinned AuthProxy key.

The Performance spec carries the providers and the onboarding behavior; the values come from the environment. The operator derives the rest of both contracts so nobody writes them twice: the invitation issuer and audience (urn:cratis:ante:<store>:<namespace>), the AuthProxy attestation issuer and audience, the public URLs and the generated keys. With onboarding.attestedProviders set, Ante runs attested invitation exchange against AuthProxy’s attestations; without it, Ante keeps the legacy exchange.

AuthProxy forwards every request it lets through to the application’s Service, <name>-app: the operator sets Cratis__AuthProxy__Services__application__Backend__BaseUrl and …Frontend__BaseUrl to it, on application.port (9090 for a published application).

AuthProxy’s onboarding URLs are on the public host, as its contract requires HTTPS outside development. Routing the /_invite and /.well-known/ante paths from AuthProxy to Ante is configured on AuthProxy’s side; set onboarding.lobbyBackendBaseUrl in the environment when your AuthProxy needs it.