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:
- Create a domain, such as
shopping
. - Generate a private/public key pair.
- 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:
- Create a domain, such as
pulsar
. - Create a role.
- 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.
# Add the Athenz auth provider
authenticationEnabled=true
authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderAthenz
athenzDomainNames=pulsar
# 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
brokerClientAuthenticationPlugin=org.apache.pulsar.client.impl.auth.AuthenticationAthenz
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
tip
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
Map<String, String> authParams = new HashMap();
authParams.put("ztsUrl", "http://localhost:9998");
authParams.put("tenantDomain", "shopping"); // Tenant domain name
authParams.put("tenantService", "some_app"); // Tenant service name
authParams.put("providerDomain", "pulsar"); // Provider domain name
authParams.put("privateKey", "file:///path/to/private.pem"); // Tenant private key path
authParams.put("keyId", "v1"); // Key id for the tenant private key (optional, default: "0")
Authentication athenzAuth = AuthenticationFactory
.create(AuthenticationAthenz.class.getName(), authParams);
PulsarClient client = PulsarClient.builder()
.serviceUrl("pulsar://my-broker.com:6650")
.authentication(athenzAuth)
.build();
authPlugin = "athenz"
authParams = """
{
"tenantDomain": "shopping",
"tenantService": "some_app",
"providerDomain": "pulsar",
"privateKey": "file:///path/to/private.pem",
"ztsUrl": "http://localhost:9998"
}
"""
client = Client(
"pulsar://my-broker.com:6650",
authentication=Authentication(authPlugin, authParams),
)
std::string params = R"({
"tenantDomain": "shopping",
"tenantService": "some_app",
"providerDomain": "pulsar",
"privateKey": "file:///path/to/private.pem",
"ztsUrl": "http://localhost:9998"
})";
pulsar::AuthenticationPtr auth = pulsar::AuthAthenz::create(params);
ClientConfiguration config = ClientConfiguration();
config.setAuth(auth);
Client client("pulsar://my-broker.com:6650", config);
const auth = new Pulsar.AuthenticationAthenz({
tenantDomain: "shopping",
tenantService: "some_app",
providerDomain: "pulsar",
privateKey: "file:///path/to/private.pem",
ztsUrl: "http://localhost:9998"
});
const client = new Pulsar.Client({
serviceUrl: 'pulsar://my-broker.com:6650',
authentication: auth
});
provider := pulsar.NewAuthenticationAthenz(map[string]string{
"ztsUrl": "http://localhost:9998",
"providerDomain": "pulsar",
"tenantDomain": "shopping",
"tenantService": "some_app",
"privateKey": "file:///path/to/private.pem",
"keyId": "v1",
})
client, err := pulsar.NewClient(pulsar.ClientOptions{
URL: "pulsar://my-broker.com:6650",
Authentication: provider,
})
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.
Currently, Pulsar supports Copper Argos in Java, C++, and Go. 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
- C++
- Go
Map<String, String> authParams = new HashMap();
authParams.put("ztsUrl", "http://localhost:9998");
authParams.put("providerDomain", "pulsar"); // Provider domain name
authParams.put("x509CertChain", "file:///path/to/x509cert.pem"); // Distributed X.509 certificate path
authParams.put("privateKey", "file:///path/to/private.pem"); // Distributed private key path
authParams.put("caCert", "file:///path/to/cacert.pem"); // CA certificate path
Authentication athenzAuth = AuthenticationFactory
.create(AuthenticationAthenz.class.getName(), authParams);
PulsarClient client = PulsarClient.builder()
.serviceUrl("pulsar://my-broker.com:6650")
.authentication(athenzAuth)
.build();
std::string params = R"({
"ztsUrl": "http://localhost:9998",
"providerDomain": "pulsar",
"x509CertChain": "file:///path/to/x509cert.pem",
"privateKey": "file:///path/to/private.pem",
"caCert": "file:///path/to/cacert.pem"
})";
pulsar::AuthenticationPtr auth = pulsar::AuthAthenz::create(params);
ClientConfiguration config = ClientConfiguration();
config.setAuth(auth);
Client client("pulsar://my-broker.com:6650", config);
provider := pulsar.NewAuthenticationAthenz(map[string]string{
"ztsUrl": "http://localhost:9998",
"providerDomain": "pulsar",
"x509CertChain": "file:///path/to/x509cert.pem",
"privateKey": "file:///path/to/private.pem",
"caCert": "file:///path/to/cacert.pem",
})
client, err := pulsar.NewClient(pulsar.ClientOptions{
URL: "pulsar://my-broker.com:6650",
Authentication: provider,
})
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:
# URL for the broker
serviceUrl=http://broker.example.com:8080
# Set Athenz auth plugin and its parameters
authPlugin=org.apache.pulsar.client.impl.auth.AuthenticationAthenz
authParams={"tenantDomain":"shopping","tenantService":"some_app","providerDomain":"pulsar","privateKey":"file:///path/to/private.pem","keyId":"v1"}