Druid API users
Most Imply users in an organization will access Pivot. You can provision such users as described in Pivot access control. Access to Druid or the Druid console, in the typical case, is limited by network firewall rules.
In some cases, however, you may wish to control access at the Druid layer. This would be the case, for example, if you want to allow for CLI queries or have custom clients or third-party software that need to access Druid. This document describes how to create and manage a Druid API user, defining its authentication credentials, roles, and permissions.
Accessing the coordinator
Druid API users are configured through an endpoint on the coordinator service. You can find the coordinator API endpoint under a cluster's API view:
This view provides both the private and public endpoints for the coordinator. Note the IP addresses of the coordinator in the Coordinator server fields.
Default admin credentials
You'll need a user account with sufficient privileges to access the API user configuration endpoints. Imply includes a default admin user with superuser privileges. The username and initial password for this default admin account is located in the Security section of a cluster's API view, contained in the Initial Druid API user and Initial Druid API pass fields, respectively.
The default admin account should be used in the following tutorial examples.
Authentication
Creating a new user
To create a new user, issue a POST to https://<coordinator-ip>:8281/druid-ext/basic-security/authentication/db/basic/users/<username>
.
The following curl command creates a user named tutorial
. Be sure to replace <coordinator-ip>
with the private or public address of the coordinator, as shown in your cluster's API view.
curl -u admin:password -XPOST https://<coordinator-ip>:8281/druid-ext/basic-security/authentication/db/basic/users/tutorial
List all users
To verify that the new user was created, issue a GET to https://<coordinator-ip>:8281/druid-ext/basic-security/authentication/db/basic/users
.
For example, the following curl command:
curl -u admin:password https://<coordinator-ip>:8281/druid-ext/basic-security/authentication/db/basic/users
should return the following output on a new cluster, indicating that the tutorial
user was created:
["admin","tutorial"]
Show a single user
You can also verify that the new user was created by requesting information for a specific user.
To do so, issue a GET to https://<coordinator-ip>:8281/druid-ext/basic-security/authentication/db/basic/users/<username>
The following curl command retrieves information for the tutorial
user:
curl -u admin:password https://<coordinator-ip>:8281/druid-ext/basic-security/authentication/db/basic/users/tutorial
It should return the following output:
{"name":"tutorial","credentials":null}
Note that the tutorial
user does not have any credentials information set. The next step will show you how to assign a password for the tutorial
user.
Set a password for the user
Let's assign a password to the tutorial
user now.
To do so, you will need to POST a password update in JSON format to https://<coordinator-ip>:8281/druid-ext/basic-security/authentication/db/basic/users/<username>/credentials
The following example request body shows the format of the JSON password update object:
{"password": "foobar123"}
The following curl command assigns a password to the tutorial
user, where pass.json
contains JSON data in the format show above.
curl -u admin:password -H'Content-Type: application/json' -XPOST --data-binary @pass.json https://<coordinator-ip>:8281/druid-ext/basic-security/authentication/db/basic/users/tutorial/credentials
If you retrieve the tutorial
user's information now, you should see that credentials have been assigned, e.g.:
curl -u admin:password https://<coordinator-ip>:8281/druid-ext/basic-security/authentication/db/basic/users/tutorial
{"name":"tutorial","credentials":{"salt":"O1777dLwNzgZVNkNBTbnl6nQxi60nmGawb9E33qernE=","hash":"02pH8/wZ8rUGv8GdokAkxbIXGad5bxRMbX9fd54EeeN5AdwWAV31FF54V0p3cBSWqQZhm/6cw14T9/bwxSgsUA==","iterations":10000}}
We've now configured a user that can authenticate with your Druid cluster. The next section will show how you can define roles and permissions for the new user.
Role-based Access Control
Creating a new user
Please note that the role-based access control system is a separate module from the basic HTTP authentication module. Therefore, it's necessary to create a new user in the role-based access control system separately from the user that you configured in the previous section. The RBAC user name must be identical to the authentication user name.
To create a new user, issue a POST to https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/users/<username>
.
The following curl command creates a user named tutorial
.
curl -u admin:password -XPOST https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/users/tutorial
List all users
To verify that the new user was created, issue a GET to https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/users
.
For example, the following curl command:
curl -u admin:password https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/users
should return the following output on a new cluster, indicating that the tutorial
user was created:
["admin","tutorial"]
Show a single user
You can also verify that the new user was created by requesting information for a specific user.
To do so, issue a GET to https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/users/<username>
The following curl command retrieves information for the tutorial
user:
curl -u admin:password https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/users/tutorial
It should return the following output:
{"name":"tutorial","roles":[]}
Creating a role
To create a new role, issue a POST to https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/roles/<rolename>
.
curl -u admin:password -XPOST https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/roles/tutorial_role
List all roles
To verify that the new role was created, issue a GET to https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/roles
.
For example, the following curl command:
curl -u admin:password https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/roles
should return the following output on a new cluster, indicating that the tutorial_role
role was created:
["admin","tutorial_role"]
Show a single role
You can also verify that the new role was created by requesting information for a specific role.
To do so, issue a GET to https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/roles/<rolename>
The following curl command retrieves information for the tutorial_role
role:
curl -u admin:password https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/roles/tutorial_role
It should return the following output:
{"name":"tutorial_role","permissions":[]}
Set the permissions of a role
Let's now set permissions for the newly created tutorial_role
.
To set permissions for a role, issue a POST to https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/roles/<roleName>/permissions
, where the request body contains a JSON list of permission definitions.
An example list of permission definitions is show below:
[
{
"resource": {
"name": ".*",
"type": "STATE"
},
"action": "READ"
},
{
"resource": {
"name": ".*",
"type": "STATE"
},
"action": "WRITE"
}
]
This list of permission definitions grants a role READ and WRITE access to all resources of type STATE. For more details on permission definitions, please refer to Defining permissions
The following curl command assigns permissions to tutorial_role
, where perms.json
contains the JSON list of permissions shown above.
curl -u admin:password -H'Content-Type: application/json' -XPOST --data-binary @perms.json https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/roles/tutorial_role/permissions
Retrieving information about the tutorial_role
should now show that it has the newly assigned permissions:
curl -u admin:password https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/roles/tutorial_role
{
"name": "tutorial_role",
"permissions": [
{
"resourceAction": {
"resource": {
"name": ".*",
"type": "STATE"
},
"action": "READ"
},
"resourceNamePattern": ".*"
},
{
"resourceAction": {
"resource": {
"name": ".*",
"type": "STATE"
},
"action": "WRITE"
},
"resourceNamePattern": ".*"
}
]
}
Assign a role to a user
Now that we have set permissions for tutorial_role
, let's assign tutorial_role
to the tutorial
user that you previously created.
To assign a role to a user, issue a POST to https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/users/<username>/roles/<rolename>
The following curl command assigns the role tutorial_role
to the tutorial
user:
curl -u admin:password -XPOST https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/users/tutorial/roles/tutorial_role | jq
Retrieving the information for tutorial
now shows that the user has the tutorial_role
assigned.
curl -u admin:password https://<coordinator-ip>:8281/druid-ext/basic-security/authorization/db/basic/users/tutorial
{"name":"tutorial","roles":["tutorial_role"]}
Verifying the new user account
Now that the tutorial
user has authentication and access control configured, you can test this new user account by issuing a GET to the /status
endpoint on the coordinator. The STATE READ permission grants the tutorial
access to this endpoint.
curl -u tutorial:foobar123 https://<coordinator-ip>:8281/status
This command should produce output similar to the following:
{"version":"0.11.0-iap1-SNAPSHOT","modules":[{"name":"io.druid.storage.s3.S3StorageDruidModule","artifact":"druid-s3-extensions","version":"0.11.0-iap1-SNAPSHOT"},{"name":"io.druid.firehose.s3.S3FirehoseDruidModule","artifact":"druid-s3-extensions","version":"0.11.0-iap1-SNAPSHOT"},{"name":"io.druid.indexing.kafka.KafkaIndexTaskModule","artifact":"druid-kafka-indexing-service","version":"0.11.0-iap1-SNAPSHOT"},{"name":"io.druid.query.aggregation.histogram.ApproximateHistogramDruidModule","artifact":"druid-histogram","version":"0.11.0-iap1-SNAPSHOT"},{"name":"io.imply.clarity.emitter.ClarityEmitterModule"},{"name":"io.druid.security.basic.BasicSecurityDruidModule","artifact":"druid-basic-security","version":"0.11.0-iap1-SNAPSHOT"},{"name":"io.druid.examples.ExamplesDruidModule","artifact":"druid-examples","version":"0.11.0-iap1-SNAPSHOT"},{"name":"io.druid.query.aggregation.datasketches.theta.SketchModule","artifact":"druid-datasketches","version":"0.11.0-iap1-SNAPSHOT"},{"name":"io.druid.query.aggregation.datasketches.theta.oldapi.OldApiSketchModule","artifact":"druid-datasketches","version":"0.11.0-iap1-SNAPSHOT"},{"name":"io.druid.metadata.storage.mysql.MySQLMetadataStorageModule","artifact":"mysql-metadata-storage","version":"0.11.0-iap1-SNAPSHOT"},{"name":"io.druid.server.lookup.namespace.NamespaceExtractionModule","artifact":"druid-lookups-cached-global","version":"0.11.0-iap1-SNAPSHOT"},{"name":"io.druid.parsers.ParserRouteModule","artifact":"druid-parser-route","version":"0.11.0.5"},{"name":"io.druid.https.SSLContextModule","artifact":"simple-client-sslcontext","version":"0.11.0-iap1-SNAPSHOT"},{"name":"io.imply.security.ImplySecurityDruidModule"}],"memory":{"maxMemory":536870912,"totalMemory":536870912,"freeMemory":213291048,"usedMemory":323579864}}