EQTY LabDocs

Chart Values

Configure values.yaml and secrets.yaml for deployment

View as Markdown

Overview

As you provision external resources (storage, key management, authentication), save the configuration in two files:

  • values.yaml - Non-sensitive configuration (domains, regions, feature flags)
  • secrets.yaml - Sensitive credentials (passwords, API keys, access keys)

These files are used together when deploying the Guardian Platform Helm chart.

Important: Never commit secrets.yaml to version control. The Helm chart will automatically create Kubernetes secrets from the values in this file.

To generate both files, plus the identity provider bootstrap file, use guardctl instead. It covers the minimum configuration; add the remaining settings from the files below.

Configuration File (values.yaml)

Create a values.yaml file with platform configuration. Replace REPLACE_* placeholders with values from the setup guides.

yaml
# Guardian Platform Configuration
# Replace all REPLACE_* placeholders with actual values

global:
  domain: "REPLACE_DOMAIN" # e.g., guardian.example.com

# =============================================================================
# Auth Service
# =============================================================================
auth-service:
  ingress:
    enabled: true
    className: "nginx"
    annotations:
      cert-manager.io/issuer: "letsencrypt-prod"
      nginx.ingress.kubernetes.io/use-regex: "true"
      nginx.ingress.kubernetes.io/rewrite-target: "/$2"
      nginx.ingress.kubernetes.io/proxy-body-size: "64m"
      nginx.ingress.kubernetes.io/proxy-buffer-size: "16k"
      nginx.ingress.kubernetes.io/client-header-buffer-size: "16k"
      nginx.ingress.kubernetes.io/large-client-header-buffers: "4 16k"
    hosts:
      - host: REPLACE_DOMAIN
        paths:
          - path: "/authService(/|$)(.*)"
            pathType: ImplementationSpecific
    tls:
      - secretName: guardian-tls
        hosts:
          - REPLACE_DOMAIN

  config:
    # Identity Provider - From Auth0, Entra ID, or Keycloak setup guide
    idp:
      provider: "REPLACE_IDP_PROVIDER" # "auth0", "entra", or "keycloak"

      # For Auth0 - from Auth0 setup guide
      # issuer: "https://REPLACE_AUTH0_DOMAIN/"
      # auth0:
      #   domain: "REPLACE_AUTH0_DOMAIN"
      #   managementAudience: "https://REPLACE_AUTH0_DOMAIN/api/v2/"
      #   apiIdentifier: "https://REPLACE_DOMAIN"

      # For Entra ID - from Entra ID setup guide
      # issuer: "https://login.microsoftonline.com/REPLACE_TENANT_ID/v2.0"
      # entra:
      #   tenantId: "REPLACE_TENANT_ID"
      #   defaultRoles: "user"

      # For Keycloak - from Keycloak setup guide
      # issuer: "https://REPLACE_KEYCLOAK_HOST/realms/guardian"
      # keycloak:
      #   realm: "guardian"
      #   adminUrl: "https://REPLACE_KEYCLOAK_HOST"
      #   clientId: "guardian-platform-frontend"

    # Token Exchange - Keycloak and Microsoft Entra ID, from the identity provider setup guide
    # tokenExchange:
    #   enabled: true
    #   keyId: "auth-service-001"

    # Key Management - From the key management setup guide
    keyManagement:
      provider: "REPLACE_KMS_PROVIDER" # "azure_key_vault", "aws_kms", "gcp_kms", or "openbao"

      # For Azure Key Vault - from Azure Key Vault setup guide
      # azure_key_vault:
      #   vaultUrl: "https://REPLACE_KEYVAULT.vault.azure.net/"
      #   tenantId: "REPLACE_AZURE_TENANT_ID"

      # For AWS KMS - from AWS KMS setup guide
      # aws_kms:
      #   region: "REPLACE_AWS_REGION"
      #   aliasPrefix: "alias/eqtylab/did"
      #   deletionWindowDays: 7
      #   keyPolicyPrincipalArn: "" # Only for an IAM role with a path, or when STS is unreachable
      #   useIamRole: true # IRSA or instance profile instead of the aws_kms secret

      # For Google Cloud KMS - credentials from Workload Identity, or the gcp_kms secret
      # gcp_kms:
      #   projectId: "REPLACE_GCP_PROJECT_ID" # Required; rendering fails without it
      #   locationId: "REPLACE_GCP_LOCATION" # Required, e.g., us-east1
      #   keyRingId: "eqtylab-did"
      #   scheduledDestroyDays: 24

      # For OpenBao Transit - fresh installations only; keys are P-256
      # openbao:
      #   address: "https://REPLACE_OPENBAO_HOST:8200"
      #   transitMount: "guardian-did"
      #   keyPrefix: "guardian"
      #   ca:
      #     configMapName: "openbao-ca" # PEM bundle for the OpenBao endpoint
      #     key: "ca.pem"
      #   auth:
      #     method: "kubernetes"
      #     mount: "kubernetes"
      #     role: "REPLACE_OPENBAO_ROLE"
      #     audience: "REPLACE_OPENBAO_AUDIENCE"

# =============================================================================
# Governance Service
# =============================================================================
governance-service:
  ingress:
    enabled: true
    className: "nginx"
    annotations:
      cert-manager.io/issuer: "letsencrypt-prod"
      nginx.ingress.kubernetes.io/use-regex: "true"
      nginx.ingress.kubernetes.io/rewrite-target: "/$2"
      nginx.ingress.kubernetes.io/proxy-body-size: "64m"
    hosts:
      - host: REPLACE_DOMAIN
        paths:
          - path: "/governanceService(/|$)(.*)"
            pathType: ImplementationSpecific
    tls:
      - secretName: guardian-tls
        hosts:
          - REPLACE_DOMAIN

  config:
    # Storage Provider - From object storage setup guide
    storageProvider: "REPLACE_STORAGE_PROVIDER" # "azure_blob", "aws_s3", or "gcs"

    # For Azure Blob - from Azure Blob Storage setup guide
    # azureStorageAccountName: "REPLACE_STORAGE_ACCOUNT"
    # azureStorageContainerName: "REPLACE_GOVERNANCE_CONTAINER"

    # For AWS S3 - from AWS S3 setup guide
    # awsS3Region: "REPLACE_AWS_REGION"
    # awsS3BucketName: "REPLACE_GOVERNANCE_BUCKET"
    # awsS3UseIamRole: true # IRSA or instance profile instead of the aws_s3 secret

    # For GCS - from GCS setup guide
    # gcsBucketName: "REPLACE_GOVERNANCE_BUCKET"

    # Auth Provider - From authentication setup guide
    # For Auth0
    # authProvider: "auth0"
    # auth0Domain: "REPLACE_AUTH0_DOMAIN"

    # For Entra ID
    # entraTenantId: "REPLACE_TENANT_ID"

    # For Keycloak
    # keycloakUrl: "https://REPLACE_KEYCLOAK_HOST"
    # keycloakRealm: "guardian"

    # Agent certification - Only with the optional Gateway Stack enabled
    # controlPlaneUrl: "http://{{ .Release.Name }}-gateway-stack-control-plane:10010"

# =============================================================================
# Guardian
# =============================================================================
guardian:
  ingress:
    enabled: true
    className: "nginx"
    annotations:
      cert-manager.io/issuer: "letsencrypt-prod"
      nginx.ingress.kubernetes.io/proxy-body-size: "64m"
    hosts:
      - host: REPLACE_DOMAIN
        paths:
          - path: /
            pathType: Prefix
    tls:
      - secretName: guardian-tls
        hosts:
          - REPLACE_DOMAIN

  config:
    # Auth Provider - From authentication setup guide
    # For Auth0
    # authProvider: "auth0"
    # auth0Domain: "REPLACE_AUTH0_DOMAIN"
    # auth0ClientId: "REPLACE_SPA_CLIENT_ID"
    # auth0Audience: "https://REPLACE_DOMAIN" # Same as auth-service apiIdentifier

    # For Entra ID
    # entraTenantId: "REPLACE_TENANT_ID"
    # entraClientId: "REPLACE_SPA_CLIENT_ID"
    # entraScopes: "openid profile email offline_access api://REPLACE_BACKEND_CLIENT_ID/access_as_user"

    # For Keycloak
    # keycloakUrl: "https://REPLACE_KEYCLOAK_HOST"
    # keycloakRealm: "guardian"
    # keycloakClientId: "guardian-platform-frontend"

    # Branding and display
    # appTitle: "Guardian" # Browser and UI title
    # displayTimezone: "UTC" # IANA timezone for displayed timestamps, e.g., America/New_York

    # Gateway - Only with the optional Gateway Stack enabled (see gateway-stack below)
    # gatewayApiUrl: "https://REPLACE_CONTROL_PLANE_HOST/api" # Required when features.gateway is true
    # llmGatewayUrl: "https://REPLACE_LLM_GATEWAY_HOST" # Shown in agent onboarding commands; blank shows a placeholder
    # features:
    #   gateway: true
    #   agentCertification: true # Governance Programs and agent certification; rendering fails without features.gateway

# =============================================================================
# Integrity Service
# =============================================================================
integrity-service:
  ingress:
    enabled: true
    className: "nginx"
    annotations:
      cert-manager.io/issuer: "letsencrypt-prod"
      nginx.ingress.kubernetes.io/use-regex: "true"
      nginx.ingress.kubernetes.io/rewrite-target: "/$2"
      nginx.ingress.kubernetes.io/proxy-body-size: "0" # No upload limit
    hosts:
      - host: REPLACE_DOMAIN
        paths:
          - path: "/integrityService(/|$)(.*)"
            pathType: ImplementationSpecific
    tls:
      - secretName: guardian-tls
        hosts:
          - REPLACE_DOMAIN

  config:
    # Storage Provider - From object storage setup guide
    integrityAppBlobStoreType: "REPLACE_STORAGE_PROVIDER" # "azure_blob", "aws_s3", or "gcs"

    # For Azure Blob - from Azure Blob Storage setup guide
    # integrityAppBlobStoreAccount: "REPLACE_STORAGE_ACCOUNT"
    # integrityAppBlobStoreContainer: "REPLACE_INTEGRITY_CONTAINER"

    # For AWS S3 - from AWS S3 setup guide
    # integrityAppBlobStoreAwsRegion: "REPLACE_AWS_REGION"
    # integrityAppBlobStoreAwsBucket: "REPLACE_INTEGRITY_BUCKET"
    # integrityAppBlobStoreAwsFolder: "rootstore"
    # integrityAppBlobStoreAwsUseIamRole: true # IRSA or instance profile instead of the aws_s3 secret

    # For GCS - from GCS setup guide
    # integrityAppBlobStoreGcsBucket: "REPLACE_INTEGRITY_BUCKET"
    # integrityAppBlobStoreGcsFolder: "rootstore"

# =============================================================================
# PostgreSQL
# =============================================================================
postgresql:
  enabled: true
  primary:
    persistence:
      enabled: true
      size: 10Gi

# =============================================================================
# Gateway Stack
# =============================================================================
# Requires gatewayDsn in secrets.yaml and the guardian gateway settings above
# See Control Plane Configuration for the remaining controlPlane values
# gateway-stack:
#   enabled: true
#   controlPlane:
#     apiBasePath: "/api"
#     auth:
#       enabled: true # Required; the Control Plane will not start without it
#       # registrationTokenSecret goes in secrets.yaml
#     adapter:
#       trustedComplianceIssuerDIDs: ["REPLACE_PLATFORM_DID"] # Agent certification; see below
#   ingress:
#     enabled: true
#     className: "nginx"
#     controlPlanePath: "/api"
#     hosts:
#       llmGateway: "REPLACE_LLM_GATEWAY_HOST"
#       controlPlane: "REPLACE_CONTROL_PLANE_HOST"

Control Plane Configuration lists the other gateway-stack.controlPlane values, including plugin artifact storage and signing. LLM Gateway Configuration lists the gateway-stack.llmGateway values, including agent registration, plugins, and project context.

Agent Certification

Agent certification lets an organization certify individual agents under its Governance Programs and have the Agent Gateway require those certifications. It needs the Gateway Stack, and is off until you turn it on. The user side is described in Governance Programs and Agent Certifications.

ValueSet it to
guardian.config.features.agentCertificationtrue, with features.gateway: true and gatewayApiUrl. Rendering fails if it is on without features.gateway.
governance-service.config.controlPlaneUrlThe Control Plane’s in-cluster URL, such as http://{{ .Release.Name }}-gateway-stack-control-plane:10010. Empty by default.
gateway-stack.controlPlane.adapter.trustedComplianceIssuerDIDsA list that includes the platform’s signing DID. Unset, it falls back to trustedMembershipIssuerDIDs.
gateway-stack.llmGateway.plugins.enabledtrue, so the gateway runs plugin configurations, including the Agent Certification plugin
gateway-stack.llmGateway.projectContext.modeobserve or enforce, so a project’s plugin configuration applies, including an Agent Certification entry on it. Read the paragraph below before turning it on.

No chart value requires a certification. An Agent Certification plugin entry in enforcement mode does, on the configuration it sits in; see Enforcing certification at the Agent Gateway. To require it per project rather than for every agent, the entry goes in the project’s configuration, which applies only with project context on. Turning project context on changes every agent that presents a project, certified or not: its requests are denied unless the effective configuration has a project membership entry that can admit the project, and that entry’s own mode decides whether a failed membership is denied. observe and enforce currently behave the same. Plan the membership entries first; see Global and project configurations.

Without controlPlaneUrl, starting an assessment fails and no certification is issued. Without the platform DID among the Control Plane’s trusted issuers, every certification is stored as from an untrusted issuer: a reviewer can’t attach it, and Guardian shows it as refused on the gateway, with no configuration standing. The gateway itself judges the issuer by each Agent Certification entry’s trusted_issuers. Setting trustedComplianceIssuerDIDs replaces the fallback to the membership issuers, and the same list decides which project compliance credentials the Control Plane trusts, so keep every issuer you already trust in it.

The platform signing DID

The Guardian Platform signs certifications with Auth Service’s platform key, the same key that signs membership and compliance credentials, so its DID is usually already your trusted membership issuer. To read it, call Auth Service with a signed-in user’s access token and take the document’s id:

bash
curl -s "https://REPLACE_DOMAIN/authService/api/v1/protected/platform/did-doc" \
  -H "Authorization: Bearer $ACCESS_TOKEN" | jq -r .id

It must appear in two places: the Control Plane’s trustedComplianceIssuerDIDs, and the trusted_issuers of every Agent Certification plugin entry, which the gateway checks for itself. A did:key is derived from its public key, so changing the key provider or recreating the key changes the DID: update both lists, and certify agents again, since certifications signed with the old key name the old DID.

The key’s curve follows the key provider. Azure Key Vault, AWS KMS, and Google Cloud KMS sign with secp256k1 (did:key:zQ3s...). OpenBao Transit, supported for fresh installations, signs with P-256 (did:key:zDn...); the Control Plane verifies P-256 certifications from Guardian Platform v1.3 on. See Key Configuration.

The governance worker registers assessments and configurations with the Integrity Service under the Certify Agents permission, which Auth Service grants its governance-worker service account in every organization. It needs no setting beyond the worker credentials every installation has. Signing itself happens on the reviewer’s or administrator’s own token, so only an Audit Owner, Organization Owner, or Project Owner can issue a certification.

Turning it on

Upgrade the platform with the flag off, so no one starts an assessment while services are still rolling out, then turn the flag on with a second upgrade. Services apply their database migrations when their new pods start. If you roll services out separately, follow their dependencies:

  1. Auth Service, then the Integrity Service, which checks Certify Agents with Auth Service and signs through it
  2. The LLM Gateway, whose migrations add the tables and columns the Control Plane reads, then the Control Plane (see Upgrade). If Agent Certification plugin entries exist from an earlier release, publish each again with both grants, then run guardian-plugin publish for the plugin; see the upgrade note under Agent Certification
  3. The Governance Service, which calls the Integrity Service’s assessment routes and attaches certifications to the Control Plane
  4. Guardian, with features.agentCertification: true

From 1.2.x, deploying the Integrity Service before the Governance Service leaves no gap: the earlier Governance Service never calls Integrity’s program or assessment routes, and the project routes it does call are unchanged. The other way round, creating a program and starting or working on an assessment fail until the Integrity Service is upgraded. Project workflows are unaffected either way.

An environment that already ran agent certification on a 1.3 pre-release build has no safe order, so upgrade the two back to back:

  • Integrity Service first: it refuses every agent review until the Governance Service vouches for it.
  • Governance Service first: a reviewer who doesn’t administer programs can’t issue or revoke a certification until the Integrity Service is upgraded. From an early enough build, submitting an assessment fails too.

Before the first agent is certified, check that:

  • governance-service.config.controlPlaneUrl reaches the Control Plane
  • The platform signing DID is in gateway-stack.controlPlane.adapter.trustedComplianceIssuerDIDs, or in trustedMembershipIssuerDIDs with the compliance list unset
  • gateway-stack.llmGateway.plugins.enabled is true, and agent registration is on
  • A platform admin has registered the builtin.agent_certification plugin (see Gateway Policies)
  • Each program has a reviewer who holds a role that can sign: Audit Owner, Organization Owner, or Project Owner
  • On a shared environment, Agent Certification entries are in project configurations, not the global floor, so agents outside those projects aren’t refused; project context is on, with the project membership entries described above in place
  • Each Agent Certification entry lists the platform signing DID in trusted_issuers, and runs in observability until its would-refuse decisions are reviewed, then in enforcement

Secrets File (secrets.yaml)

Create a secrets.yaml file with sensitive credentials. The Helm chart will automatically create Kubernetes secrets from these values.

Before starting the setup guides, fill in the image registry credentials and generate the database password, the authService secrets, and the governance worker encryptionKey. The remaining values come from the setup guides.

yaml
# WARNING: Never commit this file to version control
# WARNING: Replace all placeholders with actual credentials

global:
  secrets:
    # Enable automatic secret creation
    create: true

    # =========================================================================
    # IMAGE REGISTRY
    # =========================================================================
    # Cloudsmith, with values-cloudsmith.yaml, for a version with a verified delivery
    imageRegistry:
      secretName: "platform-image-pull-secret"
      registry: "docker.cloudsmith.io"
      values:
        username: "eqtylab/prod"
        password: "REPLACE_CLOUDSMITH_ENTITLEMENT_TOKEN"
        email: "REPLACE_EMAIL"

    # GHCR, until the version has a verified Cloudsmith delivery
    # imageRegistry:
    #   secretName: "platform-image-pull-secret"
    #   registry: "ghcr.io"
    #   values:
    #     username: "REPLACE_GITHUB_USERNAME"
    #     password: "REPLACE_GITHUB_PAT" # GitHub PAT with read:packages scope
    #     email: "REPLACE_EMAIL"

    # =========================================================================
    # DATABASE CREDENTIALS
    # =========================================================================
    database:
      secretName: "platform-database"
      values:
        username: "postgres"
        password: "GENERATE_SECURE_PASSWORD" # Generate with: openssl rand -hex 32
        # Required with gateway-stack.enabled; repeats the password above, URL-encoded
        # Bundled PostgreSQL shown; an external database uses its host and sslmode=require (see External Database)
        # gatewayDsn: "postgres://postgres:REPLACE_PASSWORD@guardian-platform-postgresql:5432/guardian_gateway?sslmode=disable"

    # =========================================================================
    # AUTH SERVICE
    # =========================================================================
    authService:
      secretName: "platform-auth-service"
      values:
        apiSecret: "GENERATE_API_SECRET" # Generate with: openssl rand -base64 32
        jwtSecret: "GENERATE_JWT_SECRET" # Generate with: openssl rand -base64 32

    # =========================================================================
    # GOVERNANCE WORKER
    # =========================================================================
    governanceWorker:
      secretName: "platform-governance-worker"
      values:
        encryptionKey: "GENERATE_WORKER_KEY" # Generate with: openssl rand -base64 32
        clientId: "REPLACE_WORKER_M2M_CLIENT_ID"
        clientSecret: "REPLACE_WORKER_M2M_CLIENT_SECRET"

    # =========================================================================
    # AUTHENTICATION PROVIDER
    # =========================================================================
    # Configure ONE provider: auth0, entra, or keycloak
    auth:
      provider: "REPLACE_AUTH_PROVIDER" # "auth0", "entra", or "keycloak"

      # For Auth0 - From Auth0 setup guide
      # auth0:
      #   secretName: "platform-auth0"
      #   values:
      #     clientId: "REPLACE_PLATFORM_API_CLIENT_ID"
      #     clientSecret: "REPLACE_PLATFORM_API_CLIENT_SECRET"
      #     mgmtClientId: "REPLACE_AUTH_SERVICE_CLIENT_ID"
      #     mgmtClientSecret: "REPLACE_AUTH_SERVICE_CLIENT_SECRET"

      # For Entra ID - From Entra ID setup guide
      # entra:
      #   secretName: "platform-entra"
      #   values:
      #     clientId: "REPLACE_BACKEND_CLIENT_ID"
      #     clientSecret: "REPLACE_BACKEND_CLIENT_SECRET"
      #     tenantId: "REPLACE_TENANT_ID"
      #     graphClientId: "REPLACE_GRAPH_CLIENT_ID"
      #     graphClientSecret: "REPLACE_GRAPH_CLIENT_SECRET"
      #     tokenExchangePrivateKey: "GENERATE_TOKEN_EXCHANGE_KEY" # Generate with: openssl genrsa 2048

      # For Keycloak - From Keycloak setup guide
      # keycloak:
      #   secretName: "platform-keycloak"
      #   values:
      #     serviceAccountClientId: "guardian-platform-backend"
      #     serviceAccountClientSecret: "REPLACE_BACKEND_CLIENT_SECRET"
      #     tokenExchangePrivateKey: "GENERATE_TOKEN_EXCHANGE_KEY" # Generate with: openssl genrsa 2048

    # =========================================================================
    # STORAGE CREDENTIALS
    # =========================================================================
    storage:
      # For AWS S3 - From AWS S3 setup guide
      # aws_s3:
      #   secretName: "platform-aws-s3"
      #   values:
      #     accessKeyId: "REPLACE_AWS_ACCESS_KEY_ID"
      #     secretAccessKey: "REPLACE_AWS_SECRET_ACCESS_KEY"

      # For Azure Blob - From Azure Blob Storage setup guide
      # azure_blob:
      #   secretName: "platform-azure-blob"
      #   values:
      #     accountKey: "REPLACE_AZURE_STORAGE_KEY"
      #     connectionString: "DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net"

      # For GCS - From GCS setup guide
      # gcs:
      #   secretName: "platform-gcs"
      #   values:
      #     serviceAccountJson: "<service-account-json>"

    # =========================================================================
    # KEY MANAGEMENT
    # =========================================================================
    # Configure ONE provider: azure_key_vault, aws_kms, gcp_kms, or openbao
    keyManagement:
      provider: "REPLACE_KMS_PROVIDER" # "azure_key_vault", "aws_kms", "gcp_kms", or "openbao"


      # For Azure Key Vault - From Azure Key Vault setup guide
      # azure_key_vault:
      #   secretName: "platform-azure-key-vault"
      #   values:
      #     clientId: "REPLACE_AZURE_CLIENT_ID"
      #     clientSecret: "REPLACE_AZURE_CLIENT_SECRET"
      #     tenantId: "REPLACE_AZURE_TENANT_ID"
      #     vaultUrl: "https://REPLACE_VAULT.vault.azure.net/"

      # For AWS KMS - From AWS KMS setup guide; omit with useIamRole
      # aws_kms:
      #   secretName: "platform-aws-kms"
      #   values:
      #     accessKeyId: "REPLACE_KMS_ACCESS_KEY_ID"
      #     secretAccessKey: "REPLACE_KMS_SECRET_ACCESS_KEY"
      #     sessionToken: ""

      # For Google Cloud KMS - omit serviceAccountJson with Workload Identity
      # gcp_kms:
      #   secretName: "platform-gcp-kms"
      #   values:
      #     serviceAccountJson: "<service-account-json>"

      # OpenBao needs no secret with the kubernetes auth method; token_file
      # reads a token from an operator-managed secret named here
      # openbao:
      #   secretName: "REPLACE_OPENBAO_TOKEN_SECRET"

# Control Plane registration token secret - with gateway-stack.enabled; the
# gateway verifies registration tokens with the same value
# gateway-stack:
#   controlPlane:
#     auth:
#       registrationTokenSecret: "REPLACE_REGISTRATION_TOKEN_SECRET" # Generate with: openssl rand -hex 32

Pre-Created Secrets

To manage the secrets outside Helm, leave global.secrets.create at its default false and create the secrets below in the release namespace first. Keep global.secrets.auth.provider (and, for OpenBao with token_file, global.secrets.keyManagement.openbao.secretName) in values.yaml, since the services read them; leave the rest of secrets.yaml out of the install. Choose one approach per release: Helm won’t install over a Secret it didn’t create, with create: false it creates none, and switching an existing release from true to false deletes the Secrets it created.

Every deployment needs these four. The pull secret below is for GHCR, with a GitHub token that has read:packages, until your version has a verified Cloudsmith delivery. For Cloudsmith, create it as in Connected Install and install with values-cloudsmith.yaml:

bash
kubectl create secret generic platform-database \
  --from-literal=password="$(openssl rand -hex 32)" \
  --namespace guardian
# With gateway-stack.enabled, add: --from-literal=gateway-dsn='postgres://...'

kubectl create secret generic platform-auth-service \
  --from-literal=api-secret="$(openssl rand -base64 32)" \
  --from-literal=jwt-secret="$(openssl rand -base64 32)" \
  --namespace guardian

kubectl create secret generic platform-governance-worker \
  --from-literal=encryption-key="$(openssl rand -base64 32)" \
  --from-literal=client-id=<worker-client-id> \
  --from-literal=client-secret=<worker-client-secret> \
  --namespace guardian

kubectl create secret docker-registry platform-image-pull-secret \
  --docker-server=ghcr.io \
  --docker-username=<github-username> \
  --docker-password="$GITHUB_TOKEN" \
  --namespace guardian

Then one identity provider secret:

bash
# Auth0 bootstrap chart: the backend application's credentials for both pairs
# (the manual setup uses the Platform API app, then the Auth Service app)
kubectl create secret generic platform-auth0 \
  --from-literal=client-id=<backend-client-id> \
  --from-literal=client-secret=<backend-client-secret> \
  --from-literal=mgmt-client-id=<backend-client-id> \
  --from-literal=mgmt-client-secret=<backend-client-secret> \
  --namespace guardian

# Microsoft Entra ID: the backend app also serves Graph access
kubectl create secret generic platform-entra \
  --from-literal=client-id=<backend-client-id> \
  --from-literal=client-secret=<backend-client-secret> \
  --from-literal=tenant-id=<tenant-id> \
  --from-literal=graph-client-id=<backend-client-id> \
  --from-literal=graph-client-secret=<backend-client-secret> \
  --from-file=token-exchange-private-key=private-key.pem \
  --namespace guardian

# Keycloak
kubectl create secret generic platform-keycloak \
  --from-literal=service-account-client-id=guardian-platform-backend \
  --from-literal=service-account-client-secret=<backend-client-secret> \
  --from-file=token-exchange-private-key=private-key.pem \
  --namespace guardian

One storage secret:

bash
# AWS S3 without an IAM role
kubectl create secret generic platform-aws-s3 \
  --from-literal=access-key-id=<access-key-id> \
  --from-literal=secret-access-key=<secret-access-key> \
  --namespace guardian

# Azure Blob Storage; connection-string is optional
kubectl create secret generic platform-azure-blob \
  --from-literal=account-key=<account-key> \
  --from-literal=connection-string="<connection-string>" \
  --namespace guardian

# Google Cloud Storage
kubectl create secret generic platform-gcs \
  --from-file=service-account-json=service-account.json \
  --namespace guardian

And one key management secret:

bash
# AWS KMS without an IAM role
kubectl create secret generic platform-aws-kms \
  --from-literal=access-key-id=<access-key-id> \
  --from-literal=secret-access-key=<secret-access-key> \
  --namespace guardian

# Azure Key Vault
kubectl create secret generic platform-azure-key-vault \
  --from-literal=client-id=<client-id> \
  --from-literal=client-secret=<client-secret> \
  --namespace guardian

# Google Cloud KMS without Workload Identity
kubectl create secret generic platform-gcp-kms \
  --from-file=service-account-json=service-account.json \
  --namespace guardian

Confirm they exist before installing:

bash
kubectl get secrets --namespace guardian
SecretKeysUsed byNeeded for
platform-databasepassword, gateway-dsnAuth Service, Governance Service, Integrity Service, bundled PostgreSQL, IdP setup jobs; Gateway Stack reads gateway-dsnAll; gateway-dsn with gateway-stack.enabled
platform-auth-serviceapi-secret, jwt-secretAuth Service; Governance Service reads api-secretAll
platform-governance-workerencryption-key, client-id, client-secretAuth ServiceAll
platform-image-pull-secretdocker-registry typeEvery podAll
platform-auth0client-id, client-secret, mgmt-client-id, mgmt-client-secretAuth Service, Governance Service, Auth0 setup jobAuth0
platform-entraclient-id, client-secret, tenant-id, graph-client-id, graph-client-secret, token-exchange-private-keyAuth Service, Governance Service, Entra setup jobMicrosoft Entra ID; token-exchange-private-key with tokenExchange.enabled
platform-keycloakservice-account-client-id, service-account-client-secret, token-exchange-private-keyAuth Service, Governance ServiceKeycloak; token-exchange-private-key with tokenExchange.enabled
platform-aws-s3access-key-id, secret-access-keyGovernance Service, Integrity ServiceAWS S3 without an IAM role
platform-azure-blobaccount-key, connection-string (optional)Governance Service, Integrity ServiceAzure Blob Storage; account-key with Integrity Service
platform-gcsservice-account-jsonGovernance Service, Integrity ServiceGoogle Cloud Storage
platform-aws-kmsaccess-key-id, secret-access-key, session-token (optional)Auth ServiceAWS KMS without an IAM role
platform-azure-key-vaultclient-id, client-secret, vault-url and tenant-id (see below)Auth ServiceAzure Key Vault
platform-gcp-kmsservice-account-jsonAuth ServiceGoogle Cloud KMS without Workload Identity
  • With Azure Key Vault, set auth-service.config.keyManagement.azure_key_vault.vaultUrl and tenantId in values.yaml, or the Auth Service fails to start. With global.secrets.create: false, they can instead come from the vault-url and tenant-id keys of platform-azure-key-vault.
  • With AWS KMS and temporary credentials, add session-token to platform-aws-kms. With global.secrets.create: false, the Auth Service reads it when the key is present.
  • With Auth0, api-secret must equal auth-service-api-secret in the auth0-management secret; see Auth0.
  • The bootstrap secrets (auth0-management, entra-bootstrap-sp, keycloak-admin, platform-admin) are created during the identity provider setup. The Auth0 and Entra bootstrap charts also create <release>-credentials, where their jobs save the client IDs and new client secrets; Helm keeps it on uninstall.
  • The services read the names in global.secrets.<name>.secretName and .keys; override them there to use other names. Renaming the database secret also needs postgresql.global.postgresql.auth.existingSecret and gateway-stack.database.existingSecret, and renaming its gatewayDsn key also needs gateway-stack.database.secretKeys.dsn; with global.secrets.create: true, rendering fails until the ones in use match.
  • A secret name that resolves to empty fails at render time, before any pod starts.

Other Settings

Settings the files above leave at their defaults, with the values they take:

yaml
global:
  # Shared database connection; empty host uses the bundled PostgreSQL
  postgresql:
    host: ""
    port: 5432
    sslMode: "disable" # disable, require, verify-ca, or verify-full
    sslRootCert:
      secretName: "" # Or configMapName; CA bundle for verify-ca and verify-full
      key: "ca.crt"

  # Mirrored or air-gapped registries
  imageRegistryOverride: "" # e.g., registry.customer.example
  imageRepositoryPrefixOverride: "" # e.g., registry.customer.example/eqtylab
  utilityImages:
    busybox: "" # Dependency wait containers; empty uses busybox:1.36

# Policy report rendering, enabled by default
eqty-pdfgen:
  enabled: true
  config:
    timestampUrl: "http://timestamp.digicert.com" # RFC 3161 timestamp authority

# Identity provider post-install Jobs; empty uses postgres:17-alpine
idpSetupImage: ""
# The Jobs run as UID and GID 70 (the image's postgres user) with a read-only root filesystem
idpSetupPodSecurityContext:
  runAsNonRoot: true
  runAsUser: 70
  runAsGroup: 70
  seccompProfile:
    type: RuntimeDefault
idpSetupSecurityContext:
  runAsNonRoot: true
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop: ["ALL"]

PDFGen Configuration lists the other eqty-pdfgen values, including signing, network policy, and sizing.

Customer Guidance

  • The chart exposes per-service overrides for Auth Service, Governance Service, Guardian, Integrity Service, PDFGen (eqty-pdfgen), and the optional Gateway Stack (gateway-stack).
  • Leave image tags unset. Each chart pins its images to the release version recorded in the release manifest.
  • Prefer global values for shared settings.
  • Use component overrides only when the customer deployment requires them.
  • Store sensitive values in a secrets file or approved secret-management system.
  • Use registry override values for mirrored or air-gapped installs.
  • Use the chart version recorded in the release manifest.

Next Steps

After creating both configuration files:

  1. Fill in the image registry credentials and generate the platform secrets (database, authService, governanceWorker encryptionKey)
  2. Follow the setup guides to obtain provider-specific credentials
  3. Uncomment and fill in sections for chosen providers (Auth0/Entra/Keycloak, S3/Blob/GCS, AWS KMS/Azure Key Vault/Google Cloud KMS/OpenBao)
  4. Replace all REPLACE_* and GENERATE_* placeholders with actual values
  5. Proceed to the Helm Deployment guide