Skip to content

DSP Druid Security

Imported from Confluence

Content may be outdated. Verify before following any procedures. View original | Last updated: June 2025

1. Configure authentication in values.yaml

Config

# security from official doc
# Security Overview
# Druid basic security
druid_auth_authenticatorChain: '["MyBasicMetadataAuthenticator", "anonymous"]'
druid_auth_authenticator_MyBasicMetadataAuthenticator_type: basic

Default password for 'admin' user, should be changed for production.

druid_auth_authenticator_MyBasicMetadataAuthenticator_initialAdminPassword: ''

# Default password for internal 'druid_system' user, should be changed for production.
druid_auth_authenticator_MyBasicMetadataAuthenticator_initialInternalClientPassword: ''

# Uses the metadata store for storing users.
# You can use the authentication API to create new users and grant permissions
druid_auth_authenticator_MyBasicMetadataAuthenticator_credentialsValidator_type: 'metadata'

# If true and if the request credential doesn't exist in this credentials store,
# the request will proceed to next Authenticator in the chain.
druid_auth_authenticator_MyBasicMetadataAuthenticator_skipOnFailure: 'true'

druid_auth_authenticator_MyBasicMetadataAuthenticator_authorizerName: 'MyBasicMetadataAuthorizer'

# Escalator
druid_escalator_type: 'basic'
druid_escalator_internalClientUsername: 'druid_system'
druid_escalator_internalClientPassword: ''
druid_escalator_authorizerName: 'MyBasicMetadataAuthorizer'

set anonymous=admin before users are configured

druid_auth_authenticator_anonymous_type: 'admin'

druid_auth_authenticator_anonymous_identity: 'anonymous'

druid_auth_authenticator_anonymous_identity: 'admin'
druid_auth_authenticator_anonymous_authorizerName: 'MyBasicMetadataAuthorizer'

druid_auth_authorizers: '["MyBasicMetadataAuthorizer"]'

druid_auth_authorizer_MyBasicMetadataAuthorizer_type: 'basic'

Info:
First we need to set druid_auth_authenticator_anonymous_type: 'admin' because user anonymous doesn't exists yet and even with defaultUser from official documentation pods will fail on readiness probe since /status will require authentication. After we create user anonymous in next steps and assign a role on it which gives permissions to access STATUS then we can replace config to  druid_auth_authenticator_anonymous_identity: 'anonymous' which will have only permissions assigned on role in next steps.

  1. Restart druid cluster

kubectl rollout restart deployment druid-coordinator druid-broker druid-router

kubectl rollout restart sts druid-historical-default

make sure all pods are in Running state

3.  Start pod with ubuntu and curl in the same GKE cluster where druid is configured

Since you need to send requests directly to coordinator pod and since pods ip are not available from openvpn you need to create a pod with curl in the same gke and run queries from there:

kubectl run -it --rm druid-auth-configurator --image ubuntu -- sh -c "apt update && apt install -y curl && bash"

How to use curl with Druid API for configuring users:

  1. You can send requests ONLY to leader coordinator
  2. To understand who is the leader, go to druid ui, services and check ip of coordinator leader
    image-2025-6-12_12-15-37.png

Examples:

curl -u admin: Users

  1. Create script
export URL_MASTER_COORDINATOR=10.143.5.194:8081
export PASSWORD=<CHANGE_ME>

# Check current users
curl -u admin:${PASSWORD} ${URL_MASTER_COORDINATOR}/druid-ext/basic-security/authentication/db/MyBasicMetadataAuthenticator/users

# Create a user by issuing a POST request to druid-ext/basic-security/authentication/db/MyBasicMetadataAuthenticator/users/<USERNAME>. Replace <USERNAME> with the new username you are trying to create.

curl -u admin:${PASSWORD} -XPOST ${URL_MASTER_COORDINATOR}/druid-ext/basic-security/authentication/db/MyBasicMetadataAuthenticator/users/${USER}

# Add a credential for the user by issuing a POST request to druid-ext/basic-security/authentication/db/MyBasicMetadataAuthenticator/users/<USERNAME>/credentials. 
# skip for anonymous 

curl -u admin:${PASSWORD} -H'Content-Type: application/json' -XPOST ${URL_MASTER_COORDINATOR}/druid-ext/basic-security/authentication/db/MyBasicMetadataAuthenticator/users/${USER}/credentials --data-raw "{\"password\": \"${USER_PASSWORD}\"}"

# For each authenticator user you create, create a corresponding authorizer user by issuing a POST request to druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/users/<USERNAME>.

curl -u admin:${PASSWORD} -XPOST ${URL_MASTER_COORDINATOR}/druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/users/${USER}

# Create authorizer roles to control permissions by issuing a POST request to druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/roles/<ROLENAME>.
curl -u admin:${PASSWORD} -XPOST ${URL_MASTER_COORDINATOR}/druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/roles/${ROLE}

# Assign roles to users by issuing a POST request to druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/users/<USERNAME>/roles/<ROLENAME>.

curl -u admin:${PASSWORD} -XPOST ${URL_MASTER_COORDINATOR}/druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/users/${USER}/roles/${ROLE}

# Finally, attach permissions to the roles to control how they can interact with Druid at druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/roles/<ROLENAME>/permissions.

echo $ROLE_PERMISSIONS > perms_${ROLE}.json

curl -u admin:${PASSWORD} -H'Content-Type: application/json' -XPOST --data-binary @perms_${ROLE}.json ${URL_MASTER_COORDINATOR}/druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/roles/${ROLE}/permissions

# check role
curl -u admin:${PASSWORD} ${URL_MASTER_COORDINATOR}/druid-ext/basic-security/authorization/db/MyBasicMetadataAuthorizer/roles/${ROLE}/permissions | jq .
  1. Create user anonymous

URL_MASTER_COORDINATOR=10.143.0.101
PASSWORD=
USER=anonymous
USER_PASSWORD=''
ROLE='anonrole'
ROLE_PERMISSIONS='[
{
"resource": {
"type": "DATASOURCE",
"name": ".*"
},
"action": "READ"
},
{
"resource": {
"type": "STATE",
"name": "STATE"
},
"action": "READ"
},
{
"resource": {
"type": "CONFIG",
"name": "CONFIG"
},
"action": "READ"
}
]'

./create_user.sh

  1. Update druid config and set

druid_auth_authenticator_anonymous_identity: 'anonymous'

  1. restart druid cluster

kubectl rollout restart deployment druid-coordinator druid-broker druid-router

kubectl rollout restart sts druid-historical-default

make sure all pods are in Running state

  1. Create user for rill

rill

URL_MASTER_COORDINATOR=10.143.0.101
PASSWORD=
USER=rilldsp
USER_PASSWORD=openssl rand -base64 12 | cut -c1-12
echo "User ${USER} was assigned password ${USER_PASSWORD}"

ROLE='rillrole'
ROLE_PERMISSIONS='[
{
"resource": {
"type": "DATASOURCE",
"name": ".*"
},
"action": "READ"
}
]'

./create_user.sh

Update - disable anonymous acces

Issue:
"another question: can we make the anonymous user more powerful or allow to connect to the dashboard with a real user? The reason is that it is really annoying to configure all lookups with HTTP requests and using the UI would be much more convenient"

So adding more permissions to anonymous user would be insecure since it's exposed to internet and even access is restricted by firewall (Cloud Armour) we did wan't to give any WRITE permissions. Instead we decided to disable it completely and let developers use admin user to login to console and then use it for configuration:

  1. Remove anoymous user from authentication chain

druid_auth_authenticatorChain: '["MyBasicMetadataAuthenticator"] 2. After anonymous user was disabled few thing were broken 1. Readiness and Liveness probs stopped working since /status path on pods require authentication 2. Autoscaler stopped working since it doesn't support authentication
Solution was use unsecured path, add to values.yaml

  druid_auth_unsecuredPaths: '["/status", "/status/selfDiscovered", "/status/health", "/status/selfDiscovered/status", "/druid/indexer/v1/pendingTasks", "/druid/indexer/v1/workers"]
  1. Disable skip on failure

druid_auth_authenticator_MyBasicMetadataAuthenticator_skipOnFailure: 'false'