安全
编辑安全编辑
Kibana 通常能够对核心和插件开发者透明地实现安全性,并且在很大程度上仍然如此。Kibana 基于 Elasticsearch Cluster
提供的两种方法:callWithRequest
和 callWithInternalUser
。
callWithRequest
使用 Kibana 最终用户的身份验证凭据对 Elasticsearch 执行请求。因此,如果您在使用 callWithRequest
时以用户 foo
登录 Kibana,则 Kibana 会以用户 foo
的身份对 Elasticsearch 执行请求。过去,callWithRequest
已被广泛用于执行由 Kibana 最终用户发起的操作。
callWithInternalUser
使用内部 Kibana 服务器用户对 Elasticsearch 执行请求,并且过去一直用于执行不是由 Kibana 最终用户发起的操作;例如,创建初始 .kibana
索引或对 Elasticsearch 执行运行状况检查。
但是,随着基于角色的访问控制 (RBAC) 引入的更改,这不再是简单明了的事情。Kibana 现在要求对 .kibana
索引的所有访问都必须通过 SavedObjectsClient
进行。这曾经是一个最佳实践,因为 SavedObjectsClient
负责在 Elasticsearch 中存储的文档与已保存对象之间进行转换,但 RBAC 现在正在利用这种抽象来实现访问控制并确定何时使用 callWithRequest
与 callWithInternalUser
。
基于角色的访问控制编辑
Kibana 中的基于角色的访问控制 (RBAC) 依赖于 Elasticsearch 公开的应用程序权限。这允许 Kibana 定义 Kibana 希望授予用户的权限,使用角色将它们分配给相关用户,然后授权用户执行特定操作。这在 SavedObjectsClient
的安全实例中处理,并在使用 request.getSavedObjectsClient()
或 savedObjects.getScopedSavedObjectsClient()
时对消费者透明地可用。
Kibana 权限编辑
当 Kibana 首次启动时,它会对 Elasticsearch 执行以下 POST
请求。这会将权限的定义与稍后用于授权用户的各种 操作
同步
POST /_security/privilege Content-Type: application/json Authorization: Basic {kib} changeme { "kibana-.kibana":{ "all":{ "application":"kibana-.kibana", "name":"all", "actions":[ "version:7.0.0-alpha1-SNAPSHOT", "action:login", "action:*" ], "metadata":{} }, "read":{ "application":"kibana-.kibana", "name":"read", "actions":[ "version:7.0.0-alpha1-SNAPSHOT", "action:login", "saved_object:dashboard/get", "saved_object:dashboard/bulk_get", "saved_object:dashboard/find", ... ],"metadata":{}} } }
应用程序是通过将 kibana-
的前缀与 kibana.yml
中 kibana.index
的值连接起来创建的,因此不同的 Kibana 租户彼此隔离。
分配 Kibana 权限编辑
Kibana 权限使用 applications
元素分配给特定角色。例如,以下角色将 *
资源
(将来将用于保护空间)的所有权限分配给默认的 Kibana 应用程序
"new_kibana_user": { "applications": [ { "application": "kibana-.kibana", "privileges": [ "all" ], "resources": [ "*" ] } ] }
授予Kibana 权限的角色应使用Kibana 角色管理 API或管理 → 安全 → 角色页面进行管理,而不是直接使用 Elasticsearch 角色管理 API。然后可以使用 Elasticsearch 用户管理 API将此角色分配给用户。
授权编辑
Elasticsearch has privileges API 确定用户是否有权执行特定操作
POST /_security/user/_has_privileges Content-Type: application/json Authorization: Basic foo_read_only_user password { "applications":[ { "application":"kibana-.kibana", "resources":["*"], "privileges":[ "saved_object:dashboard/save", ] } ] }
Elasticsearch 检查用户是否被授予了特定操作的权限。如果用户被分配了一个授予权限的角色,Elasticsearch 会使用Kibana 权限定义将其与操作相关联,这使得以编程方式授权用户更加直观和灵活。
一旦我们授权用户执行特定操作,我们就可以使用 callWithInternalUser
执行请求。
插件功能注册编辑
如果您的插件将与 Kibana 的默认发行版一起使用,那么您就可以注册您的插件提供的功能。功能通常是 Kibana 中的应用程序;注册后,您就可以通过 Spaces 切换它们,并在启用安全功能时通过 Roles 保护它们。
UI 功能编辑
注册功能还可以让您的插件访问“UI 功能”。这些功能是布尔标志,您可以使用它们根据当前用户的权限有条件地呈现您的界面。例如,如果当前用户未经授权,您可以隐藏或禁用“保存”按钮。
注册功能编辑
功能注册由内置的 features
插件控制。要注册功能,请从插件的 setup
生命周期函数调用 features
的 registerKibanaFeature
函数,并提供相应的详细信息
setup(core, { features }) { features.registerKibanaFeature({ // feature details here. }); }
功能详细信息编辑
注册功能包含以下字段。有关更多信息,请参阅功能注册表接口。
字段名称 | 数据类型 | 示例 | 描述 |
---|---|---|---|
|
|
|
功能的唯一标识符。通常,插件的 ID 就足够了。 |
|
|
|
功能的可读名称。 |
|
|
最能代表您功能的 |
|
|
|
|
此功能启用的应用程序数组。通常,您的插件的所有应用程序(来自 |
|
此功能正常运行所需的一组权限。 |
||
|
请参阅示例 3 |
一组子功能,可实现比 |
使用 UI 功能编辑
UI 功能可用于您的公共(客户端)插件代码。这些功能是只读的,用于通知 UI。此对象由功能 ID 命名空间。例如,如果您的功能 ID 是“foo”,则您的 UI 功能存储在 uiCapabilities.foo
中。可以从 core.application
服务的插件的 start
生命周期访问功能
public start(core) { const { capabilities } = core.application; const canUserSave = capabilities.foo.save; if (canUserSave) { // show save button } }
示例 1:Canvas 应用程序编辑
public setup(core, { features }) { features.registerKibanaFeature({ id: 'canvas', name: 'Canvas', category: DEFAULT_APP_CATEGORIES.kibana, app: ['canvas', 'kibana'], catalogue: ['canvas'], privileges: { all: { savedObject: { all: ['canvas-workpad'], read: ['index-pattern'], }, ui: ['save'], }, read: { savedObject: { all: [], read: ['index-pattern', 'canvas-workpad'], }, ui: [], }, }, }); }
这显示了 Canvas 应用程序如何将自身注册为 Kibana 功能。请注意,它为每个权限指定了不同的 savedObject
访问级别
- 具有读/写访问权限(
all
权限)的用户需要能够读/写canvas-workpad
已保存对象,并且他们需要对index-pattern
已保存对象的只读访问权限。 - 具有只读访问权限(
read
权限)的用户不需要对任何已保存对象具有读/写访问权限,而是获得对index-pattern
和canvas-workpad
已保存对象的只读访问权限。
此外,Canvas 还注册了 canvas
UI 应用程序和 canvas
目录条目。这告诉 Kibana 这些实体可供具有 read
或 all
权限的用户使用。
all
权限定义了一个“保存”UI 功能。要在 UI 中访问此功能,Canvas 可以
public start(core) { const { capabilities } = core.application; const canUserSave = capabilities.canvas.save; if (canUserSave) { // show save button } }
由于 read
权限未定义 save
功能,因此具有只读访问权限的用户将会将其 uiCapabilities.canvas.save
标志设置为 false
。
示例 2:开发工具编辑
public setup(core, { features }) { features.registerKibanaFeature({ id: 'dev_tools', name: i18n.translate('xpack.features.devToolsFeatureName', { defaultMessage: 'Dev Tools', }), category: DEFAULT_APP_CATEGORIES.management, app: ['kibana'], catalogue: ['console', 'searchprofiler', 'grokdebugger'], privileges: { all: { api: ['console'], savedObject: { all: [], read: [], }, ui: ['show'], }, read: { api: ['console'], savedObject: { all: [], read: [], }, ui: ['show'], }, }, privilegesTooltip: i18n.translate('xpack.features.devToolsPrivilegesTooltip', { defaultMessage: 'User should also be granted the appropriate {es} cluster and index privileges', }), }); }
与 Canvas 示例不同,开发工具不需要访问任何已保存的对象即可运行。但是,开发工具确实指定了一个 API 端点。配置此项后,安全插件将自动授权访问任何标记为 access:console
的服务器 API 路由,类似于以下内容
server.route({ path: '/api/console/proxy', method: 'POST', config: { tags: ['access:console'], handler: async (req, h) => { // ... } } });
示例 3:Discover编辑
Discover 利用子功能权限来实现细粒度的访问控制。在此示例中,定义了两个子功能权限:“创建短链接”和“生成 PDF 报告”。这些权限允许用户授予对此功能的访问权限,而无需授予对 Discover 的 all
权限。换句话说,您可以授予对 Discover 的 read
访问权限,还可以授予创建短链接或生成 PDF 报告的权限。
请注意,“生成 PDF 报告”子功能权限还有一个附加的 minimumPrivilege
选项。仅当满足许可证要求时,Kibana 才会提供此子功能权限。
public setup(core, { features }) { features.registerKibanaFeature({ { id: 'discover', name: i18n.translate('xpack.features.discoverFeatureName', { defaultMessage: 'Discover', }), order: 100, category: DEFAULT_APP_CATEGORIES.kibana, app: ['kibana'], catalogue: ['discover'], privileges: { all: { app: ['kibana'], catalogue: ['discover'], savedObject: { all: ['search', 'query'], read: ['index-pattern'], }, ui: ['show', 'save', 'saveQuery'], }, read: { app: ['kibana'], catalogue: ['discover'], savedObject: { all: [], read: ['index-pattern', 'search', 'query'], }, ui: ['show'], }, }, subFeatures: [ { name: i18n.translate('xpack.features.ossFeatures.discoverShortUrlSubFeatureName', { defaultMessage: 'Short URLs', }), privilegeGroups: [ { groupType: 'independent', privileges: [ { id: 'url_create', name: i18n.translate( 'xpack.features.ossFeatures.discoverCreateShortUrlPrivilegeName', { defaultMessage: 'Create Short URLs', } ), includeIn: 'all', savedObject: { all: ['url'], read: [], }, ui: ['createShortUrl'], }, ], }, { groupType: 'independent', privileges: [ { id: 'pdf_generate', name: i18n.translate( 'xpack.features.ossFeatures.discoverGeneratePDFReportsPrivilegeName', { defaultMessage: 'Generate PDF Reports', } ), minimumLicense: 'platinum', includeIn: 'all', savedObject: { all: [], read: [], }, api: ['generatePDFReports'], ui: ['generatePDFReports'], }, ], }, ], }, ], } }); }