Authentication using Athenz

Athenz is a role-based authentication/authorization system. In Pulsar, you can use Athenz role tokens (also known as z-tokens) to establish the identity of the client.

A decentralized Athenz system contains an authoriZation Management System (ZMS) server and an authoriZation Token System (ZTS) server.

Prerequisites

To begin, you need to set up Athenz service access control by creating domains for the provider (which provides some resources to other services with some authentication/authorization policies) and the tenant (which is provisioned to access some resources in a provider). In this case, the provider corresponds to the Pulsar service itself and the tenant corresponds to each application using Pulsar (typically, a tenant in Pulsar).

Create a tenant domain and service

On the tenant side, do the followings:

  1. Create a domain, such as shopping.
  2. Generate a private/public key pair.
  3. Create a service, such as some_app, on the domain with the public key.

Note that you need to specify the private key generated in step 2 when the Pulsar client connects to the broker.

For more specific steps involving the Athenz UI, refer to Example Service Access Control Setup.

Create a provider domain and add the tenant service to role members

On the provider side, you need to do the following things:

  1. Create a domain, such as pulsar.
  2. Create a role.
  3. Add the tenant service to the members of the role.

Note that you can specify any action and resource in step 2 since they are not used on Pulsar. In other words, Pulsar uses the Athenz role token only for authentication, not for authorization.

For more specific steps involving the Athenz UI, refer to Example Service Access Control Setup.

Enable Athenz authentication on brokers/proxies

To configure brokers/proxies to authenticate clients using Authenz, add the following parameters to the conf/broker.conf and the conf/proxy.conf files and provide the class name of the Athenz authentication provider as well as a comma-separated list of provider domain names. If you use a standalone Pulsar, you need to add these parameters to the conf/standalone.conf file.

  1. # Add the Athenz auth provider
  2. authenticationEnabled=true
  3. authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderAthenz
  4. athenzDomainNames=pulsar
  5. # Authentication settings of the broker itself. Used when the broker connects to other brokers, or when the proxy connects to brokers, either in same or other clusters
  6. brokerClientAuthenticationPlugin=org.apache.pulsar.client.impl.auth.AuthenticationAthenz
  7. brokerClientAuthenticationParameters={"tenantDomain":"shopping","tenantService":"some_app","providerDomain":"pulsar","privateKey":"file:///path/to/private.pem","keyId":"v1"}

Configure Athenz authentication in Pulsar clients

To use Athenz as an authentication provider, you need to provide values for four parameters in a hash:

  • tenantDomain
  • tenantService
  • providerDomain
  • privateKey

Authentication using Athenz - 图1tip

The privateKey parameter supports the following three pattern formats:

  • file:///path/to/file
  • file:/path/to/file
  • data:application/x-pem-file;base64,<base64-encoded value>

You can also set an optional keyId. The following is an example.

  • Java
  • Python
  • C++
  • Node.js
  • Go
  1. Map<String, String> authParams = new HashMap();
  2. authParams.put("ztsUrl", "http://localhost:9998");
  3. authParams.put("tenantDomain", "shopping"); // Tenant domain name
  4. authParams.put("tenantService", "some_app"); // Tenant service name
  5. authParams.put("providerDomain", "pulsar"); // Provider domain name
  6. authParams.put("privateKey", "file:///path/to/private.pem"); // Tenant private key path
  7. authParams.put("keyId", "v1"); // Key id for the tenant private key (optional, default: "0")
  8. Authentication athenzAuth = AuthenticationFactory
  9. .create(AuthenticationAthenz.class.getName(), authParams);
  10. PulsarClient client = PulsarClient.builder()
  11. .serviceUrl("pulsar://my-broker.com:6650")
  12. .authentication(athenzAuth)
  13. .build();
  1. authPlugin = "athenz"
  2. authParams = """
  3. {
  4. "tenantDomain": "shopping",
  5. "tenantService": "some_app",
  6. "providerDomain": "pulsar",
  7. "privateKey": "file:///path/to/private.pem",
  8. "ztsUrl": "http://localhost:9998"
  9. }
  10. """
  11. client = Client(
  12. "pulsar://my-broker.com:6650",
  13. authentication=Authentication(authPlugin, authParams),
  14. )
  1. std::string params = R"({
  2. "tenantDomain": "shopping",
  3. "tenantService": "some_app",
  4. "providerDomain": "pulsar",
  5. "privateKey": "file:///path/to/private.pem",
  6. "ztsUrl": "http://localhost:9998"
  7. })";
  8. pulsar::AuthenticationPtr auth = pulsar::AuthAthenz::create(params);
  9. ClientConfiguration config = ClientConfiguration();
  10. config.setAuth(auth);
  11. Client client("pulsar://my-broker.com:6650", config);
  1. const auth = new Pulsar.AuthenticationAthenz({
  2. tenantDomain: "shopping",
  3. tenantService: "some_app",
  4. providerDomain: "pulsar",
  5. privateKey: "file:///path/to/private.pem",
  6. ztsUrl: "http://localhost:9998"
  7. });
  8. const client = new Pulsar.Client({
  9. serviceUrl: 'pulsar://my-broker.com:6650',
  10. authentication: auth
  11. });
  1. provider := pulsar.NewAuthenticationAthenz(map[string]string{
  2. "ztsUrl": "http://localhost:9998",
  3. "providerDomain": "pulsar",
  4. "tenantDomain": "shopping",
  5. "tenantService": "some_app",
  6. "privateKey": "file:///path/to/private.pem",
  7. "keyId": "v1",
  8. })
  9. client, err := pulsar.NewClient(pulsar.ClientOptions{
  10. URL: "pulsar://my-broker.com:6650",
  11. Authentication: provider,
  12. })

Use Copper Argos

Athenz has a mechanism called Copper Argos. This means that ZTS distributes an X.509 certificate and private key pair to each service, which it can use to identify itself to other services within the organization.

When using Copper Argos, you need to provide at least the following four parameters:

  • providerDomain
  • x509CertChain
  • privateKey
  • caCert

In this case, tenantDomain, tenantService and keyId are ignored.

  • Java
  • Python
  • C++
  • Node.js
  • Go
  1. Map<String, String> authParams = new HashMap();
  2. authParams.put("ztsUrl", "http://localhost:9998");
  3. authParams.put("providerDomain", "pulsar"); // Provider domain name
  4. authParams.put("x509CertChain", "file:///path/to/x509cert.pem"); // Distributed X.509 certificate path
  5. authParams.put("privateKey", "file:///path/to/private.pem"); // Distributed private key path
  6. authParams.put("caCert", "file:///path/to/cacert.pem"); // CA certificate path
  7. Authentication athenzAuth = AuthenticationFactory
  8. .create(AuthenticationAthenz.class.getName(), authParams);
  9. PulsarClient client = PulsarClient.builder()
  10. .serviceUrl("pulsar://my-broker.com:6650")
  11. .authentication(athenzAuth)
  12. .build();
  1. authPlugin = "athenz"
  2. authParams = """
  3. {
  4. "ztsUrl": "http://localhost:9998",
  5. "providerDomain": "pulsar",
  6. "x509CertChain": "file:///path/to/x509cert.pem",
  7. "privateKey": "file:///path/to/private.pem",
  8. "caCert": "file:///path/to/cacert.pem"
  9. }
  10. """
  11. client = Client(
  12. "pulsar://my-broker.com:6650",
  13. authentication=Authentication(authPlugin, authParams),
  14. )
  1. std::string params = R"({
  2. "ztsUrl": "http://localhost:9998",
  3. "providerDomain": "pulsar",
  4. "x509CertChain": "file:///path/to/x509cert.pem",
  5. "privateKey": "file:///path/to/private.pem",
  6. "caCert": "file:///path/to/cacert.pem"
  7. })";
  8. pulsar::AuthenticationPtr auth = pulsar::AuthAthenz::create(params);
  9. ClientConfiguration config = ClientConfiguration();
  10. config.setAuth(auth);
  11. Client client("pulsar://my-broker.com:6650", config);
  1. const auth = new Pulsar.AuthenticationAthenz({
  2. ztsUrl: "http://localhost:9998",
  3. providerDomain: "pulsar",
  4. x509CertChain: "file:///path/to/x509cert.pem",
  5. privateKey: "file:///path/to/private.pem",
  6. caCert: "file:///path/to/cacert.pem"
  7. });
  8. const client = new Pulsar.Client({
  9. serviceUrl: 'pulsar://my-broker.com:6650',
  10. authentication: auth
  11. });
  1. provider := pulsar.NewAuthenticationAthenz(map[string]string{
  2. "ztsUrl": "http://localhost:9998",
  3. "providerDomain": "pulsar",
  4. "x509CertChain": "file:///path/to/x509cert.pem",
  5. "privateKey": "file:///path/to/private.pem",
  6. "caCert": "file:///path/to/cacert.pem",
  7. })
  8. client, err := pulsar.NewClient(pulsar.ClientOptions{
  9. URL: "pulsar://my-broker.com:6650",
  10. Authentication: provider,
  11. })

Configure Athenz authentication in CLI tools

Command-line tools like pulsar-admin, pulsar-perf, and pulsar-client use the conf/client.conf config file in a Pulsar installation.

You need to add the following authentication parameters to the conf/client.conf config file to use Athenz with CLI tools of Pulsar:

  1. # URL for the broker
  2. serviceUrl=http://broker.example.com:8080
  3. # Set Athenz auth plugin and its parameters
  4. authPlugin=org.apache.pulsar.client.impl.auth.AuthenticationAthenz
  5. authParams={"tenantDomain":"shopping","tenantService":"some_app","providerDomain":"pulsar","privateKey":"file:///path/to/private.pem","keyId":"v1"}