加载中

安全

Kibana 通常能够对核心和插件开发者透明地实现安全性,并且在很大程度上仍然是这样。Kibana 利用 Elasticsearch 提供的两种方法:callWithRequestcallWithInternalUser

callWithRequest 使用 Kibana 终端用户的身份验证凭据对 Elasticsearch 执行请求。因此,如果使用 `callWithRequest` 时,您使用用户 `foo` 登录 Kibana,Kibana 将以用户 `foo` 的身份对 Elasticsearch 执行请求。从历史上看,`callWithRequest` 已被广泛用于执行由 Kibana 终端用户发起的请求。

callWithInternalUser 使用 Kibana 内部服务器用户对 Elasticsearch 执行请求,并且历史上一直用于执行非由 Kibana 终端用户发起的操作;例如,创建初始的 `.kibana` 索引或对 Elasticsearch 执行健康检查。

但是,随着基于角色的访问控制 (RBAC) 的引入,情况不再是这样简单了。Kibana 现在要求所有对 `.kibana` 索引的访问都通过 `SavedObjectsClient`。这曾经是一个最佳实践,因为 `SavedObjectsClient` 负责在 Elasticsearch 中存储的文档与 Saved Objects 之间进行转换,但 RBAC 现在利用此抽象来实现访问控制,并确定何时使用 `callWithRequest` 而不是 `callWithInternalUser`。

Kibana 中的基于角色的访问控制 (RBAC) 依赖于 Elasticsearch 公开的应用程序权限。这允许 Kibana 定义 Kibana 希望授予用户的权限,使用角色将它们分配给相关用户,然后授权用户执行特定操作。这在一个安全的 `SavedObjectsClient` 实例中处理,并且在使用 `request.getSavedObjectsClient()` 或 `savedObjects.getScopedSavedObjectsClient()` 时对使用者透明可用。

当 Kibana 首次启动时,它会对 Elasticsearch 执行以下 POST 请求。这会将权限定义与各种 actions 同步,后者稍后用于授权用户。

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 权限使用 `applications` 元素分配给特定角色。例如,以下角色将默认 Kibana application 的 `*` resources(将来将用于保护 Spaces)上的所有权限授予默认 Kibana application

"new_kibana_user": {
   "applications": [
     {
       "application": "kibana-.kibana",
       "privileges": [
         "all"
       ],
       "resources": [
         "*"
       ]
     }
   ]
 }

授予Kibana 权限的角色应使用角色 API 或 **Management → Security → Roles** 页面进行管理,而不是直接使用 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 功能”。这些功能是布尔标志,您可以使用它们根据当前用户的权限有条件地渲染您的界面。例如,如果当前用户未授权,您可以隐藏或禁用“保存”按钮。

功能注册由内置的 `features` 插件控制。要注册一个功能,请在插件的 `setup` 生命周期函数中调用 `features` 的 `registerKibanaFeature` 函数,并提供适当的详细信息。

setup(core, { features }) {
  features.registerKibanaFeature({
    // feature details here.
  });
}

注册一个功能包括以下字段。有关更多信息,请参阅功能注册接口

字段名称 数据类型 示例 描述
id (必需)
string
"sample_feature"
功能的唯一标识符。通常,插件的 ID 就足够了。
name (必需)
string
"Sample Feature"
功能的易读名称。
category (必需)
AppCategory
DEFAULT_APP_CATEGORIES.kibana
最能代表您功能的 AppCategory。用于在管理屏幕中组织功能的显示。
app (必需)
string[]
["sample_app", "kibana"]
此功能启用的应用程序数组。通常,您插件的所有应用(来自 uiExports)都将包含在此处。
privileges (必需)
KibanaFeatureConfig.
请参阅示例 1示例 2
此功能运行所需的一组权限。
subFeatures (可选)
KibanaFeatureConfig.
请参阅示例 3
一组子功能,可提供比 allread 功能权限更精细化的访问控制。这些选项仅在 Gold 订阅级别及以上可用。
scope (可选)
string[]
["spaces", "security"]
默认 security。Scope 确定功能是仅出现在 Security Feature Privileges 中,还是同时出现在 Spaces Visibility Toggles 和 Security Feature Privileges 中。

功能注册的 privileges 部分允许插件为其应用程序实现读/写模式和只读模式。

有关字段和选项的完整说明,请参阅功能注册接口

UI 功能可用于您的公共(客户端)插件代码。这些功能是只读的,用于通知 UI。此对象按功能 ID 命名空间。例如,如果您的功能 ID 是“foo”,则您的 UI 功能存储在 uiCapabilities.foo。可以从插件的 start 生命周期中的 core.application 服务访问功能。

public start(core) {
  const { capabilities } = core.application;

  const canUserSave = capabilities.foo.save;
  if (canUserSave) {
    // show save button
  }
}
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-patterncanvas-workpad 保存的对象具有只读访问权限。

此外,Canvas 还注册了 canvas UI 应用和 canvas 目录条目。这告诉 Kibana,这些实体可供具有 readall 权限的用户使用。

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

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 示例不同,Dev Tools 不需要访问任何保存的对象即可运行。但是,Dev Tools 会指定一个 API 端点。配置此项后,Security 插件将自动授权访问任何标记为 access:console 的服务器 API 路由,如下所示:

server.route({
 path: '/api/console/proxy',
 method: 'POST',
 config: {
   tags: ['access:console'],
   handler: async (req, h) => {
     // ...
   }
 }
});

Discover 利用子功能权限来实现细粒度的访问控制。在此示例中,定义了两个子功能权限:“创建短 URL”和“生成 PDF 报告”。这允许用户授予对此功能的访问权限,而无需授予 Discover 的 all 权限。换句话说,您可以授予 Discover read 访问权限,并同时授予创建短 URL 或生成 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'],
                },
              ],
            },
          ],
        },
      ],
    }
  });
}
© . This site is unofficial and not affiliated with Elasticsearch BV.