基础安全
Apache Druid 的基础安全扩展增加了以下功能:
- 一个身份验证器(Authenticator),支持使用 Druid 元数据存储或 LDAP 作为凭据存储的 HTTP 基本身份验证。
- 一个授权转换器(Escalator),用于确定 Druid 内部进程的身份验证方案。
- 一个授权器(Authorizer),为 Druid 元数据存储或 LDAP 用户和组实现了基本的基于角色的访问控制。
要加载此扩展,请在 common.runtime.properties 文件中的 druid.extensions.loadList 里包含 druid-basic-security。例如:
druid.extensions.loadList=["postgresql-metadata-storage", "druid-hdfs-storage", "druid-basic-security"]
要启用基本身份验证,请在 common.runtime.properties 中配置基础身份验证器、授权转换器和授权器。有关 HTTP 基本身份验证的配置示例,请参阅安全概述。
访问身份验证与授权,了解更多有关已实现扩展接口的信息及配置示例。
配置
本节中的示例对身份验证器和授权器使用了以下名称:
MyBasicMetadataAuthenticatorMyBasicLDAPAuthenticatorMyBasicMetadataAuthorizerMyBasicLDAPAuthorizer
这些属性并不绑定到特定的身份验证器或授权器实例。
要设置这些配置属性的值,请将它们添加到通用运行时属性文件中。
通用属性
druid.auth.basic.common.pollingPeriod
定义进程轮询 Coordinator 以获取当前 Druid 元数据存储身份验证器/授权器状态的频率(以毫秒为单位)。
必需:否
默认值: 60000
druid.auth.basic.common.maxRandomDelay
定义添加到 pollingPeriod 中的随机延迟量(以毫秒为单位),用于将轮询请求分散到不同时间点。
必需:否
默认值: 6000
druid.auth.basic.common.maxSyncRetries
确定如果与 Coordinator 的身份验证/授权 Druid 元数据存储状态同步失败时,服务将重试的次数。
必需:否
默认值: 10
druid.auth.basic.common.cacheDirectory
如果定义了此路径,基础身份验证器和授权器 Druid 元数据存储缓存的快照将存储在该目录的磁盘上。若定义了此属性,且服务无法通过与 Coordinator 通信来初始化其状态时,服务在启动时将尝试从这些磁盘快照中初始化缓存。
必需:否
默认值:null
身份验证器
要使用基础身份验证器,请向 authenticatorChain 添加一个类型为 basic 的身份验证器。默认凭据验证器(credentialsValidator)为 metadata。要使用 LDAP 验证器,请定义一个类型为 'ldap' 的凭据验证器。
使用以下语法配置命名身份验证器:
druid.auth.authenticator.<authenticatorName>.<authenticatorProperty>
使用 Druid 元数据存储来查找和验证凭据的身份验证器配置示例:
# Druid basic security
druid.auth.authenticatorChain=["MyBasicMetadataAuthenticator"]
druid.auth.authenticator.MyBasicMetadataAuthenticator.type=basic
# Default password for 'admin' user, should be changed for production.
druid.auth.authenticator.MyBasicMetadataAuthenticator.initialAdminPassword=password1
# Default password for internal 'druid_system' user, should be changed for production.
druid.auth.authenticator.MyBasicMetadataAuthenticator.initialInternalClientPassword=password2
# Uses the metadata store for storing users, you can use authentication API to create new users and grant permissions
druid.auth.authenticator.MyBasicMetadataAuthenticator.credentialsValidator.type=metadata
# If true and the request credential doesn't exist in this credentials store, the request proceeds to the next Authenticator in the chain.
druid.auth.authenticator.MyBasicMetadataAuthenticator.skipOnFailure=false
druid.auth.authenticator.MyBasicMetadataAuthenticator.authorizerName=MyBasicMetadataAuthorizer
剩余的身份验证器配置示例均使用 MyBasicMetadataAuthenticator 或 MyBasicLDAPAuthenticator 作为身份验证器名称。
用于 Druid 元数据存储用户身份验证的属性
druid.auth.authenticator.MyBasicMetadataAuthenticator.initialAdminPassword
为自动创建的默认管理员用户提供的初始密码提供程序。如果未指定密码,则不会创建默认管理员用户。如果默认管理员用户已存在,设置此属性不会影响其密码。
必需:否
默认值:null
druid.auth.authenticator.MyBasicMetadataAuthenticator.initialInternalClientPassword
用于内部进程通信的默认内部系统用户的初始密码提供程序。如果未指定密码,则不会创建默认内部系统用户。如果默认内部系统用户已存在,设置此属性不会影响其密码。
必需:否
默认值:null
druid.auth.authenticator.MyBasicMetadataAuthenticator.enableCacheNotifications
如果为 true,当此身份验证器的配置发生变化时,Coordinator 将通知 Druid 进程,从而允许它们立即更新状态而无需等待轮询。
必需:否
默认值:True
druid.auth.authenticator.MyBasicMetadataAuthenticator.cacheNotificationTimeout
缓存通知的超时时间(以毫秒为单位)。
必需:否
默认值: 5000
druid.auth.authenticator.MyBasicMetadataAuthenticator.credentialIterations
用于密码哈希的迭代次数。请参阅凭据迭代次数与 API 性能。
必需:否
默认值: 10000
druid.auth.authenticator.MyBasicMetadataAuthenticator.credentialsValidator.type
用于验证请求凭据的凭据存储类型(metadata)。
必需:否
默认值:metadata
druid.auth.authenticator.MyBasicMetadataAuthenticator.skipOnFailure
如果为 true,且请求凭据不存在或在凭据存储中未完全配置,则请求将继续由链中的下一个身份验证器处理。
必需:否
默认值:false
druid.auth.authenticator.MyBasicMetadataAuthenticator.authorizerName
请求应导向的授权器。
必需:是
默认值:不适用
凭据迭代次数与 API 性能
如上所述,credentialIterations 的值决定了对密码进行哈希处理的迭代次数。迭代次数越高,安全性越强。默认值 10,000 是刻意设置的高值,以防止攻击者使用暴力破解猜测密码。我们建议不要降低此值。Druid 会缓存过去一小时内使用的多达 1000 个密码的哈希值,以确保大量的迭代次数不会对查询性能产生明显影响。
如果 Druid 使用默认凭据验证器(即 credentialsValidator.type=metadata),更改 credentialIterations 值仅会影响更改后创建的用户,或随后通过 /druid-ext/basic-security/authentication/db/basic/users/{userName}/credentials 端点更新密码的用户。如果 Druid 使用 ldap 验证器,则此更改会在下次登录时应用于任何用户(以及新用户或更新密码的用户)。
用于 LDAP 用户身份验证的属性
druid.auth.authenticator.MyBasicLDAPAuthenticator.initialAdminPassword
为自动创建的默认管理员用户提供的初始密码提供程序。如果未指定密码,则不会创建默认管理员用户。如果默认管理员用户已存在,设置此属性不会影响其密码。
必需:否
默认值:null
druid.auth.authenticator.MyBasicLDAPAuthenticator.initialInternalClientPassword
用于内部进程通信的默认内部系统用户的初始密码提供程序。如果未指定密码,则不会创建默认内部系统用户。如果默认内部系统用户已存在,设置此属性不会影响其密码。
必需:否
默认值:null
druid.auth.authenticator.MyBasicLDAPAuthenticator.enableCacheNotifications
如果为 true,当此身份验证器的配置发生变化时,Coordinator 将通知 Druid 进程,从而允许它们立即更新状态而无需等待轮询。
必需:否
默认值:true
druid.auth.authenticator.MyBasicLDAPAuthenticator.cacheNotificationTimeout
缓存通知的超时时间(以毫秒为单位)。
必需:否
默认值: 5000
druid.auth.authenticator.MyBasicLDAPAuthenticator.credentialIterations
用于密码哈希的迭代次数。
必需:否
默认值: 10000
druid.auth.authenticator.MyBasicLDAPAuthenticator.credentialsValidator.type
用于验证请求凭据的凭据存储类型(ldap)。
必需:否
默认值:metadata
druid.auth.authenticator.MyBasicLDAPAuthenticator.credentialsValidator.url
LDAP 服务器的 URL。
必需:是
默认值:null
druid.auth.authenticator.MyBasicLDAPAuthenticator.credentialsValidator.bindUser
LDAP 绑定用户的用户名。
必需:是
默认值:null
druid.auth.authenticator.MyBasicLDAPAuthenticator.credentialsValidator.bindPassword
密码提供程序 LDAP 绑定用户密码。
必需:是
默认值:null
druid.auth.authenticator.MyBasicLDAPAuthenticator.credentialsValidator.baseDn
LDAP 服务器搜索用户的起始位置。
必需:是
默认值:null
druid.auth.authenticator.MyBasicLDAPAuthenticator.credentialsValidator.userSearch
用于搜索的过滤器/表达式。例如,(&(sAMAccountName=%s)(objectClass=user))
必需:是
默认值:null
druid.auth.authenticator.MyBasicLDAPAuthenticator.credentialsValidator.userAttribute
用于标识搜索结果中返回的属性的 ID。例如,sAMAccountName。
必需:是
默认值:null
druid.auth.authenticator.MyBasicLDAPAuthenticator.credentialsValidator.credentialVerifyDuration
当未请求时,有效凭据在缓存中可被验证的持续时间(以秒为单位)。
必需:否
默认值: 600
druid.auth.authenticator.MyBasicLDAPAuthenticator.credentialsValidator.credentialMaxDuration
无论请求频率如何,有效凭据可在缓存中保留的最长持续时间(以秒为单位)。
必需:否
默认值: 3600
druid.auth.authenticator.MyBasicLDAPAuthenticator.credentialsValidator.credentialCacheSize
有效凭据缓存的大小。缓存使用 LRU(最近最少使用)策略。
必需:否
默认值: 100
druid.auth.authenticator.MyBasicLDAPAuthenticator.skipOnFailure
如果为 true,且请求凭据不存在或在凭据存储中未完全配置,则请求将继续由链中的下一个身份验证器处理。
必需:否
默认值:false
druid.auth.authenticator.MyBasicLDAPAuthenticator.authorizerName
请求应导向的授权器。
必需:是
默认值:不适用
授权转换器(Escalator)
授权转换器确定用于 Druid 集群内部通信的身份验证方案,例如当 Broker 服务在查询处理过程中与 Historical 服务通信时。
配置示例
# Escalator
druid.escalator.type=basic
druid.escalator.internalClientUsername=druid_system
druid.escalator.internalClientPassword=password2
druid.escalator.authorizerName=MyBasicMetadataAuthorizer
属性
druid.escalator.internalClientUsername
授权转换器将对以内部系统用户身份发出的请求使用此用户名。
必需:是
默认值:不适用
druid.escalator.internalClientPassword
授权转换器将对以内部系统用户身份发出的请求使用此密码提供程序。
必需:是
默认值:不适用
druid.escalator.authorizerName
请求应导向的授权器。
必需:是
默认值:不适用
授权器(Authorizer)
要使用基础授权器,请向 authorizers 列表添加一个类型为 basic 的授权器。
使用以下语法配置命名授权器:
druid.auth.authorizer.<authorizerName>.<authorizerProperty>
配置示例
# Authorizer
druid.auth.authorizers=["MyBasicMetadataAuthorizer"]
druid.auth.authorizer.MyBasicMetadataAuthorizer.type=basic
本文档其余部分的示例均使用 MyBasicMetadataAuthorizer 或 MyBasicLDAPAuthorizer 作为授权器名称。
用于 Druid 元数据存储用户授权的属性
druid.auth.authorizer.MyBasicMetadataAuthorizer.enableCacheNotifications
如果为 true,当此授权器的配置发生变化时,Coordinator 将通知 Druid 进程,从而允许它们立即更新状态而无需等待轮询。
必需:否
默认值:true
druid.auth.authorizer.MyBasicMetadataAuthorizer.cacheNotificationTimeout
缓存通知的超时时间(以毫秒为单位)。
必需:否
默认值: 5000
druid.auth.authorizer.MyBasicMetadataAuthorizer.initialAdminUser
初始管理员用户。如果指定了 initialAdminRole 属性,则为其分配该角色;否则,将分配默认管理员角色。
必需:否
默认值:admin
druid.auth.authorizer.MyBasicMetadataAuthorizer.initialAdminRole
如果初始管理员角色不存在,则创建该角色。
必需:否
默认值:admin
druid.auth.authorizer.MyBasicMetadataAuthorizer.roleProvider.type
用于授权请求凭据的角色提供程序类型。
必需:否
默认值:metadata
用于 LDAP 用户授权的属性
druid.auth.authorizer.MyBasicLDAPAuthorizer.enableCacheNotifications
如果为 true,当此授权器的配置发生变化时,Coordinator 将通知 Druid 进程,从而允许它们立即更新状态而无需等待轮询。
必需:否
默认值:true
druid.auth.authorizer.MyBasicLDAPAuthorizer.cacheNotificationTimeout
缓存通知的超时时间(以毫秒为单位)。
必需:否
默认值: 5000
druid.auth.authorizer.MyBasicLDAPAuthorizer.initialAdminUser
初始管理员用户。如果指定了 initialAdminRole 属性,则为其分配该角色;否则,将分配默认管理员角色。
必需:否
默认值:admin
druid.auth.authorizer.MyBasicLDAPAuthorizer.initialAdminRole
如果初始管理员角色不存在,则创建该角色。
必需:否
默认值:admin
druid.auth.authorizer.MyBasicLDAPAuthorizer.initialAdminGroupMapping
初始管理员组映射。如果指定了 initialAdminRole 属性,则为其分配该角色;否则,将分配默认管理员角色。此初始管理员组映射的名称将设为 adminGroupMapping。
必需:否
默认值:null
druid.auth.authorizer.MyBasicLDAPAuthorizer.roleProvider.type
用于授权请求凭据的角色提供程序类型(ldap)。
必需:否
默认值:metadata
druid.auth.authorizer.MyBasicLDAPAuthorizer.roleProvider.groupFilters
用于过滤从 LDAP 搜索返回的允许组集的 LDAP 组过滤器数组。过滤器可以以 开头,或以 结尾,以提供配置灵活性,从而限制或过滤 LDAP 授权器可用的允许组集。
必需:否
默认值:null
只读授权器(ReadOnly Authorizer)
只读授权器允许所有 READ 操作,并拒绝所有其他操作(WRITE、DELETE 等)。
配置示例
druid.auth.authenticatorChain=["basic","anonymous"]
# Basic authenticator for internal user
druid.auth.authenticator.basic.type=basic
druid.auth.authenticator.basic.initialAdminPassword=password
druid.auth.authenticator.basic.initialInternalClientPassword=password
druid.auth.authenticator.basic.credentialsValidator.type=metadata
druid.auth.authenticator.basic.authorizerName=BasicAuthorizer
# Anonymous authenticator for external users
druid.auth.authenticator.anonymous.type=anonymous
druid.auth.authenticator.anonymous.identity=defaultUser
druid.auth.authenticator.anonymous.authorizerName=ReadOnlyAuthorizer
# Escalator with Basic auth for internal communications
druid.escalator.type=basic
druid.escalator.internalClientUsername=druid_system
druid.escalator.internalClientPassword=password
druid.escalator.authorizerName=BasicAuthorizer
# Both authorizers
druid.auth.authorizers=["BasicAuthorizer","ReadOnlyAuthorizer"]
# BasicAuthorizer configuration
druid.auth.authorizer.BasicAuthorizer.type=basic
# ReadOnlyAuthorizer configuration
druid.auth.authorizer.ReadOnlyAuthorizer.type=readOnly
通过此配置:
- Druid 内部通信使用基本身份验证 → AllowAll 授权器 → 完全访问权限
- 无身份验证的外部用户 → 匿名身份验证器 → 只读授权器 → 只读访问权限
LDAPS 属性
使用以下属性配置 Druid 的 TLS LDAP 身份验证 (LDAPS)。有关更多信息,请参阅配置 LDAP 身份验证。
druid.auth.basic.ssl.protocol
要使用的 SSL 协议。TLS 版本为 1.2。
必需:是
默认值:tls
druid.auth.basic.ssl.trustStorePath
信任库(trust store)文件的路径。
必需:是
默认值:不适用
druid.auth.basic.ssl.trustStorePassword
访问信任库文件的密码。
必需:是
默认值:不适用
druid.auth.basic.ssl.trustStoreType
信任库文件的格式。对于 Java,该格式为 jks。
必需:否
默认值:jks
druid.auth.basic.ssl.trustStoreAlgorithm
信任管理器用于验证证书链的算法。
必需:否
默认值:不适用
druid.auth.basic.ssl.trustStorePassword
允许访问信任库的密码详细信息。
必需:否
默认值:不适用
LDAPS 配置示例:
druid.auth.basic.ssl.protocol=tls
druid.auth.basic.ssl.trustStorePath=/usr/local/druid-path/certs/truststore.jks
druid.auth.basic.ssl.trustStorePassword=xxxxx
druid.auth.basic.ssl.trustStoreType=jks
druid.auth.basic.ssl.trustStoreAlgorithm=PKIX
您可以将 druid.auth.basic.ssl.trustStorePassword 配置为纯文本密码,也可以将密码设置为环境变量。有关更多信息,请参阅密码提供程序。
用法
Coordinator 安全 API
要使用这些 API,用户需要对名称为 "security" 的 CONFIG 资源类型拥有读/写权限。
身份验证 API
根路径:/druid-ext/basic-security/authentication
每个 API 端点都包含 {authenticatorName},用于指定正在配置的身份验证器实例。
用户/凭据管理
GET(/druid-ext/basic-security/authentication/db/{authenticatorName}/users)
返回所有用户名列表。
GET(/druid-ext/basic-security/authentication/db/{authenticatorName}/users/{userName})
返回名称为 {userName} 的用户的名称和凭据信息。
POST(/druid-ext/basic-security/authentication/db/{authenticatorName}/users/{userName})
创建一个名为 {userName} 的新用户。
DELETE(/druid-ext/basic-security/authentication/db/{authenticatorName}/users/{userName})
删除名称为 {userName} 的用户。
POST(/druid-ext/basic-security/authentication/db/{authenticatorName}/users/{userName}/credentials)
为 {userName} 分配用于 HTTP 基本身份验证的密码。内容:JSON 密码请求对象。
请求体示例:
{
"password": "helloworld"
}
缓存加载状态
GET(/druid-ext/basic-security/authentication/loadStatus)
返回身份验证 Druid 元数据存储的本地缓存的当前加载状态。
授权 API
根路径:/druid-ext/basic-security/authorization
每个 API 端点都包含 {authorizerName},用于指定正在配置的授权器实例。
用户创建/删除
GET(/druid-ext/basic-security/authorization/db/{authorizerName}/users)
返回所有用户名列表。
GET(/druid-ext/basic-security/authorization/db/{authorizerName}/users/{userName})
返回名称为 {userName} 的用户的名称和角色信息。
输出示例:
{
"name": "druid2",
"roles": [
"druidRole"
]
}
此 API 支持以下标志:
?full:响应还将包含当前分配给用户的每个角色的完整信息。
输出示例:
{
"name": "druid2",
"roles": [
{
"name": "druidRole",
"permissions": [
{
"resourceAction": {
"resource": {
"name": "A",
"type": "DATASOURCE"
},
"action": "READ"
},
"resourceNamePattern": "A"
},
{
"resourceAction": {
"resource": {
"name": "C",
"type": "CONFIG"
},
"action": "WRITE"
},
"resourceNamePattern": "C"
}
]
}
]
}
当指定 ?full 时,此 API 的输出格式已弃用,在以后的版本中将更改为同时设置 ?full 和 ?simplifyPermissions 标志时使用的输出格式。
resourceNamePattern 是资源名称正则表达式的编译版本。它是多余的,并且使前端等编辑授权配置的客户端使用此 API 变得复杂,因为该输出中的权限格式与添加到角色时使用的格式不匹配。
?full?simplifyPermissions:当同时设置?full和?simplifyPermissions时,输出中的权限将仅包含resourceAction对象的列表,而不包含多余的resourceNamePattern字段。
{
"name": "druid2",
"roles": [
{
"name": "druidRole",
"users": null,
"permissions": [
{
"resource": {
"name": "A",
"type": "DATASOURCE"
},
"action": "READ"
},
{
"resource": {
"name": "C",
"type": "CONFIG"
},
"action": "WRITE"
}
]
}
]
}
POST(/druid-ext/basic-security/authorization/db/{authorizerName}/users/{userName})
创建一个名为 {userName} 的新用户。
DELETE(/druid-ext/basic-security/authorization/db/{authorizerName}/users/{userName})
删除名称为 {userName} 的用户。
组映射创建/删除
GET(/druid-ext/basic-security/authorization/db/{authorizerName}/groupMappings)
返回所有组映射列表。
GET(/druid-ext/basic-security/authorization/db/{authorizerName}/groupMappings/{groupMappingName})
返回名称为 {groupMappingName} 的组映射的组映射和角色信息。
POST(/druid-ext/basic-security/authorization/db/{authorizerName}/groupMappings/{groupMappingName})
创建一个名为 {groupMappingName} 的新组映射。内容:JSON 组映射对象。请求体示例:
{
"name": "user",
"groupPattern": "CN=aaa,OU=aaa,OU=Groupings,DC=corp,DC=company,DC=com",
"roles": [
"user"
]
}
DELETE(/druid-ext/basic-security/authorization/db/{authorizerName}/groupMappings/{groupMappingName})
删除名为 {groupMappingName} 的组映射。
角色创建/删除
GET(/druid-ext/basic-security/authorization/db/{authorizerName}/roles)
返回所有角色名称列表。
GET(/druid-ext/basic-security/authorization/db/{authorizerName}/roles/{roleName})
返回名为 {roleName} 的角色的名称和权限。
输出示例:
{
"name": "druidRole2",
"permissions": [
{
"resourceAction": {
"resource": {
"name": "E",
"type": "DATASOURCE"
},
"action": "WRITE"
},
"resourceNamePattern": "E"
}
]
}
此 API 的默认输出格式已弃用,在以后的版本中将更改为设置 ?simplifyPermissions 标志时使用的输出格式。resourceNamePattern 是资源名称正则表达式的编译版本。它是多余的,并且使前端等编辑授权配置的客户端使用此 API 变得复杂,因为该输出中的权限格式与添加到角色时使用的格式不匹配。
此 API 支持以下标志:
?full:输出将包含一个额外的users列表,其中包含当前拥有此角色的用户。
{"users":["druid"]}
?simplifyPermissions:输出中的权限将仅包含resourceAction对象的列表,而不包含多余的resourceNamePattern字段。当未指定?full时,users字段将为 null。
输出示例:
{
"name": "druidRole2",
"users": null,
"permissions": [
{
"resource": {
"name": "E",
"type": "DATASOURCE"
},
"action": "WRITE"
}
]
}
POST(/druid-ext/basic-security/authorization/db/{authorizerName}/roles/{roleName})
创建一个名为 {roleName} 的新角色。内容:用户名字符串。
DELETE(/druid-ext/basic-security/authorization/db/{authorizerName}/roles/{roleName})
删除名为 {roleName} 的角色。
角色分配
POST(/druid-ext/basic-security/authorization/db/{authorizerName}/users/{userName}/roles/{roleName})
将角色 {roleName} 分配给用户 {userName}。
DELETE(/druid-ext/basic-security/authorization/db/{authorizerName}/users/{userName}/roles/{roleName})
从用户 {userName} 取消分配角色 {roleName}。
POST(/druid-ext/basic-security/authorization/db/{authorizerName}/groupMappings/{groupMappingName}/roles/{roleName})
将角色 {roleName} 分配给组映射 {groupMappingName}。
DELETE(/druid-ext/basic-security/authorization/db/{authorizerName}/groupMappings/{groupMappingName}/roles/{roleName})
从组映射 {groupMappingName} 取消分配角色 {roleName}。
权限
POST(/druid-ext/basic-security/authorization/db/{authorizerName}/roles/{roleName}/permissions)
设置 {roleName} 的权限。这将替换该角色上之前的一组权限。
内容:JSON 资源-操作对象列表,例如:
[
{
"resource": {
"name": "wiki.*",
"type": "DATASOURCE"
},
"action": "READ"
},
{
"resource": {
"name": "wikiticker",
"type": "DATASOURCE"
},
"action": "WRITE"
}
]
权限定义中资源的 "name" 字段是正则表达式,用于在授权检查期间匹配资源名称。
请参阅定义权限以获取更多详细信息。
缓存加载状态
GET(/druid-ext/basic-security/authorization/loadStatus)
返回授权 Druid 元数据存储的本地缓存的当前加载状态。