How to Configure Apicurio Authentication

This guide shows you how to stand Keycloak up on a MySQL datastore, switch Apicurio Registry over to authenticating against it, and confirm the registry accepts a token from that realm.

Type

How-to guide

Goal

Move an Apicurio Registry installation from its default access model onto authenticated, role-based access.

Audience

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

When to use

Use this guide before an installation carries production data, since the default allows anonymous reads.

The chart runs Apicurio Registry without authentication by default, so any caller that reaches the registry views, registers and deletes artifacts. Apicurio Registry accepts one authentication method at a time, so to accept OAuth and Basic Auth together, see How to Enable the Apicurio Auth Proxy. For the settings the Axual chart does not wrap, see the Apicurio documentation.

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.

  • Administrator access to the Apicurio Keycloak realm, to check its realm-level roles.

Tools and versions required

You need the following tools:

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

  • curl and jq, for the verification step.

Resources that must exist before starting

The following must already exist:

  • A running Apicurio Registry v3, from How to Enable Apicurio Registry.

  • A DNS name and a TLS certificate for the Keycloak ingress host, because Apicurio Registry reaches Keycloak over HTTPS at that name.

  • A MySQL database for Keycloak, either the one the Apicurio chart bundles or an external instance.

  • The sr-readonly realm-level role in the Apicurio Keycloak realm, when the installation moves to authenticated read access. A realm imported before 2026.1 does not carry it.

Choose a read access model

Decide whether reads stay anonymous or require credentials before you apply any values, because apicurio.auth.anonymous-read-access.enabled sits in the same security block as the rest of the authentication settings. Apicurio Registry Read Access Models compares the two models, states what each exposes, and describes the order in which an existing installation switches over.

Enable the MySQL datastore for Keycloak

Keycloak stores its realm, clients and users in a database, so configure that database first. The Apicurio chart bundles MySQL for this purpose.

Replace every <VALUE> placeholder below with your own value before applying the values or running a command.
values.yaml
apicurio-registry-v3:

  apicurioKeycloakMysql:
    enabled: true
    fullnameOverride: "apicurio-kc-mysql"
    auth:
      rootPassword: "<MYSQL_ROOT_PASSWORD>"
      database: "<KEYCLOAK_DB_NAME>"
      username: "<KEYCLOAK_DB_USERNAME>"
      password: "<KEYCLOAK_DB_PASSWORD>"

The bundled chart is the Bitnami MySQL chart, so its MySQL public documentation lists every value it accepts.

Enable Keycloak

Point Keycloak at the database from the previous section and import the Apicurio realm the Streaming charts ship.

The className: "nginx" value in the example below refers to the community ingress-nginx controller, which was deprecated in March 2026. Axual has migrated to a supported ingress controller. Update this value to match the ingress class configured in your cluster.
values.yaml
apicurio-registry-v3:

  apicurioKeycloak:
    # -- Required when running Apicurio Keycloak on the same k8s cluster as Governance Keycloak
    nameOverride: "apicurio-keycloak"
    enabled: true
    # -- By default, we are importing the Apicurio realm used to Authenticate Admin access
    args: [ 'start', '--import-realm' ]
    realm: "apicurio"
    # -- Required since Keycloak 25.0.1 when running behind an ingress
    proxy:
      mode: xforwarded
      http:
        enabled: true
    autoscaling:
      enabled: false
    database:
      vendor: "mysql"
      hostname: "apicurio-kc-mysql"
      database: "<KEYCLOAK_DB_NAME>"
      port: "3306"
      username: "<KEYCLOAK_DB_USERNAME>"
      password: "<KEYCLOAK_DB_PASSWORD>"

      extraVolumes: |
        - name: keycloak-init-realm
          configMap:
            name: "<APICURIO_FULLNAME>-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: "<KEYCLOAK_ADMIN_PASSWORD>"
        - 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
      className: "nginx"
      rules:
        - # -- The fully qualified domain name of a network host.
          host: "<APICURIO_KEYCLOAK_HOST>"
          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: [ ]

The bundled chart is the Codecentric KeycloakX chart, so its KeycloakX public documentation lists every value it accepts.

Enable Apicurio authentication

Point Apicurio Registry at the Keycloak realm and turn HTTP Basic authentication on. Every other authentication feature depends on security.authentication.enabled, so it stays true for all of them.

values.yaml
apicurio-registry-v3:

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

      # Attributes that are required for Apicurio to access the Keycloak instance
      # in case the security.authentication.enabled is enabled and
      # security.authentication.basicAuthEnabled is enabled
      keycloak:
        authUrl: "https://<APICURIO_KEYCLOAK_HOST>/auth"
        realm: "apicurio"
        webClientId: "apicurio-web"
        webRedirectUrl: "https://<APICURIO_HOST>"

Role-based authorisation and the anonymous read property live in the same security block. Every key the block accepts is listed in Apicurio Chart Values Reference.

Confirm authentication is enforced

Apply the values, then check that the registry accepts a token from the Apicurio Keycloak realm. Request a token with the client credentials grant and call the registry’s search endpoint with it.

TOKEN=$(curl -sk -X POST \
  "https://<APICURIO_KEYCLOAK_HOST>/auth/realms/apicurio/protocol/openid-connect/token" \
  -d "grant_type=client_credentials&client_id=<CLIENT_ID>&client_secret=<CLIENT_SECRET>" \
  | jq -r '.access_token')

curl -sk -o /dev/null -w '%{http_code}\n' \
  -H "Authorization: Bearer $TOKEN" \
  "https://<APICURIO_HOST>/apis/registry/v3/search/artifacts"

The authenticated call returns 200. An empty TOKEN means Keycloak rejected the client credentials, so check the realm import before looking at the registry.

Then open the registry web UI at the webRedirectUrl host. With authentication enabled the UI sends you to the Apicurio Keycloak realm to log in before it loads the artifact list.