<a id="gateway-security"></a>

<a id="gateway-security-docker"></a>

# Configure Security for Confluent Cloud Gateway

This section provides details on the following security configurations for
Confluent Cloud Gateway (Confluent Gateway) using Docker Compose.

* [Authentication](#gateway-auth-docker)
* [TLS/SSL](#gateway-ssl-docker)
* [Secret stores](#gateway-secret-stores-docker)
* [Passwords](#gateway-password-docker)

For the security configuration steps using Confluent for Kubernetes (CFK), see
[Configure Security for Confluent Gateway using CFK](https://docs.confluent.io/operator/current/gateway/co-gateway-security.html).

The top-level layout for the Confluent Gateway security configuration is as follows:

```yaml
gateway:
  secretStores:
  streamingDomains:
    kafkaCluster:
      bootstrapServers:
        - id:
          endpoint:
          ssl:
  routes:
    - name:
      security:
        auth:
        ssl:
        swapConfig:
        passthroughConfig:
```

For `streamingDomains.kafkaCluster.bootstrapServers.ssl` and
`routes.security.ssl`, see the [SSL configuration](#gateway-ssl-docker) section.

<a id="gateway-security-best-practices"></a>

## Security best practices and recommendations

**Use unique Gateway-to-Broker credentials per client**

In Confluent Gateway deployments, there are two authentication
layers in security configuration scenarios:

* Client → Confluent Gateway (SASL/PLAIN, SASL/SCRAM, SASL/OAUTHBEARER,
  mTLS, or NONE)
* Confluent Gateway → Broker (SASL/PLAIN, SASL/OAUTHBEARER, or NONE), with
  secrets stored in AWS Secrets Manager, HashiCorp Vault, Azure Key
  Vault, CyberArk Conjur, or a local directory.

Following are authentication best practices:

* Choose SASL/SCRAM over SASL/PLAIN. Unlike SASL/PLAIN, SCRAM doesn’t
  send passwords in cleartext and protects against dictionary attacks
  using salted hashes.
* Don’t map multiple client users to a single Confluent Gateway-to-Broker credential.
* Each client should ideally have its own Confluent Gateway-to-Broker SASL credential.
* Avoid static shared credentials across multiple clients.

<a id="gateway-auth-docker"></a>

## Authentication configuration

Confluent Gateway supports two modes for authenticating clients and forwarding traffic
to Kafka clusters: **identity passthrough** and **authentication swapping**.

* **Identity passthrough:** Client credentials are forwarded directly to Kafka
  clusters without modification.

  Use identity passthrough for environments where the authentication
  method is uniform and Confluent Gateway transparency is sufficient.

  With identity passthrough, SASL authentication mechanisms, such as
  SASL/PLAIN, SASL/SCRAM, or SASL/OAUTHBEARER, are supported.
* **Authentication swapping:** Client credentials are transformed into different
  credentials before connecting to Kafka clusters.

  When enabled, Confluent Gateway authenticates incoming clients, optionally
  using a different authentication mechanism than the backing Kafka cluster.
  Confluent Gateway then swaps the client identity and credentials as it forwards
  requests to brokers.

  With authentication swapping,
  : * SASL/PLAIN, SASL/SCRAM, mTLS, or NONE authentication is
      supported for client-to-Confluent Gateway authentication.
    * SASL/PLAIN, SASL/OAUTHBEARER, or NONE authentication is supported
      for Confluent Gateway-to-Kafka cluster authentication.

  Use authentication swapping when you need to:
  * Migrate clients between source and destination clusters that have different
    authentication requirements, without modifying client applications.
  * Share cluster access with external clients while maintaining your internal
    authentication standards, even when you can’t enforce those standards
    directly on the client side.

  The following diagram shows a sample authentication flow for
  authentication swapping:
  ![image](cp-component/gateway/images/CC-Gateway-auth-translation.png)

Some considerations when selecting the authentication mode in Confluent Gateway are:

- You can configure either identity passthrough or authentication swapping for
  an individual route.
- You cannot configure multiple authentication mechanisms for the same route
  while using authentication swapping.
- Identity passthrough cannot be used for mTLS due to TLS termination at
  Confluent Gateway; currently, authentication swapping is mandatory for mTLS clients.
- Swapping mandates more setup (identity stores, KMS, mappings) but adds
  flexibility and supports more complex enterprise scenarios.
- Authentication swapping with multi-cluster streaming domains
  requires identical user identities and role-based access control (RBAC) policies across
  all clusters. If clusters have different authentication systems or
  user permissions, use separate streaming domains instead.

<a id="gateway-authn-passthrough-docker"></a>

### Configure identity passthrough mode

When a route is configured for identity passthrough, the Confluent Gateway forwards
unaltered authentication information (no interception) directly to Kafka brokers,
and it does not itself authenticate incoming clients. The brokers perform
authentication and authorization checks.

Identity passthrough is supported for SASL authentication mechanisms, such as
SASL/PLAIN, SASL/SCRAM, or SASL/OAUTHBEARER.

**To configure a route for identity passthrough in Docker Compose:**

```yaml
gateway:
  routes:
    - name:
      security:
        auth: passthrough              --- [1]
        passthroughConfig:             --- [2]
          sasl:
            mechanism:                 --- [3]
            extensionHeaders:          --- [4]
              logicalCluster:
```

* [1] The authentication mode for the route. Set to `passthrough` to
  enable identity passthrough.
* [2] Optional. Configures Confluent Gateway to inject SASL extension headers into the
  client’s authentication request before forwarding it to the backing Kafka
  cluster. Use `passthroughConfig` when clients authenticate with
  SASL/OAUTHBEARER and the backing Kafka cluster requires a logical cluster
  (`lkc`) extension to identify the target cluster. Confluent Gateway sets the
  extension on the client’s behalf, which keeps client configurations
  independent of the active cluster, so authentication continues to succeed
  after a failover.
* [3] The client SASL mechanism that `passthroughConfig` applies to.
  `OAUTHBEARER` is the only supported value.
* [4] One or more SASL extension headers that Confluent Gateway adds to the client’s
  authentication request to the backing Kafka cluster. Each header is a
  key-value pair. Set `logicalCluster` to the target cluster ID, for
  example, `lkc-abc123`.

**Example: inject a logical cluster header for SASL/OAUTHBEARER passthrough:**

```yaml
gateway:
  routes:
    - name:
      security:
        auth: passthrough
        passthroughConfig:
          sasl:
            mechanism: OAUTHBEARER
            extensionHeaders:
              logicalCluster: 'lkc-abc123'
```

<a id="gateway-authn-swap"></a>

<a id="gateway-authn-swap-docker"></a>

### Configure authentication swapping mode

When a route is configured for authentication swapping, Confluent Gateway authenticates
incoming clients, optionally using a different authentication mechanism than the
backing Kafka cluster. Confluent Gateway then swaps the client identity and credentials
as it forwards requests to Kafka brokers.

Authentication swapping requires configuration of identity mapping, potentially
integration with external Key Management Systems (KMS) or secret stores, and
audit policies.

The following secret stores are supported for fetching credentials:

* HashiCorp Vault
* AWS Secrets Manager
* Azure Key Vault
* CyberArk Conjur
* File

**To configure a route for authentication swapping in Docker Compose:**

```yaml
gateway:
  routes:
    - name:               --- [1]
      security:
        auth: swap        --- [2]
        swapConfig:
          clientAuth:     --- [3]
          secretStore:    --- [4]
          clusterAuth:    --- [5]
```

* [1] The unique name for the route.
* [2] The authentication mode for the route. Set to `swap` to enable
  authentication swapping.
* [3] How clients authenticate to Confluent Gateway. See
  [Client authentication for authentication swapping](#gateway-authn-swap-client-docker).
* [4] Reference to a secret store for exchanging credentials. See
  [Secret store configuration](#gateway-secret-stores-docker).
* [5] How Confluent Gateway authenticates to the Kafka cluster after swapping. See
  [Cluster authentication for authentication swapping](#gateway-authn-swap-cluster-docker).

<a id="gateway-authn-swap-client-docker"></a>

#### **Client authentication for authentication swapping**

Define how clients authenticate to the Confluent Gateway. Enable exactly one
authentication provider:

* SASL
* mTLS
* None

**SASL/PLAIN authentication**

```yaml
gateway:
  routes:
    - name:
      security:
        auth: swap
        swapConfig:
          clientAuth:
            sasl:
              mechanism:               --- [1]
              callbackHandlerClass:    --- [2]
              jaasConfig:
                file:                  --- [3]
            connectionsMaxReAuthMs:    --- [4]
```

* [1] The SASL mechanism to use. Set to `PLAIN` for SASL/PLAIN authentication.
* [2] The callback handler class to use. Set to
  `org.apache.kafka.common.security.plain.internals.PlainServerCallbackHandler`
  for SASL/PLAIN authentication.
* [3] The path to the JAAS configuration file. See below for the JAAS
  configuration file content.
* [4] The maximum re-authentication time in milliseconds.

**JAAS configuration file content for SASL/PLAIN authentication**

```properties
org.apache.kafka.common.security.plain.PlainLoginModule required
    username="admin"
    password="admin-secret"
    user_admin="admin-secret";
```

The JAAS configuration file content is a single login-module entry, ending in
`;`, with the following properties:

* `org.apache.kafka.common.security.plain.PlainLoginModule`: The
  login module to use.
* `username`: The username to use.
* `password`: The password to use.
* `user_<username>`: Defines the password for each user that connects to
  Confluent Gateway. Add one `user_<username>` property per user.

A sample JAAS configuration file content:

```properties
org.apache.kafka.common.security.plain.PlainLoginModule required
    username="admin"
    password="admin-secret"
    user_admin="admin-secret"
    user_additional-user="additionaluser-secret";
```

**SASL/SCRAM authentication**

Confluent Gateway supports SASL/SCRAM authentication for client-to-Confluent Gateway
connections. When using SCRAM with authentication swapping, you have
three options for managing SCRAM credentials:

* **Store SCRAM credentials in the same secret store as authentication
  swapping:** SCRAM credentials are stored in the route’s secret
  store.
* **Store SCRAM credentials in a SCRAM-specific secret store:** SCRAM
  credentials are stored in a separate secret store from other
  authentication swap credentials.
* **Manage SCRAM credentials with the Kafka administrator API:**
  Confluent Gateway can automatically manage SCRAM credentials by creating and
  updating SCRAM user credentials through the Kafka administrator API.

SCRAM doesn’t store a plain password. It stores derived cryptographic
material, a salted hash, which can only be represented as structured JSON,
not a plain string.

#### NOTE
Regardless of the `useJson` setting on the secret store, Confluent Gateway
always requires SCRAM credentials to be stored as JSON. `useJson`
only affects how the secret store provider returns raw, non-SCRAM
secret values, such as PLAIN username and password credentials.

```yaml
gateway:
  routes:
    - name:
      security:
        auth: swap
        swapConfig:
          secretStore: vault-store   --- [1]
          clientAuth:
            sasl:
              mechanism: SCRAM   --- [2]
              scram:
                alterScramCredentials: true   --- [3]
                scramCredentialsTtlMs: 600000   --- [4]
                secretStore: scram-vault-store --- [5]
                admin:                          --- [6]
                  username: admin-user
                  password: admin-password
```

* [1] The secret store reference for authentication swapping. For
  more information, see [Secret store configuration](#gateway-secret-stores-docker).
* [2] The SASL mechanism to use for client authentication. Set to
  `SCRAM` for SASL/SCRAM authentication.
* [3] Optional. When set to `true`, enables Confluent Gateway to manage
  SCRAM user credentials by creating and updating them through the
  Kafka Admin API. This field requires administrator credentials. The
  default is `false`.
* [4] Optional. The time-to-live, in milliseconds, for cached SCRAM
  credentials. The default is `600,000` (10 minutes).
* [5] Optional. A SCRAM-specific secret store. If not specified, the
  field uses the secret store defined in `swapConfig.secretStore`.
* [6] Required when `alterScramCredentials: true`. The administrator
  `username` and `password` that Confluent Gateway uses to perform SCRAM
  credential operations through the Kafka Admin API. Ensure the
  administrator user has the required permissions to alter and
  describe SCRAM credentials.

**Configuration Scenario 1: Using the same secret store as authentication swapping**

In this configuration, you store SCRAM credentials in the route’s secret store.

```yaml
gateway:
  routes:
    - name: gateway-route
      security:
        auth: swap
        swapConfig:
          secretStore: vault-store
          clientAuth:
            sasl:
              mechanism: SCRAM
```

**Configuration Scenario 2: Using a SCRAM-specific secret store**

In this configuration, you store SCRAM credentials in a separate
secret store from other authentication swap credentials.

```yaml
gateway:
  routes:
    - name: gateway-route
      security:
        auth: swap
        swapConfig:
          secretStore: vault-store
          clientAuth:
            sasl:
              mechanism: SCRAM
              scram:
                secretStore: scram-secret-store
```

**Configuration Scenario 3: Managing SCRAM credentials from Gateway**

In this configuration, you enable Confluent Gateway to automatically create
and update SCRAM user credentials through the Kafka Admin API. Complete
the following:

- Provide `admin.username` and `admin.password`.
- Grant the administrator user the necessary permissions to perform
  `AlterUserScramCredentials` and `DescribeUserScramCredentials`
  operations on the Kafka cluster.
- Add a swap-credential entry for the administrator user in the secret
  store, mapping `admin.username` to a broker-valid identity. The
  route’s swap configuration also applies to this administrator
  connection, so a missing entry causes provisioning to fail with a
  secret-lookup error referencing the administrator username.

```yaml
gateway:
  routes:
    - name: gateway-route
      security:
        auth: swap
        swapConfig:
          secretStore: vault-store
          clientAuth:
            sasl:
              mechanism: SCRAM
              scram:
                alterScramCredentials: true
                admin:
                  username: admin-user
                  password: admin-password
```

#### NOTE
When using `alterScramCredentials: true`, ensure that Confluent Gateway
has the necessary permissions to create, update, and delete
secrets.
For required permissions, see the [Secret store configuration](#gateway-secret-stores-docker).

<a id="gateway-scram-json-format-docker"></a>

**Expected JSON format for a SCRAM secret**

When you provision SCRAM credentials manually (`alterScramCredentials:
false`), store each credential in the secret store under the name
`SCRAM_<username>`, with the following JSON structure. If the secret
store has a `prefixPath` configured, Confluent Gateway looks up the secret under
`<prefixPath>SCRAM_<username>`, the same way `prefixPath` applies to
other credential lookups on this page.

```json
{
    "sha256": {
        "salt": "<base64-encoded-salt>",
        "storedKey": "<base64-encoded-storedKey>",
        "serverKey": "<base64-encoded-serverKey>",
        "iterations": 4096
    },
    "sha512": {
        "salt": "<base64-encoded-salt>",
        "storedKey": "<base64-encoded-storedKey>",
        "serverKey": "<base64-encoded-serverKey>",
        "iterations": 4096
    }
}
```

* At least one `sha256` or `sha512` must be present. Include the block
  or blocks that correspond to the SCRAM mechanisms your clients use.
* If a block is present, it must include all four fields: `salt`,
  `storedKey`, `serverKey`, and `iterations`.
* `salt`, `storedKey`, and `serverKey` must be standard Base64-encoded
  strings of the raw binary output from the SCRAM key-derivation steps
  defined in [Request for Comments (RFC) 5802](https://www.rfc-editor.org/rfc/rfc5802), the same algorithm Kafka uses
  internally. The derivation uses two intermediate values, `SaltedPassword`
  and `ClientKey`, that aren’t stored in the JSON secret themselves:
  1. `salt`: Random bytes. 16 bytes is typical. Not derived from the
     password.
  2. `SaltedPassword`: `PBKDF2WithHmacSHA256` for the `sha256` block,
     or `PBKDF2WithHmacSHA512` for the `sha512` block, applied to the
     password, salt, and iteration count.
  3. `ClientKey`: `HMAC(SaltedPassword, "Client Key")`.
  4. `storedKey`: Hash of `ClientKey`, using SHA-256 or SHA-512 to match
     the block.
  5. `serverKey`: `HMAC(SaltedPassword, "Server Key")`.

  Base64-encode the raw `salt`, `storedKey`, and `serverKey` bytes
  computed in the preceding steps for the corresponding JSON values.
* `iterations` must be between `4096` and `16384`.

**SCRAM configuration limitations**

The following limitations apply when configuring SCRAM authentication:

* No standalone tool exists for generating SCRAM credential material. The
  `salt`, `storedKey`, and `serverKey` values are cryptographic hashes
  derived from the password, so you can’t create them by hand. If you don’t
  enable `alterScramCredentials: true`, follow the RFC 5802 key
  derivation steps described previously, or use an existing library that
  implements them, to compute and provision the JSON secret yourself, as
  described in [Expected JSON format for a SCRAM secret](#gateway-scram-json-format-docker).
* SCRAM secrets must always be stored as JSON, regardless of the
  `useJson` setting on the secret store.
* The `clusterAuth` block, used for Confluent Gateway-to-Kafka cluster
  authentication, doesn’t support SCRAM. See
  [Cluster authentication for authentication swapping](#gateway-authn-swap-cluster-docker).
* Azure Key Vault doesn’t support SCRAM credential storage. See
  [Secret store configuration](#gateway-secret-stores-docker).

**SASL/OAUTHBEARER authentication (OAuth-to-OAuth support)**

Confluent Gateway supports SASL/OAUTHBEARER authentication for client-to-Confluent Gateway
connections, including OAuth-to-OAuth support, where the client authenticates
to Confluent Gateway with an OAuth token and Confluent Gateway separately authenticates to
the backing Kafka cluster with its own OAuth token. The client presents an
OAuth bearer token, and Confluent Gateway validates its signature against your
identity provider’s JSON Web Key Set (JWKS) endpoint.

After validation, Confluent Gateway reads the client principal from a claim in the
token and uses it as the lookup key for the swapped credentials in the
secret store.

```yaml
gateway:
  routes:
    - name:
      security:
        auth: swap
        swapConfig:
          clientAuth:
            sasl:
              mechanism: OAUTHBEARER             --- [1]
              callbackHandlerClass: "org.apache.kafka.common.security.oauthbearer.OAuthBearerValidatorCallbackHandler"  --- [2]
              jaasConfig:
                file:                            --- [3]
              oauth:
                jwksEndpointUrl:                 --- [4]
                jwksEndpointRefreshMs:           --- [5]
                jwksEndpointRetryBackoffMs:      --- [6]
                jwksEndpointRetryBackoffMaxMs:   --- [7]
                expectedAudience:                --- [8]
                expectedIssuer:                  --- [9]
                subClaimName:                    --- [10]
                scopeClaimName:                  --- [11]
            connectionsMaxReAuthMs:              --- [12]
```

* [1] The SASL mechanism to use. Set to `OAUTHBEARER` for SASL/OAUTHBEARER
  authentication.
* [2] The callback handler class to use. Set to
  `org.apache.kafka.common.security.oauthbearer.OAuthBearerValidatorCallbackHandler`,
  as Confluent Gateway validates client tokens as a SASL server.
* [3] The path to the JAAS configuration file that Confluent Gateway loads to set up
  token validation. Because Confluent Gateway only validates the inbound token, the
  file doesn’t need to define login options:
  ```properties
  org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required;
  ```
* [4] Required. The JWKS endpoint URL that Confluent Gateway uses to validate the
  signature of the inbound token. For example:
  ```yaml
  jwksEndpointUrl: "https://idp.mycompany.io:8080/realms/clients/protocol/openid-connect/certs"
  ```
* [5] Optional. The interval, in milliseconds, at which Confluent Gateway refreshes
  its JWKS cache. The default is `3600000` (1 hour).
* [6] Optional. The delay, in milliseconds, that Confluent Gateway waits before the
  first retry after a failed JWKS retrieval. Each subsequent retry increases
  this delay exponentially, up to the maximum set by
  `jwksEndpointRetryBackoffMaxMs`. The default is `100`.
* [7] Optional. The maximum delay, in milliseconds, between JWKS retrieval
  retries. This sets the upper limit for the exponential increase set by
  `jwksEndpointRetryBackoffMs`. The default is `10000`.
* [8] Optional. The expected audience (the `aud` claim) in the token. Your
  identity provider sets this claim to identify who it issued the token for.
  Provide a comma-separated list to accept multiple audiences. Confluent Gateway
  rejects tokens whose `aud` claim doesn’t match one of the listed values.
* [9] Optional. The expected issuer (the `iss` claim) in the token. Your
  identity provider sets this claim to identify itself as the token’s
  issuer. Confluent Gateway rejects tokens whose `iss` claim doesn’t match this
  value.
* [10] Optional. The token claim that Confluent Gateway reads to determine the
  client’s identity (the principal). Confluent Gateway uses this value as the key to
  look up the client’s swapped credentials in the secret store. Most
  identity providers populate the standard OAuth/OpenID Connect (OIDC)
  `sub` (subject) claim with a unique client identifier, so the default is
  `sub`. Override this only if your identity provider uses a different
  claim to identify the client.
* [11] Optional. The token claim that Confluent Gateway reads to determine the
  client’s granted scope (the level of access the identity provider
  authorized for this token). Most identity providers populate the standard
  OAuth `scope` claim, so the default is `scope`. Override this only if
  your identity provider uses a different claim name.
* [12] Optional. The maximum re-authentication time in milliseconds.

**mTLS authentication**

```yaml
gateway:
  routes:
    - name:
      security:
        auth: swap
        swapConfig:
          clientAuth:
            ssl:
              principalMappingRules: --- [1]
```

* [1] Required only for authentication swapping with mTLS authentication. The
  pattern to read principal name from the certificates. For example:
  `"OU=.*$/$1/,RULE:^UID=([a-zA-Z0-9._-]+),.*$/$1/,DEFAULT`

**NONE authentication**

```yaml
gateway:
  routes:
    - name:
      security:
        auth: swap
        swapConfig:
          clientAuth:
            none: {}
```

When using the `none` authentication method, the Confluent Gateway identifies
all incoming clients as anonymous and assigns the client ID
`ANONYMOUS`. Therefore, ensure to configure the swapped credentials
for the `ANONYMOUS` user in the associated secret store.

<a id="gateway-authn-swap-cluster-docker"></a>

#### **Cluster authentication for authentication swapping**

Configure how Confluent Gateway authenticates to the Kafka cluster for
authentication swapping.

**SASL authentication**

```yaml
gateway:
  routes:
    - name:
      security:
        auth: swap
        swapConfig:
          clusterAuth:
            sasl:
              mechanism:               --- [1]
              callbackHandlerClass:    --- [2]
              jaasConfig:
                file:                  --- [3]
              oauth:
                tokenEndpointUri:      --- [4]
```

* [1] The SASL mechanism to use. Set to `PLAIN` for SASL/PLAIN authentication
  or `OAUTHBEARER` for SASL/OAUTHBEARER authentication. Confluent Gateway doesn’t
  support `SCRAM` for cluster authentication.
* [2] The callback handler class to use. Set to
  `org.apache.kafka.common.security.authenticator.SaslClientCallbackHandler`
  for SASL/PLAIN authentication, or
  `org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginCallbackHandler`
  for SASL/OAUTHBEARER authentication. Confluent Gateway acts as a client when
  authenticating to brokers, so use the client-side callback handler.
* [3] The path to the JAAS configuration file.
* [4] The URI for the OAuth token endpoint.

**JAAS configuration file content for SASL/PLAIN authentication**

```properties
org.apache.kafka.common.security.plain.PlainLoginModule required username="%s" password="%s";
```

**JAAS configuration file content for SASL/OAUTHBEARER authentication**

```properties
org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required clientId="%s" clientSecret="%s";
```

**NONE authentication**

The `none` authentication method disables authentication between the
Confluent Gateway and the cluster. In this mode, the Confluent Gateway ignores the
client ID and bypasses cluster authentication.

Because the Confluent Gateway doesn’t require a secret lookup, skip the secret
store configuration. Including a secret store in this configuration
triggers a validation error.

```yaml
gateway:
  routes:
    - name:
      security:
        auth: swap
        swapConfig:
          clusterAuth:
            none: {}
```

#### Authentication swapping examples

*SASL/PLAIN to SASL/OAUTHBEARER example:*

```yaml
gateway:
  routes:
    - name: gateway
      security:
        auth: swap
        ssl:
          ignoreTrust: false
          truststore:
            type: PKCS12
            location: /opt/ssl/client-truststore.p12
            password:
              file: /opt/secrets/client-truststore.password
          keystore:
            type: PKCS12
            location: /opt/ssl/gw-keystore.p12
            password:
              file: /opt/secrets/gw-keystore.password
              keyPassword:
                value: inline-password
          clientAuth: required

        swapConfig:
          clientAuth:
            sasl:
              mechanism: PLAIN
              callbackHandlerClass: "org.apache.kafka.common.security.plain.internals.PlainServerCallbackHandler" # required for PLAIN
              jaasConfig: # required for PLAIN
                  file: /opt/gateway/gw-users.conf
            connectionsMaxReAuthMs: 0 # optional. link: https://docs.confluent.io/platform/current/installation/configuration/broker-configs.html#connections-max-reauth-ms
          secretStore: s1
          clusterAuth:
            sasl:
              mechanism: OAUTHBEARER
              callbackHandlerClass: "org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginCallbackHandler"
              jaasConfig:
                file: /opt/gateway/cluster-login.tmpl.conf
              oauth: # required only if clusterAuth.sasl.mechanism=oauth
                tokenEndpointUri: "https://idp.mycompany.io:8080/realms/cp/protocol/openid-connect/token"
```

*mTLS to SASL/OAUTHBEARER example:*

```yaml
gateway:
  routes:
    - name: gateway
      security:
        auth: swap
        ssl:
          ignoreTrust: false
          truststore:
            type: PKCS12
            location: /opt/ssl/client-truststore.p12
            password:
              file: /opt/secrets/client-truststore.password
          keystore:
            type: PKCS12
            location: /opt/ssl/gw-keystore.p12
            password:
              file: /opt/secrets/gw-keystore.password
              keyPassword:
                value: inline-password
          clientAuth: required
        swapConfig:
          clientAuth:
            ssl:
              principalMappingRules: "RULE:^CN=([a-zA-Z0-9._-]+),OU=.*$/$1/,RULE:^UID=([a-zA-Z0-9._-]+),.*$/$1/,DEFAULT"
          secretStore: "oauth-secrets"
          clusterAuth:
            sasl:
              mechanism: OAUTHBEARER
              callbackHandlerClass: "org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginCallbackHandler"
              jaasConfig:
                file: "/etc/gateway/cluster-jaas.tmpl.conf"
              oauth:
                tokenEndpointUri: "https://idp.mycompany.io:8080/realms/cp/protocol/openid-connect/token"
```

*SASL/OAUTHBEARER to SASL/OAUTHBEARER (OAuth-to-OAuth) example:*

In this configuration, the client presents an OAuth token to Confluent Gateway.
Confluent Gateway validates the token against the client identity provider’s JWKS
endpoint, then obtains a separate token from the cluster identity provider to
authenticate to the Kafka cluster.

```yaml
gateway:
  routes:
    - name: gateway
      security:
        auth: swap
        swapConfig:
          clientAuth:
            sasl:
              mechanism: OAUTHBEARER
              callbackHandlerClass: "org.apache.kafka.common.security.oauthbearer.OAuthBearerValidatorCallbackHandler"
              jaasConfig:
                file: "/opt/gateway/client-oauth-jaas.conf"
              oauth:
                jwksEndpointUrl: "https://idp.mycompany.io:8080/realms/clients/protocol/openid-connect/certs"
                expectedAudience: "kafka-clients"
                expectedIssuer: "https://idp.mycompany.io:8080/realms/clients"
                subClaimName: "sub"
          secretStore: "oauth-secrets"
          clusterAuth:
            sasl:
              mechanism: OAUTHBEARER
              callbackHandlerClass: "org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginCallbackHandler"
              jaasConfig:
                file: "/opt/gateway/cluster-oauth-jaas.conf"
              oauth:
                tokenEndpointUri: "https://idp.mycompany.io:8080/realms/cp/protocol/openid-connect/token"
```

#### NOTE
Confluent Gateway requires the endpoint for each OAuth leg to be allowlisted.
In this example, both the client and cluster legs use OAuth, so set
`GATEWAY_OPTS` to a comma-separated list that includes both the
client JWKS endpoint and the cluster token endpoint:

```yaml
gateway:
  environment:
    GATEWAY_OPTS: "-Dorg.apache.kafka.sasl.oauthbearer.allowed.urls=https://idp.mycompany.io:8080/realms/clients/protocol/openid-connect/certs,https://idp.mycompany.io:8080/realms/cp/protocol/openid-connect/token"
```

Otherwise, Confluent Gateway rejects requests to either OAuth endpoint with an
`is not allowed` error. For more information, see
[OAuth token or JWKS endpoint not allowed](docker-troubleshoot.md#gateway-oauth-endpoint-not-allowed).

<a id="gateway-ssl-docker"></a>

## SSL configuration

The following SSL configuration is supported for streaming domain
configuration (`streamingDomains.kafkaCluster.bootstrapServers.ssl`)
and route configuration (`routes.security.ssl`) using Docker
Compose.

```yaml
ssl:
  ignoreTrust:            --- [1]
  truststore:             --- [2]
    type:                 --- [3]
    location:             --- [4]
    password:             --- [5]
  keystore:               --- [6]
    type:                 --- [7]
    location:             --- [8]
    password:             --- [9]
    keyPassword:          --- [10]
      value:
      file:
```

* [1] Skip certificate validation (not recommended for production).
  Essentially, setting this to `true` trusts all certificates.
* [2] Truststore configuration.
* [3] Truststore certificate type. The supported values are `JKS`, `PKCS12`,
  and `PEM`.
* [4] The path to the truststore file.
* [5] The password for the truststore file. For more information, see
  [Password configuration](#gateway-password-docker).
* [6] Keystore configuration (gateway identity).
* [7] The keystore certificate type. The supported values are `JKS`,
  `PKCS12`, and `PEM`.
* [8] The path to the keystore file.
* [9] The password for the keystore file. For more information, see
  [Password configuration](#gateway-password-docker).
* [10] The password for the private key inside the keystore. Can be
  defined either inline or file-based.

An example SSL configuration for Confluent Gateway using Docker Compose:

```yaml
ssl:
  ignoreTrust: false
  truststore:
    type: PKCS12 # optional, default=JKS
    location: /opt/ssl/client-truststore.p12
    password:
      file: /opt/secrets/client-truststore.password # or inline password
  keystore:
    type: PKCS12 # optional, default=JKS
    location: /opt/ssl/gw-keystore.p12
    password:
      file: /opt/secrets/gw-keystore.password # or inline password
    keyPassword:
      value: inline-password
```

<a id="gateway-password-docker"></a>

## Password configuration

Confluent Gateway supports the file-based and inline password configurations. Only one
of the two should be provided.

```yaml
password:
  file:                   --- [1]
  value:                  --- [2]
```

* [1] The path to the password file.
* [2] The inline password value.

<a id="gateway-secret-stores-docker"></a>

## Secret store configuration

Confluent Gateway uses secret stores, such as AWS Secrets Manager, Azure Key
Vault, HashiCorp Vault, CyberArk Conjur, or a file, to securely manage
authentication credentials and sensitive information. This setup is
critical for several key operations:

- Storing Confluent Gateway to Kafka broker credentials.
- Supporting authentication swapping scenarios.

  In cases where Confluent Gateway translates or swaps authentication, for
  example from mTLS clients to OAuthbearer brokers or vice versa,
  secret stores are needed to store and fetch the credentials used in
  the swap. This allows each client connection to use its mapped
  broker credential, enhancing security and enabling fine-grained
  access control.

Interaction with these secret stores should always occur over TLS for
confidentiality and integrity.

As a security best practice, configure Confluent Gateway to assume an IAM role
with the least privilege principle. Do not use static IAM user
credentials to avoid sensitive credential exposure.

Ensure proper role trust policies are in place and limit permissions to
only what the Confluent Gateway needs. For example in AWS:

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetSecretValue"
            ],
            "Resource": [
                "arn:aws:secretsmanager:us-east-1:123456789012:secret:gateway/*",
                "arn:aws:secretsmanager:us-east-1:123456789012:secret:confluent/*"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:RequestTag/Environment": "production"
                }
            }
        }
    ]
}
```

When using SCRAM authentication with automatic credential management
(`alterScramCredentials: true`), Confluent Gateway requires additional
permissions to create, update, and delete SCRAM user credentials in
the secret store:

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetSecretValue",
                "secretsmanager:CreateSecret",
                "secretsmanager:PutSecretValue",
                "secretsmanager:DeleteSecret"
            ],
            "Resource": [
                "arn:aws:secretsmanager:us-east-1:123456789012:secret:gateway/*",
                "arn:aws:secretsmanager:us-east-1:123456789012:secret:confluent/*"
            ]
        }
    ]
}
```

### HashiCorp Vault

To use HashiCorp Vault as a secret store, provide the following configurations.

**Connect using an authentication token**

```yaml
gateway:
  secretStores:
    - name:               --- [1]
      provider:
        type:             --- [2]
        config:
          address:        --- [3]
          authMethod:     --- [4]
          authToken:      --- [5]
          prefixPath:     --- [6]
          separator:      --- [7]
```

* [1] A unique name for the secret store.
* [2] The type of the secret store. Set to `Vault` to use HashiCorp Vault.
* [3] The address of the Vault server.
* [4] The authentication method to use. You can set to `Token` as the
  default value or leave it empty.
* [5] The authentication token for the Vault server to connect using
  the `authToken` method.
* [6] Required. The path prefix under which Confluent Gateway looks up secrets in Vault.
* [7] Optional. The separator for the secret store. The default value is `:`.

**Connect using AppRole**

```yaml
gateway:
  secretStores:
    - name:               --- [1]
      provider:
        type:             --- [2]
        config:
          address:        --- [3]
          authMethod:     --- [4]
          role:           --- [5]
          secret:         --- [6]
          prefixPath:     --- [7]
          separator:      --- [8]
```

* [1] A unique name for the secret store.
* [2] The type of the secret store. Set to `Vault` to use HashiCorp Vault.
* [3] The address of the Vault server.
* [4] The authentication method to use. Set to `AppRole`.
* [5] The role to use to connect to the Vault server.
* [6] The secret to use to connect to the Vault server.
* [7] Required. The path prefix under which Confluent Gateway looks up secrets in Vault.
* [8] Optional. The separator for the secret store. The default value is `:`.

**Connect using Username and Password**

```yaml
gateway:
  secretStores:
    - name:               --- [1]
      provider:
        type:             --- [2]
        config:
          address:        --- [3]
          authMethod:     --- [4]
          username:       --- [5]
          password:       --- [6]
          prefixPath:     --- [7]
          separator:      --- [8]
```

* [1] A unique name for the secret store.
* [2] The type of the secret store. Set to `Vault` to use HashiCorp Vault.
* [3] The address of the Vault server.
* [4] The authentication method to use. Set to `UserPass`.
* [5] The username to use to connect to the Vault server.
* [6] The password to use to connect to the Vault server.
* [7] Required. The path prefix under which Confluent Gateway looks up secrets in Vault.
* [8] Optional. The separator for the secret store. The default value is `:`.

Note that connecting to HashiCorp Vault using a certificate is not supported.

For authentication swapping with SASL/PLAIN, store the swapped credential
in Vault under a field named `value`, containing the username and
password joined by the configured `separator`, regardless of which
connection method you use:

```text
value: "swapped-user:swapped-password"
```

#### NOTE
The Vault secret store requires a KV version 2 secrets engine. If
you use a KV version 1 engine, credential lookups fail with a
`Could not find secret for request` error.

**Additional Vault capabilities for SCRAM credential management**

When using SCRAM authentication with automatic credential management
(`alterScramCredentials: true`), Confluent Gateway requires additional Vault
capabilities to create, update, and delete SCRAM user credentials.

HashiCorp Vault uses policies to grant capabilities. Ensure the
Confluent Gateway has the following capabilities on the secret paths:

```hcl
path "secret/data/gateway/*" {
  capabilities = ["create", "read", "update", "delete"]
}
```

For more information on Vault policies, see [Policies | Vault |
HashiCorp Developer](https://developer.hashicorp.com/vault/docs/concepts/policies).

### AWS Secrets Manager

To use AWS Secrets Manager as a secret store, provide the following
configurations. You can connect to the Secrets Manager using IAM Role
or using Access Key and Secret Key.

If the environment (EC2 for instance) has an IAM Role attached with sufficient
permissions, you do not need to specify accessKey or secretKey. The provider
automatically assumes the attached IAM role using the default AWS
credential provider chain.

```yaml
gateway:
  secretStores:
    - name:                  --- [1]
      provider:
        type:                --- [2]
        config:
          region:            --- [3]
          accessKey:         --- [4]
          secretKey:         --- [5]
          endpointOverride:  --- [6]
          prefixPath:        --- [7]
          separator:         --- [8]
          useJson:           --- [9]
```

* [1] A unique name for the secret store.
* [2] The type of the secret store. Set to `AWS`.
* [3] The region of the AWS Secrets Manager.
* [4] AWS IAM Access Key ID. Only required when authenticating with IAM user
  credentials.
* [5] AWS IAM Secret Key corresponding to the `accessKey`.
  Only required when authenticating with IAM user credentials.
* [6] Optional. A custom endpoint URL to use instead of the default AWS
  endpoint. Defaults to the AWS region endpoint.
* [7] Optional. A string prefix added to all secret paths. Useful
  for environment separation (example: staging, production). Defaults
  to an empty string.
* [8] Optional. The character/string used to split authentication data within
  the retrieved secret. Defaults to `:`.
* [9] If set to `true`, the provider attempts to parse the secret value as
  a JSON object. If `false` (the default value), the raw string value is
  returned.

An example IAM role configuration for AWS Secrets Manager:

```yaml
gateway:
  secretStores:
    - name: aws-secrets
      provider:
        type: AWS
        config:
          region: us-west-2
          endpointOverride: https://secretsmanager.us-west-2.amazonaws.com
          prefixPath: secret/
          separator: ":"
          useJson: true
```

**Additional AWS capabilities for SCRAM credential management**

When using SCRAM authentication with automatic credential management
(`alterScramCredentials: true`), Confluent Gateway requires additional AWS
Secrets Manager permissions to create, update, and delete SCRAM user
credentials.

Ensure the IAM role or policy attached to Confluent Gateway includes the
following permissions:

```json
{
    "Version": "XX-XX-XXXX",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "secretsmanager:CreateSecret",
                "secretsmanager:PutSecretValue",
                "secretsmanager:DeleteSecret"
            ],
            "Resource": [
                "arn:aws:secretsmanager:us-east-1:123456789012:secret:gateway/*",
                "arn:aws:secretsmanager:us-east-1:123456789012:secret:confluent/*"
            ]
        }
    ]
}
```

### Azure Key Vault

To use Azure Key Vault as a secret store, provide the following configurations.

**Connect using Client ID and Secret**

```yaml
gateway:
  secretStores:
    - name:                  --- [1]
      provider:
        type:                --- [2]
        config:
          vaultUrl:          --- [3]
          credentialType:    --- [4]
          tenantId:          --- [5]
          clientId:          --- [6]
          clientSecret:      --- [7]
          prefixPath:        --- [8]
          separator:         --- [9]
          useJson:           --- [10]
```

* [1] A unique name for the secret store.
* [2] The type of the secret store. Set to `Azure`.
* [3] The URL of the Azure Key Vault to connect to.
* [4] The credential type to use. Set to `ClientSecret`.
* [5] The tenant ID of the Azure Key Vault.
* [6] The client ID of the Azure Key Vault.
* [7] The client secret of the Azure Key Vault for the authentication.
* [8] Optional. The prefix path to the secret store. Defaults to an
  empty string.
* [9] Optional. The character or string used to split authentication data within
  the retrieved secret. Defaults to `:`.
* [10] Optional. Set to `true` to have the provider attempt to parse the
  secret value as a JSON object. The default value is `false`, which
  returns the raw string value.

An example configuration for Azure Key Vault using Client ID and Secret:

```yaml
gateway:
  secretStores:
    - name: azure-keyvault
      provider:
        type: Azure
        config:
          vaultUrl: https://authswap.vault.azure.net/
          credentialType: ClientSecret
          tenantId: xxxx-xxxx-xxxx-xxxx-xxxxxxxx
          clientId: xxxx-xxxx-xxxx-xxxx-xxxxxxxx
          clientSecret: client-secret
          prefixPath: ""
          separator: ":"
          useJson: true
```

**Connect using Username and Password**

```yaml
gateway:
  secretStores:
    - name:                  --- [1]
      provider:
        type:                --- [2]
        config:
          vaultUrl:          --- [3]
          credentialType:    --- [4]
          tenantId:          --- [5]
          clientId:          --- [6]
          username:          --- [7]
          password:          --- [8]
          prefixPath:        --- [9]
          separator:         --- [10]
          useJson:           --- [11]
```

* [1] A unique name for the secret store.
* [2] The type of the secret store. Set to `Azure`.
* [3] The URL of the Azure Key Vault to connect to.
* [4] The credential type to use. Set to `UsernamePassword`.
* [5] The tenant ID of the Azure Key Vault.
* [6] The client ID of the Azure Key Vault.
* [7] The username to authenticate with.
* [8] The password to authenticate with.
* [9] Optional. The prefix path to the secret store. Defaults to an empty
  string.
* [10] Optional. The character or string used to split authentication data
  within the retrieved secret. Defaults to `:`.
* [11] Optional. Set to `true` to have the provider attempt to parse the
  secret value as a JSON object. Defaults to `false`, which returns the
  raw string value.

An example configuration for Azure Key Vault using Username and Password:

```yaml
gateway:
  secretStores:
    - name: azure-keyvault
      provider:
        type: Azure
        config:
          vaultUrl: https://authswap.vault.azure.net/
          credentialType: UsernamePassword
          tenantId: xxxx-xxxx-xxxx-xxxx-xxxxxxxx
          clientId: xxxx-xxxx-xxxx-xxxx-xxxxxxxx
          username: username
          password: password
          prefixPath: ""
          separator: ":"
          useJson: true
```

**Connect using Client Certificate**

You can connect to Azure Key Vault using the Privacy-Enhanced Mail (PEM)
or Personal Information Exchange (PFX) format certificates.

```yaml
gateway:
  secretStores:
    - name:                       --- [1]
      provider:
        type:                     --- [2]
        config:
          vaultUrl:               --- [3]
          credentialType:         --- [4]
          tenantId:               --- [5]
          clientId:               --- [6]
          certificateType:        --- [7]
          certificatePath:        --- [8]
          certificatePfxPassword: --- [9]
          certificateSendChain:   --- [10]
          prefixPath:             --- [11]
          separator:              --- [12]
          useJson:                --- [13]
```

* [1] A unique name for the secret store.
* [2] The type of the secret store. Set to `Azure`.
* [3] The URL of the Azure Key Vault to connect to.
* [4] The credential type to use. Set to `ClientCertificate`.
* [5] The tenant ID of the Azure Key Vault.
* [6] The client ID of the Azure Key Vault.
* [7] The type of encoding used on the file specified in `certificatePath`.
  Set to `PEM` for PEM certificates or `PFX` for PFX certificates.
* [8] The path to the client certificate file.
* [9] Required for the PFX certificates. The password protecting the PFX file.
* [10] Optional. The flag to indicate if certificate chain should be sent as
  part of authentication request. Defaults to `false`.
* [11] Optional. The prefix path to the secret store. Defaults to an empty
  string.
* [12] Optional. The character or string used to split authentication data
  within the retrieved secret. Defaults to `:`.
* [13] Optional. Set to `true` to have the provider attempt to parse the
  secret value as a JSON object. Defaults to `false`, which returns the
  raw string value.

An example configuration for Azure Key Vault using *PEM* certificate:

```yaml
gateway:
  secretStores:
    - name: azure-keyvault
      provider:
        type: Azure
        config:
          vaultUrl: https://authswap.vault.azure.net/
          credentialType: ClientCertificate
          tenantId: xxxx-xxxx-xxxx-xxxx-xxxxxxxx
          clientId: xxxx-xxxx-xxxx-xxxx-xxxxxxxx
          certificatePath: /opt/ssl/client-cert.pem
          prefixPath: ""
          separator: ":"
          useJson: true
```

An example configuration for Azure Key Vault using *PFX* certificate:

```yaml
gateway:
  secretStores:
    - name: azure-keyvault
      provider:
        type: Azure
        config:
          vaultUrl: https://authswap.vault.azure.net/
          credentialType: ClientCertificate
          tenantId: xxxx-xxxx-xxxx-xxxx-xxxxxxxx
          clientId: xxxx-xxxx-xxxx-xxxx-xxxxxxxx
          certificateType: PFX
          certificatePath: /opt/ssl/client-cert.pfx
          certificatePfxPassword: <pfx-password>
          prefixPath: ""
          separator: ":"
          useJson: true
```

#### NOTE
Azure Key Vault is currently not supported for SCRAM authentication.

<a id="cyberark-conjur"></a>

### CyberArk Conjur

To use CyberArk Conjur as a secret store, provide the following configurations.

**Connect using API Key**

```yaml
gateway:
  secretStores:
    - name:                  --- [1]
      provider:
        type:                --- [2]
        config:
          url:               --- [3]
          account:           --- [4]
          username:          --- [5]
          apiKey:            --- [6]
          prefixPath:        --- [7]
          sslVerifyEnabled:  --- [8]
          separator:         --- [9]
```

* [1] A unique name for the secret store.
* [2] The type of the secret store. Set to `CyberArk` to use CyberArk Conjur.
* [3] The URL of the CyberArk Conjur server.
* [4] The CyberArk Conjur account name.
* [5] The username (login) used to authenticate with CyberArk Conjur.
* [6] The API key used to authenticate with CyberArk Conjur.
* [7] Required. The path prefix prepended to all secret lookups. For example,
  if set to `secrets/` and the client username is `user1`, the Confluent Gateway
  looks up the secret at `secrets/user1`.
* [8] Optional. Whether to verify the SSL certificate of the Conjur server.
  Set to `false` only in development or test environments.
* [9] Optional. The character used to split the retrieved secret into username
  and password. Defaults to `:`.

An example configuration for CyberArk Conjur:

```yaml
gateway:
  secretStores:
    - name: conjur-store
      provider:
        type: CyberArk
        config:
          url: "https://conjur.example.com"
          account: "myaccount"
          username: "gateway-user"
          apiKey: "your-conjur-api-key"
          prefixPath: "secrets/"
          sslVerifyEnabled: true
          separator: ":"
```

**Additional Conjur capabilities for SCRAM credential management**

When using SCRAM authentication with automatic credential management
(`alterScramCredentials: true`), Confluent Gateway requires additional CyberArk
Conjur permissions to create, update, and delete SCRAM user credentials in
the secret store.

Ensure the Conjur identity used by the Confluent Gateway has `create` and `update`
privileges on the secret variables, beyond the standard `read` and
`execute` privileges:

```text
- !host
  id: gateway-user
- !permit
  role: !host gateway-user
  privileges: [ read, execute, create, update ]
  resource: !variable secrets/user1
- !permit
  role: !host gateway-user
  privileges: [ read, execute, create, update ]
  resource: !variable secrets/user2
```

<a id="gateway-file-secret-store"></a>

### File

To use a local directory as a secret store, provide the following
configurations.

```yaml
gateway:
  secretStores:
    - name:            --- [1]
      provider:
        type:          --- [2]
        config:
          path:        --- [3]
          separator:   --- [4]
```

* [1] A unique name for the secret store.
* [2] The type of the secret store. Set to `File`.
* [3] Optional. The directory containing secret files,
  with one file per client username. Defaults to `/opt/secrets`.
* [4] Optional. The character used to separate the mapped username
  and password within each secret file. Defaults to `:`.

Under the configured `path`, create individual secret files named after each
client username. Each file must contain the swapped username and password
joined by `separator`.

For example, for a client username of `user1` using the default separator
(`:`), create a file at `/opt/secrets/user1` containing:

```text
swapped_user1:swapped_user1_password
```

An example configuration for a file-based secret store:

```yaml
gateway:
  secretStores:
    - name: file-store
      provider:
        type: File
        config:
          path: /opt/secrets
          separator: ":"
```
