An OpenID Connect implementation of Apache Pulsar's AuthenticationProvider
and AuthenticationState
interfaces.
OpenID Connect is a protocol for identity and authorization.
This broker side plugin supports the retrieval of Public Keys from an identity provider, like KeyCloak, to support
dynamic validation of JWTs for multiple, configured allowed-listed issuers. It also provides for the ability to first
attempt to use the local AuthenticationProviderToken
verifier before retrieving a remote JWK for token validation.
This plugin requires Java 11 runtime and will work with all current versions of Pulsar (2.7, 2.8, 2.9, 2.10). It is packaged by default in the Luna Streaming Distributions found here: https://github.com/datastax/pulsar/releases.
To integrate your client with a broker using this authentication plugin, use Pulsar's built in OAuth2.0 client integration.
The following configuration options are available for this plugin:
Name | Default Value | Format | Description |
---|---|---|---|
openIDAllowedTokenIssuers | Empty Set | Comma delimited set of URIs | The allowed issuers to trust from the JWT. The iss claim must be contained in this set. See Issuers. |
openIDAllowedAudience | null |
String | If not set, defaults to null , and the aud claim is not checked. If set, the JWT must have the configured aud in its claims. If it is missing, the token will be rejected. |
openIDRoleClaim | sub |
String | The JWT claim used to get the authenticated token's role. Defaults to the sub claim, but can be any claim. |
openIDAcceptedTimeLeewaySeconds | 0 |
Number (no decimals) | The number of seconds that a token will be accepted past its expiration time. |
openIDJwkCacheSize | 10 |
Number (no decimals) | The number of JWK values to keep in the cache. |
openIDJwkExpiresSeconds | 300 |
Number (no decimals) | The length of time, in seconds, to store a JWK before calling the issuer again. Note that this time is also the maximum time that a revoked token can be used. A longer window may improve performance, but it also increases the length of time than a deactivated token could be used. |
openIDJwkConnectionTimeoutMillis | 10000 |
Number (no decimals) | The length of time, in milliseconds, to wait while opening a connection to the JWKS url for an OpenID provider. |
openIDJwkReadTimeoutMillis | 10000 |
Number (no decimals) | The length of time, in milliseconds, to wait for data to be available to read while connected to the OpenID provider. |
openIDMetadataCacheSize | 10 |
Number (no decimals) | The number of OpenID metadata objects to store in the cache. |
openIDMetadataExpiresSeconds | 86400 |
Number (no decimals) | The length of time, in seconds, to store the result of the /.well-known/openid-configuration result from an issuer. This result is used to retrieve the issuer's jwks_uri , which is then used to retrieve the current public keys for the issuer. |
openIDMetadataConnectionTimeoutMillis | 10000 |
Number (no decimals) | The length of time, in milliseconds, to wait while opening a connection to the issuer's /.well-known/openid-configuration endpoint. |
openIDMetadataReadTimeoutMillis | 10000 |
Number (no decimals) | The length of time, in milliseconds, to wait for data to be available to read while connected to the issuer's /.well-known/openid-configuration endpoint. |
openIDRequireHttps | true |
Boolean | Whether to fail initialization if the openIDAllowedTokenIssuers configuration contains schemes other than https . This is provided as a convenience for testing environments. It is strongly recommended, and the OpenID Spec technically requires, using a secure connection when connecting to issuers. |
openIDAttemptAuthenticationProviderToken | true |
Boolean | Whether to use the AuthenticationProviderToken class when attempting verification of the JWT. See Using AuthenticationProviderToken. |
Note that the only required configuration is the openIDAllowedTokenIssuers
.
Here is a list of supported algorithms for the OpenID Connect auth plugin: RS256, RS384, RS512, ES256, ES384, ES512. The algorithm names follow the spec in RFC-7518.
The JWT claim used to retrieve the role is sub
, by default. If required, you can change the claim by configuring the
openIDRoleClaim
. Note that this library can handle roles that are a String (JSON text) or Arrays of Strings. In the
case that the JSON node is an Array, this library retrieves the first element of the array for the role. This could lead
to undefined behavior if the array changes order, so it is recommended to use single element arrays.
The openIDAllowedTokenIssuers
configuration is essential when configuring which token issuers can be trusted. It is
required by the OAuth2.0 spec RFC-8414 that issuers use
the "https" scheme. This ensures the authenticity of the data received from the Authorization Provider and prevents
the leaking of tokens, which are secrets. By default, this plugin will fail to initialize if there are any allowed
issuers without the "https" scheme. Since it can be helpful during testing to turn this off, it is possible to disable
this verification. Note that this plugin uses the issuer url to first retrieve provider metadata at the
/.well-known/openid-configuration
endpoint. At this endpoint, the plugin retrieves the jwks_uri
, which points
to the current public keys for the issuer. The plugin retrieves the public keys located at the jwks_uri
and caches
them for a configurable amount of time.
Note, also, that the plugin verifies the issuer claim by a direct string equality check, per
RFC-7519. As such, it is necessary
to make sure that the iss
claim on your JWT is contained in the openIDAllowedTokenIssuers
collection.
It is also essential to ensure that the iss
is reachable by the pulsar broker. If the broker cannot reach the allowed
iss
, it won't be able to retrieve the Public Key, which is a necessary step in asymmetric key validation. This detail
is especially relevant if you are deploying keycloak outside the kubernetes cluster hosting pulsar or even in a
separate namespace within the same kubernetes cluster.
In the case where your Token Issuer is running in the same kubernetes cluster as pulsar, but the issuer is accessed from
outside that kubernetes cluster, there is a chance that the networking may not be ideal. This is because the issuer will
likely be the FQDN for the Token Issuer, which is likely pointed at a load balancer, which means that when the broker
retrieves the JWK, it will egress the kubernetes cluster, ingress through the load balancer, and then connect to the
Token Issuer. For this reason, it is recommended that applications collocated in the kubernetes cluster with the Token
Issuer and the Pulsar cluster should use kubernetes cluster DNS to minimize unnecessary network hops. In cases where
both access is required from within and without the kubernetes cluster, multiple openIDAllowedTokenIssuers
should
be configured, even though they will represent the same token issuer backend.
In order to simplify deployment and integration with this new broker plugin, there is a configuration option to use the
AuthenticationProviderToken
plugin in conjunction with the OpenID Connect plugin.
If the openIDAttemptAuthenticationProviderToken
is set to true, and the JWT does not have an iss
claim, the plugin
will attempt to validate the token using the AuthenticationProviderToken
plugin. Otherwise,
it will then attempt to retrieve a Public Key via the OpenID Connect protocol and will use that key to
validate the token. This feature is helpful because there are several pulsar components that need access to a super user
token in order to work, and deploying those components using OpenID Connect (or OAuth2.0) clients is not yet available.
The Luna Streaming Helm Chart includes this plugin by default.
If you're looking to use this plugin without using the Luna Streaming Pulsar distribution, you will need to do the following:
- Include the jar for this plugin on the broker's classpath. Note that the jar produced for this plugin is an uber jar containing the necessary dependencies to run on a pulsar broker.
- Configure the broker to use
com.datastax.oss.pulsar.auth.AuthenticationProviderOpenID
as the authentication provider class. Make sure to enable authentication on the broker. - Configure pulsar clients to use the
AuthenticationOAuth2
clientAuthentication
class. This is the class distributed as part of pulsar.
This plugin will not work simultaneously with org.apache.pulsar.broker.authentication.AuthenticationProviderToken
because Pulsar Brokers load and store authentication providers by the AuthMethodName
, and both this plugin and the
AuthenticationProviderToken
plugin use token
as the AuthMethodName
. This design decision is intentional to make
it easier to use this plugin. See Using AuthenticationProviderToken for details
on using both plugins together.