How to Enable Apicurio Registry

This guide shows you how to switch Apicurio Registry v3 on in the Axual Streaming chart, apply a working base configuration, and confirm the registry is reachable over TLS before you register a schema against it.

Type

How-to guide

Goal

Get Apicurio Registry v3 running as part of an Axual Streaming installation.

Audience

Platform Operator who can edit the Axual Streaming values and apply them.

When to use

Use this guide when installing the streaming layer, or when adding Apicurio Registry to an installation that has none.

Apicurio Registry is a runtime server that stores schemas as artifacts, so producers can reference a schema by id instead of carrying it in every record.

Prerequisites

Confirm the following before you begin.

Access and permissions required

You need the following access and permissions:

  • Permission to edit the Axual Streaming values and apply them.

Tools and versions required

You need the following tools:

  • helm >= 3.12, or access to the pipeline that applies the values.

  • openssl, for the verification step.

Resources that must exist before starting

The following must already exist:

  • A running Apache Kafka cluster, because Apicurio stores its artifacts on a Kafka topic.

  • A DNS name and a server certificate for the registry, plus a client certificate whose identity matches that server certificate.

Apicurio must use a client certificate whose identity matches the DNS name in its server certificate. When they differ, Apicurio cannot obtain the Access Control List (ACL) entries it needs, and the failure appears as an authorisation error rather than a certificate error.

Enable the chart dependency

Axual Streaming charts 3.0.0 and later deploy Apicurio Registry v3 by default. Set global.apicurio-registry-v3.enabled to true in your values so the file states that the registry runs.

global:
  apicurio-registry-v3:
    enabled: true

Apply the base configuration

The example below is a working starting point: it stores artifacts on a Kafka topic and authenticates through Keycloak. Adjust the hostnames, Secret names and Keycloak details to your installation.

Click to open apicurio-values.yaml
global:
  apicurio-registry-v3:
    enabled: true

apicurio-registry-v3:
  logLevel: INFO

  # In Apicurio v3 the web UI runs as its own container.
  # `registryApiUrl` is REQUIRED: it is the public HTTPS URL the browser uses to reach the API.
  # Do NOT use localhost - this URL is resolved by the user's browser, not by the container.
  ui:
    config:
      registryApiUrl: "https://apicurio.<domain>/apis/registry/v3"

  # Application configuration, injected as an application.properties file.
  # Apicurio v3 uses the `apicurio.*` property prefix.
  config:
    apicurio.auth.anonymous-read-access.enabled: "true"
    apicurio.auth.role-based-authorization: "true"
    apicurio.auth.owner-only-authorization: "true"
    apicurio.auth.admin-override.enabled: "true"

  # The configuration related to authentication and authorization of users to the registry.
  # Note: security.authentication.enabled must be enabled for any other authentication feature to work.
  security:
    authentication:
      enabled: true
      basicAuthEnabled: true

      # Attributes required for Apicurio to access the Keycloak instance
      keycloak:
        authUrl: "https://apicurio-keycloak.<domain>/auth"
        realm: "<realm>" # Typically it is set to apicurio
        webClientId: "apicurio-web"
        webRedirectUrl: "https://apicurio.<domain>"

  # Kafka storage. Apicurio v3 uses three topics (journal, snapshots, events). All three are
  # created by the init container below, together with the ACLs for the Apicurio principal.
  kafka:
    # -- Kafka bootstrap servers
    bootstrapServers: "cluster01-kafka-bootstrap:9093"
    # -- KafkaSQL journal topic (typically _{tenant}-{instance}-journal)
    journalTopic: "_<tenant-short-name>-<instance-short-name>-journal"
    # -- KafkaSQL snapshots topic (typically _{tenant}-{instance}-snapshots)
    snapshotsTopic: "_<tenant-short-name>-<instance-short-name>-snapshots"
    # -- Registry events topic (typically _{tenant}-{instance}-events)
    eventsTopic: "_<tenant-short-name>-<instance-short-name>-events"
    # -- Override group prefix to give access to (typically {tenant}.{instance}.apicurio)
    # groupPatternOverride: ""

  tls:
    # -- Existing server Keypair secret name
    serverKeypairSecretName: "server-cert-secret" # Server cert generated from Cert-Manager. Ensure a Kafka superUser matches the DNS of this certificate
    # -- Existing client Keypair secret name
    clientKeypairSecretName: "client-cert-secret" # Client cert generated from Cert-Manager with the right DNS
    # -- Existing truststore secret name
    truststoreCaSecretName: "my-external-ca" # The CA secret used by Cert-Manager to create the previous two certificates

  kafkaInitContainer:
    # -- The principal common name used to produce and consume from the schema topics (should match the one on APICURIO_KAFKASQL_SSL_KEYSTORE_LOCATION)
    # If Kafka is configured to validate ACLs over the full principal chain, please provide the principal chain as this example: [0] CN=Root CA, [1] CN=Intermediate CA, [3] CN=schema-registry
    # Otherwise, just provide the common name prefixed with `CN:`
    apicurioPrincipal: "CN=Apicurio Client"
    # -- Replication factor of the journal, snapshots and events topics
    replicationFactor: "3"
    # -- min.isr of the journal, snapshots and events topics
    minIsr: "2"
    tls:
      # -- Existing Keypair secret name
      keypairSecretName: "server-cert-secret"
      # -- Existing Keypair key name
      keypairSecretKeyName: "tls.key"
      # -- Existing Keypair certificate name
      keypairSecretCertName: "tls.crt"
      # -- Existing Truststore secret name
      truststoreCaSecretName: "my-external-ca"
      # -- Existing Truststore certificate name
      truststoreCaSecretCertName: "ca.crt"

  # Apicurio v3 splits the ingress in two: `backend` serves the API (/apis) and `ui` serves the web UI (/).
  # They can share the same hostname.
  ingress:
    backend:
      # -- Enable creation of the backend Ingress resource (serves /apis).
      enabled: true
      # -- The name of the IngressClass cluster resource.
      # NOTE: "nginx" refers to the community ingress-nginx controller, deprecated March 2026.
      # Axual has migrated to a supported enterprise-grade ingress controller.
      # Update className and annotations to match the ingress controller in your cluster.
      className: "nginx"
      annotations:
        nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
      # -- The fully qualified domain name of a network host.
      host: "apicurio.<domain>"
      tls:
        - hosts:
            - "apicurio.<domain>"
          # This field is required to set the correct certificates on the ingress. Generated from Cert-Manager as well
          secretName: "apicurio-ingress-cert-secret"
    ui:
      # -- Enable creation of the UI Ingress resource (serves /).
      enabled: true
      className: "nginx"
      annotations:
        nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
      host: "apicurio.<domain>"
      tls:
        - hosts:
            - "apicurio.<domain>"
          secretName: "apicurio-ingress-cert-secret"

  apicurioKeycloakMysql:
    enabled: true
    image:
      repository: bitnamilegacy/mysql
    nameOverride: "apicurio-kc-mysql"
    auth:
      rootPassword: "rootpassword"
      database: "apicurio-kc-db"
      username: "keycloak"
      password: "Passw0rd1!"
    primary:
      resources:
        requests:
          cpu: 250m
          memory: 200Mi
        limits:
          memory: 500Mi


  apicurioKeycloak:
    enabled: true
    # -- Required when running Apicurio Keycloak on the same k8s cluster as Governance Keycloak
    nameOverride: "apicurio-keycloak"
    realm: "apicurio"
    # -- Keycloak proxy configuration (required since Keycloak 25.0.1 when running behind an ingress)
    proxy:
      mode: xforwarded
      http:
        enabled: true
    autoscaling:
      enabled: false
    database:
      vendor: "mysql"
      hostname: "streaming-apicurio-kc-mysql"
      database: "apicurio-kc-db"
      port: "3306"
      username: "keycloak"
      password: "Passw0rd1!"
    # -- By default, we are importing the Apicurio realm used to Authenticate Admin access
    args: [ 'start', '--import-realm' ]
    extraVolumes: |
      - name: keycloak-init-realm
        configMap:
          name: streaming-apicurio-registry-keycloak-realm

    extraVolumeMounts: |
      - name: keycloak-init-realm
        mountPath: "/opt/keycloak/data/import"
        readOnly: true

    extraEnv: |
      - name: KEYCLOAK_ADMIN
        value: "admin"
      - name: KEYCLOAK_ADMIN_PASSWORD
        value: "admin123"
      - name: JAVA_OPTS_APPEND
        value: -Djgroups.dns.query={{ template "keycloak.serviceDnsName" . }}
      - name: KC_HTTP_ENABLED
        value: "true"
      - name: KC_HOSTNAME_STRICT
        value: "false"

    ingress:
      enabled: true
      # NOTE: "nginx" refers to the community ingress-nginx controller, deprecated March 2026.
      # Axual has migrated to a supported enterprise-grade ingress controller.
      # Update className and annotations to match the ingress controller in your cluster.
      className: "nginx"
      annotations:
        nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
      rules:
        - # -- The fully qualified domain name of a network host.
          host: "apicurio-keycloak.<domain>"
          paths:
            - # -- Matched against the path of an incoming request.
              path: "/auth"
              # -- Determines the interpretation of the Path matching.
              # Can be one of the following values: `Exact`, `Prefix`, `ImplementationSpecific`.
              pathType: "ImplementationSpecific"
      tls:
        - hosts:
            - "apicurio-keycloak.<domain>"
          # This field is required in order to set the correct certificates to ingress. Generated from Cert-Manager as well
          secretName: "keycloak-ingress-cert-secret"
    resources:
      requests:
        cpu: 450m
        memory: 200Mi
      limits:
        memory: 700Mi

Every key in that file is described in Apicurio Chart Values Reference. For anything the Axual chart does not wrap, see the Apicurio documentation.

Confirm the registry is reachable

Check the certificate chain the registry serves before trying to register anything, because a missing certificate authority here looks like a client problem later.

Replace every <VALUE> placeholder with your own value before running a command.
openssl s_client -showcerts -verify 5 -connect apicurio.<DOMAIN>:443 -servername apicurio.<DOMAIN> < /dev/null

Then attach the registry to an instance with the Apicurio Keycloak configuration steps, register a schema, and produce and consume a record with it from a Java application. That is the end-to-end check.

What to configure next

The base configuration authenticates with Keycloak and allows anonymous reads, which a production installation has to change. Continue with How to Configure Apicurio Authentication.