身份:实体与组

Vault 支持多种身份验证方法,还允许在不同的挂载路径上启用相同类型的身份验证方法。每个 Vault 客户端可能有多个帐户,这些帐户具有在 Vault 服务器上启用的各种身份提供者。

Vault 客户端可以映射为实体,并且它们与身份验证提供程序的对应帐户可以映射为别名。本质上,每个实体都由零个或多个别名组成。Vault 内部使用身份机密引擎维护 Vault 识别的客户端。

举例来说,Bob 在 Github 和 LDAP 中都有帐户。 Github 和 LDAP 身份验证方法都在 Vault 服务器上启用,他可以使用他的任一帐户进行身份验证。虽然两个账户都属于 Bob,但是两个账户之间并没有关联来设置一些共同的属性。

解决方案

创建一个代表 Bob 的实体,并将代表他的每个帐户的别名关联为实体成员。我们可以在实体级别设置其他策略和元数据,以便两个帐户都可以继承。

当 Bob 使用他的任一帐户进行身份验证时,实体标识符将与经过身份验证的令牌相关联。当使用此类令牌时,它们的实体标识符会被审计记录,标记特定用户执行的操作的踪迹。

准备工作

要执行本教程的实验,我们需要:

  1. 一个已经初始化并解封的 Vault 服务器
  2. 安装 jq

启动一个 dev 服务

  1. 在命令行终端中,使用 root 作为根令牌启动一个 Vault dev 服务:
$ vault server -dev -dev-root-token-id root

Vault dev 服务默认运行于 127.0.0.1:8200。该服务启动后已被初始化并解封。

  1. 开启一个新的终端,使用环境变量设置 Vault 命令行使用的 Vaul 服务地址:
$ export VAULT_ADDR=http://127.0.0.1:8200
  1. 使用环境变量设置 Vault 命令行使用的 Vaul 根令牌:
$ export VAULT_TOKEN=root

步骤一:创建一个带别名的实体

我们将创建一个分配了基本策略的新实体。该实体定义了两个实体别名,每个别名都分配了不同的策略。

场景:一个 ACME Inc. 的用户 Bob Smith 碰巧有两组凭据:bobbsmith。 Bob 可以使用他的任一帐户向 Vault 进行身份验证。要管理用户的帐户并将其链接到 QA 团队中的身份 Bob Smith,您将为 Bob 创建一个实体。

实验场景
图 1.10.8/1 - 实验场景

请注意,为简化本教程,我们将使用 userpass 身份验证方法。在实际场景中,用户 bob 可能是一个存在于活动目录中的用户名,而 bsmith 可能是 Bob 在 GitHub 的用户名。为了模拟该行为,本教程中将在两个独立路径上启用 userpass 身份验证方法:userpass-test 以及 userpass-qa,来模拟两种不同的身份验证方法。

场景策略

base.hcl:

path "secret/data/training_*" {
   capabilities = ["create", "read"]
}

test.hcl:

path "secret/data/test" {
   capabilities = [ "create", "read", "update", "delete" ]
}

team-qa.hcl:

path "secret/data/team-qa" {
   capabilities = [ "create", "read", "update", "delete" ]
}

请注意该场景假设已在 secret 路径上启用了 K/V v2 机密引擎。如果不了解 K/V 机密引擎,请先阅读相关文档

现在,让我们使用合适的权限来创建 bobbsmith 用户:

  1. 创建 base 策略:
$ vault policy write base -<<EOF 
path "secret/data/training_*" {
   capabilities = ["create", "read"]
}
EOF
  1. 创建 test 策略:
$ vault policy write test -<<EOF 
path "secret/data/test" {
   capabilities = [ "create", "read", "update", "delete" ]
}
EOF
  1. 创建 team-qa 策略:
$ vault policy write team-qa -<<EOF 
path "secret/data/team-qa" {
   capabilities = [ "create", "read", "update", "delete" ]
}
EOF
  1. 列出所有策略,确认 basetest 以及 team-qa 策略已就绪:
$ vault policy list
base
default
team-qa
test
root
  1. userpass-test 路径上启用 userpass 身份验证方法:
$ vault auth enable -path="userpass-test" userpass
  1. userpass-test 上创建一个名为 bob 的新用户,密码为 training,附加 test 策略:
$ vault write auth/userpass-test/users/bob password="training" policies="test"
  1. 在另一个路径 userpass-qa 上启用 userpass 身份验证方法:
$ vault auth enable -path="userpass-qa" userpass
  1. userpass-qa 上创建一个名为 bsmith 的新用户,密码为 training,附加 team-qa 策略:
$ vault write auth/userpass-qa/users/bsmith password="training" policies="team-qa"
  1. 执行以下命令获取 userpass 身份验证方法挂载点的访问器:
$ vault auth list -detailed

Path              Type        Accessor                    ...
----              ----        --------                    ...
token/            token       auth_token_c5943123         ...
userpass-qa/      userpass    auth_userpass_8c7b8e0f      ...
userpass-test/    userpass    auth_userpass_264d4705      ...
...

每一个 userpass 身份验证方法都有一个唯一的 Accessor 值作为标志符。

  1. 运行以下命令将 userpass-test 身份验证方法的访问器保存在名为 access_test.txt 的文件里:
$ vault auth list -format=json | jq -r '.["userpass-test/"].accessor' > accessor_test.txt
  1. 类似的,运行以下命令将 userpass-qa 身份验证方法的访问器保存在名为 access_qa.txt 的文件里:
$ vault auth list -format=json | jq -r '.["userpass-qa/"].accessor' > accessor_qa.txt
  1. 创建名为 bob-smith 的实体,将返回的实体 ID 保存在名为 entity_id.txt 的文件内:
$ vault write -format=json identity/entity name="bob-smith" policies="base" \
     metadata=organization="ACME Inc." \
     metadata=team="QA" \
     | jq -r ".data.id" > entity_id.txt
  1. 现在,通过创建一个实体别名来将用户 bob 添加到实体 bob-smith 中。在名为 bob 的实体的别名上设置自定义元数据“account”,并将其值设置为“Tester Account”:
$ vault write identity/entity-alias name="bob" \
     canonical_id=$(cat entity_id.txt) \
     mount_accessor=$(cat accessor_test.txt) \
     custom_metadata=account="Tester Account"

请注意:要在实体别名上设置自定义元数据,需要运行 Vault 1.9 或更高版本。如果我们的 Vault 版本低于 v1.9,那么执行上述命令时请不要添加 custom_metadata=account="Tester Account"

输出样例:

Key             Value
---             -----
canonical_id    24204b50-22a6-61f5-bd4b-803f1a4e4726
id              ae2cdd0f-9807-7336-2265-5575c71837e7
  1. 重复以上步骤,通过创建一个实体别名来将用户 bsmith 添加到实体 bob-smith 中。在名为 bob 的实体的别名上设置自定义元数据“account”,并将其值设置为“QA Eng Account”:
$ vault write identity/entity-alias name="bsmith" \
     canonical_id=$(cat entity_id.txt) \
     mount_accessor=$(cat accessor_qa.txt) \
     custom_metadata=account="QA Eng Account"

输出样例:

Key             Value
---             -----
canonical_id    24204b50-22a6-61f5-bd4b-803f1a4e4726
id              6066f6af-bb1c-5310-58a1-fd9c8f151573
  1. 审查实体明细:
$ vault read -format=json identity/entity/id/$(cat entity_id.txt) | jq -r ".data"

样例输出:输出应包括实体别名、元数据(组织和团队)和基本策略:

{
  "aliases": [
    {
      "canonical_id": "73503625-abcd-db22-08c3-c121d682d550",
      "creation_time": "2021-11-17T05:33:48.040506Z",
      "custom_metadata": {
        "account": "Tester Account"
      },
      "id": "cf073e2e-41af-852f-848d-f67533c8a610",
      "last_update_time": "2021-11-17T05:33:48.040506Z",
      "local": false,
      "merged_from_canonical_ids": null,
      "metadata": null,
      "mount_accessor": "auth_userpass_0a6936a7",
      "mount_path": "auth/userpass-test/",
      "mount_type": "userpass",
      "name": "bob"
    },
    {
      "canonical_id": "73503625-abcd-db22-08c3-c121d682d550",
      "creation_time": "2021-11-17T05:33:48.107834Z",
      "custom_metadata": {
        "account": "QA Eng Account"
      },
      "id": "7add6763-ce53-d92a-c795-c8ae529ce6e7",
      "last_update_time": "2021-11-17T05:33:48.107834Z",
      "local": false,
      "merged_from_canonical_ids": null,
      "metadata": null,
      "mount_accessor": "auth_userpass_ef4f8068",
      "mount_path": "auth/userpass-qa/",
      "mount_type": "userpass",
      "name": "bsmith"
    }
  ],
  "creation_time": "2021-11-17T05:33:47.966585Z",
  "direct_group_ids": [
    "49e8b9e8-8933-1e14-f05c-e1c9674b142b"
  ],
  "disabled": false,
  "group_ids": [
    "49e8b9e8-8933-1e14-f05c-e1c9674b142b"
  ],
  "id": "73503625-abcd-db22-08c3-c121d682d550",
  "inherited_group_ids": [],
  "last_update_time": "2021-11-17T05:33:47.966585Z",
  "merged_entity_ids": null,
  "metadata": {
    "organization": "ACME Inc.",
    "team": "QA"
  },
  "mfa_secrets": {},
  "name": "bob-smith",
  "namespace_id": "root",
  "policies": [
    "base"
  ]
}

安全注意事项:避免在实体元数据中存储任何敏感的个人身份信息 (PII)。如果配置了性能复制,实体元数据将复制到其他集群。这可能严重违反 GDPR 规定。 Vault 1.9 引入了在不与 Vault 设置的元数据重叠的每个实体别名上设置自定义元数据的功能。如果身份验证方法是集群本地的,则元数据不会被复制到同一性能复制组中的其他集群。因此,建议改用实体别名上的自定义元数据。

步骤二:测试实体

为了更好地理解令牌如何从实体的策略继承功能,您将通过以 bob 身份登录来测试它。

  1. 首先以 bob 的身份登录,并将生成的客户端令牌保存在 bob_token.txt 文件中:
$ vault login -format=json -method=userpass -path=userpass-test \
    username=bob password=training \
    | jq -r ".auth.client_token" > bob_token.txt
  1. test 策略授予了对 secret/test 路径的 CRUD 操作权限。测试确认我们可以向该路径写入机密:
$ VAULT_TOKEN=$(cat bob_token.txt) vault kv put secret/test owner="bob"

Key                Value
---                -----
created_time       2021-11-06T02:12:02.104146Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1
  1. 虽然用户名 bob 没有附加 base 策略,但它的令牌集成了 base 策略,因为 bobbob-smith 实体的成员之一,而该实体附加了 base 策略。检查 bob 的令牌是否集成了这些权限:
$ VAULT_TOKEN=$(cat bob_token.txt) vault token capabilities secret/data/training_test
create, read
  1. base 策略授予了对 secret/training_* 路径的创建与读取权限;所以 bob 也可以对任意以 secret/training_* 为前缀的路径执行创建以及读取操作。

那么 secret/team-qa 路径呢?

$ VAULT_TOKEN=$(cat bob_token.txt) vault token capabilities secret/data/team-qa
deny

用户 bob 只集成了关联实体的策略。用户只可以通过以 bsmith 的凭据登录才能访问 secret/team-qa 路径。

步骤三:创建一个内部组

请注意,请在执行步骤三的操作前,先使用先前配置实体所使用的令牌重新登录。

现在,我们要创建一个名为 engineers 的内部组,它的成员是我们在步骤一中创建的实体 bob-smith

内部组
图 1.10.8/2 - 内部组

名为 team-eng.hcl 的文件中定义了名为 team-eng 的组策略:

team-eng.hcl:

path "secret/data/team/eng" {
  capabilities = [ "create", "read", "update", "delete"]
}

注意:在继续下面的操作前,请确认环境变量 VAULT_TOKEN 被设置为了 root

  1. 创建名为 team-eng 的新策略:
$ vault policy write team-eng -<<EOF 
path "secret/data/team/eng" {
  capabilities = [ "create", "read", "update", "delete"]
}
EOF
  1. 创建名为 engineers 的内部组,将 bob-smith 实体添加为组成员,并附加 team-eng 策略:
$ vault write identity/group name="engineers" \
     policies="team-eng" \
     member_entity_ids=$(cat entity_id.txt) \
     metadata=team="Engineering" \
     metadata=region="North America"

输出样例:

Key     Value
---     -----
id      0cd76d41-fe36-8c7b-4758-d36bbc212650
name    engineers

现在,当我们用 bob 或是 bsmith 登录时,生成的令牌都继承了组级别的策略 team-eng

总结

默认情况下,Vault 创建内部组。当我们创建一个内部组时,我们可以设置组成员而不是组别名。组别名时 Vault 与外部身份提供者(例如 LDAP、GitHub 等)之间的映射。因此,只有在创建外部组时才定义组别名。对于内部组,我们指定 member_entity_ids 和/或 member_group_ids

步骤四:创建一个外部组

组织通常使用 LDAP、Okta 和 GitHub 等身份验证方法来处理 Vault 用户身份验证,并且在这些身份提供程序中定义个人用户的组成员身份。

为了管理组级别的授权,我们可以创建一个外部组以将 Vault 与外部身份提供者(身份验证提供者)链接起来,并将适当的策略附加到该组。

样例场景

所有属于 Github 组织 example-inctraining 团队的用户都被允许在 secret/education 路径上执行任意操作。

请注意,该场景假设 GitHub 上已经存在了名为 example-inc 的组织以及名为 training 的团队。

education.hcl:

path "secret/data/education" {
  capabilities = [ "create", "read", "update", "delete", "list" ]
}
  1. 创建名为 education 的新策略:
$ vault policy write education -<<EOF 
path "secret/data/education" {
  capabilities = [ "create", "read", "update", "delete", "list" ]
}
EOF
  1. 启用 GitHub 身份验证方法:
$ vault auth enable github
  1. 获取 GitHub 身份验证方法的挂载点访问器,并保存在名为 accessor_github.txt 的文件内:
$ vault auth list -format=json | jq -r '.["github/"].accessor' > accessor_github.txt
  1. 配置指向我们的 GitHub 组织:
$ vault write auth/github/config organization=example-inc
  1. 创建一个外部组,将组 ID 保存至文件 group_id.txt 中:
$ vault write -format=json identity/group name="education" \
     policies="education" \
     type="external" \
     metadata=organization="Product Education" | jq -r ".data.id" > group_id.txt
  1. 创建一个组别名,其中 canonical_id 是组 ID,名称必须是存在的实际 GitHub 团队名称。:
$ vault write identity/group-alias name="training" \
     mount_accessor=$(cat accessor_github.txt) \
     canonical_id="$(cat group_id.txt)"

样例输出:

Key             Value
---             -----
canonical_id    66818a45-ef85-0ff3-6c1e-37faf12ea55e
id              578944f0-dcfd-29fd-a763-d3f9431512d7

results matching ""

    No results matching ""