PostgreSQL 凭据

在开始之前,你必须具备以下条件:

  • Vault 1.3.1 或更新版本
  • Vault 注入器 0.3.0 或更新版本

设置 Vault

安装 Vault(不需要在 Kubernetes 集群中安装,但应该能够从 Kubernetes 集群内部访问)。Vault 注入器(agent-injector)必须安装到集群中,并配置以注入 sidecar。这可以通过自动完成 Helm 图表 v0.5.0+ 来实现,该图表安装了 Vault 0.12+ 和 Vault 注入器 0.3.0+。下面的示例假设 Vault 安装在 tsb 命名空间中。

有关详细信息,请查看 Vault 文档

helm install --name=vault --set='server.dev.enabled=true' ./vault-helm

为 PostgreSQL 设置数据库秘密引擎

在 Vault 中启用数据库秘密引擎。

vault secrets enable database

预期输出:

Success! Enabled the database secrets engine at: database/

默认情况下,秘密引擎在与引擎同名的路径上启用。要在不同路径上启用秘密引擎,请使用 -path 参数。

使用适当的插件和连接信息配置 Vault。在 connection_url 参数中,将 postgres.tsb.svc:5432/tsb 替换为你的 PostgreSQL 集群的完整 host:port/db_name。只需更改 URL 中的小写 usernamepassword,不要编辑在 URL 中的 {{ }},它用作模板:

vault write database/config/tsb \
    plugin_name=postgresql-database-plugin \
    allowed_roles="pg-role" \
    connection_url="postgresql://{{username}}:{{password}}@postgres.tsb.svc:5432/tsb?sslmode=disable" \
    username="<postgres-username>" \
    password="<postgres-password>"

你可以使用 read 操作来查看配置:

vault read  database/config/tsb
# Key                                   Value
# ---                                   -----
# allowed_roles                         [pg-role]
# connection_details                    map[connection_url:postgresql://{{username}}:{{password}}@postgres.tsb.svc:5432/?sslmode=disable username:postgres]
# plugin_name                           postgresql-database-plugin
# root_credentials_rotate_statements    []

配置一个角色,将 Vault 中的名称映射到 Vault 可以执行以创建数据库凭据的模板化 SQL 语句。
max_ttl 定义了新凭证的有效时间。
default_ttl 定义了租约时间,Vault 注入器将续订租约,直到达到 max_ttl

TTL 值必须与应用程序的数据库连接生命周期配对,以确保在 TTL 到期之前关闭它们。

运行以下命令,确保不要编辑 {{ }} 之间的参数,因为它们被 Vault 用作模板:

vault write database/roles/pg-role \
    db_name=tsb \
    creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
        GRANT ALL ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
    default_ttl="12h" \
    max_ttl="24h"

Success! Data written to: database/roles/pg-role

再次使用 read 操作来验证设置:

vault read  database/roles/pg-role
# Key                      Value
# ---                      -----
# creation_statements      [CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';       GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}";]
# db_name                  tsb
# default_ttl              24h
# max_ttl                  24h
# renew_statements         []
# revocation_statements    []
# rollback_statements      []

现在,通过使用角色名称从 /creds 终端点生成新凭据。这是 Vault 注入器将用于为你的 Kubernetes 应用程序获取凭据的机制:

vault read database/creds/pg-role
Key                Value
---                -----
lease_id           database/creds/pg-role/tUEs8eogkk9KL5erU5rLv7hD
lease_duration     24h
lease_renewable    true
password           A1a-1ZYMcUHKJIJH6rrc
username           v-token-pg-role-KQ4ze3GYi5He0D70tEmo-1587973449

设置 Kubernetes 秘密引擎

配置一个名为 “pg-auth” 的策略。这是一个非常不受限制的策略,但在生产环境中,你应该添加更多的限制。

vault policy write pg-auth - <<EOF
path "database/creds/*" {
    capabilities = ["read"]
}
EOF
Success! Uploaded policy: pg-auth

配置 Vault 以启用对 Kubernetes API 的访问。此示例假设你正在 Vault pod 中使用 kubectl exec 运行命令。如果不是这样,你将需要找到正确的 JWT 令牌、Kubernetes API URL(Vault 将用于连接到 Kubernetes 的 URL)以及 vaultserver 服务帐户的 CA 证书,如 Vault 文档 中所述。

vault auth enable kubernetes
vault write auth/kubernetes/config \
    token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
    kubernetes_host=https://${KUBERNETES_PORT_443_TCP_ADDR}:443 \
    kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

将数据库策略附加到管理命名空间中的服务帐户(在这里是 tsb 命名空间):

vault write auth/kubernetes/role/pg \
    bound

_service_account_names=* \
    bound_service_account_namespaces=tsb \
    policies=pg-auth \
    ttl=24h

要添加更多限制,为每个 ServiceAccount 创建一个角色。对于 PostgreSQL,你将需要为 tsb-iamtsb-spmdefault 服务帐户创建一个角色,因为 TSB API pod 使用 default 服务帐户运行:

vault write auth/kubernetes/role/pg \
    bound_service_account_names=default,tsb-spm,tsb-iam \
    bound_service_account_namespaces=tsb \
    policies=pg-auth \
    ttl=24h

将凭据注入到 Pod

要在管理平面中使用 Vault Agent 注入器与 PostgreSQL 结合使用,请向 ManagementPlane 自定义资源中的部署 pod 注释和环境变量中添加以下内容。

使用覆盖层来即时重新配置部署:

spec:
  dataStore:
    postgres:
      connectionLifetime: 1h # 设置连接生存期
  components:
    apiServer:
      kubeSpec:
        deployment:
          podAnnotations:
            vault.hashicorp.com/agent-inject: 'true'
            vault.hashicorp.com/agent-init-first: 'true'
            vault.hashicorp.com/agent-inject-secret-config.yaml: 'database/creds/pg-role'
            vault.hashicorp.com/agent-inject-template-config.yaml: |
              {{- with secret "database/creds/pg-role" -}}
              data:
                username: {{ .Data.username }}
                password: {{ .Data.password }}
              {{- end -}}              
            vault.hashicorp.com/role: 'pg'
            vault.hashicorp.com/secret-volume-path: /etc/dbvault
        overlays:
        - apiVersion: v1
          kind: Deployment
          name: tsb
          patches:
          - path: spec.template.spec.containers[name:tsb].args.[:/etc/db/config\.yaml]
            value: /etc/dbvault/config.yaml
          - path: spec.template.spec.initContainers[name:migration].args.[:/etc/db/config\.yaml]
            value: /etc/dbvault/config.yaml
    iamServer:
      kubeSpec:
        deployment:
          podAnnotations:
            vault.hashicorp.com/agent-inject: 'true'
            vault.hashicorp.com/agent-init-first: 'true'
            vault.hashicorp.com/agent-inject-secret-config.yaml: 'database/creds/pg-role'
            vault.hashicorp.com/agent-inject-template-config.yaml: |
              {{- with secret "database/creds/pg-role" -}}
              data:
                username: {{ .Data.username }}
                password: {{ .Data.password }}
              {{- end -}}              
            vault.hashicorp.com/role: 'pg'
            vault.hashicorp.com/secret-volume-path: /etc/dbvault
        overlays:
        - apiVersion: v1
          kind: Deployment
          name: iam
          patches:
          - path: spec.template.spec.containers[name:iam].args.[:/etc/db/config\.yaml]
            value: /etc/dbvault/config.yaml
    spmServer:
      kubeSpec:
        deployment:
          podAnnotations:
            vault.hashicorp.com/agent-inject: 'true'
            vault.hashicorp.com/agent-init-first: 'true'
            vault.hashicorp.com/agent-inject-secret-config.yaml: 'database/creds/pg-role'
            vault.hashicorp.com/agent-inject-template-config.yaml: |
              {{- with secret "database/creds/pg-role" -}}
              data:
                username: {{ .Data.username }}
                password: {{ .Data.password }}
              {{- end -}}              
            vault.hashicorp.com/role: 'pg'
            vault.hashicorp.com/secret-volume-path: /etc/dbvault
        job:
          podAnnotations:
            vault.hashicorp.com/agent-inject: 'true'
            vault.hashicorp.com/agent-init-first: 'true'
            vault.hashicorp.com/agent-inject-secret-config.yaml: 'database/creds/pg-role'
            vault.hashicorp.com/agent-pre-populate-only: "true"
            vault.hashicorp.com/agent-inject-template-config.yaml: |
              {{- with secret "database/creds/pg-role" -}}
                data:
                  username: {{ .Data.username }}
                  password: {{ .Data.password }}
              {{- end -}}              
            vault.hashicorp.com/role: 'pg'
            vault.hashicorp.com/secret-volume-path: /etc/dbvault
        overlays:
        - apiVersion: v1
          kind: Deployment
          name: spm
          patches:
          - path: spec.template.spec.containers[name:spm].args.[:/etc/db/config\.yaml]
            value: /etc/dbvault/config.yaml
        - apiVersion: v1
          kind: CronJob
          name: spmsync
          patches:
          - path: spec.jobTemplate.spec.template.spec.containers[name:spmsync].args.[:/etc/db/config\.yaml]
            value: /etc/dbvault/config.yaml

调试

检查 PostgreSQL 中的角色

使用 PostgreSQL 命令行客户端 psql 来检查目标数据库 tsb 中的角色创建:

psql -h postgres -p 5432 -U tsb -d tsb

连接到数据库后,你可以使用 \du 命令列出数据库的当前角色:

\du
 
                                                                                 List of roles
                     Role name                      |                         Attributes                         |                          Member of
----------------------------------------------------+------------------------------------------------------------+-------------------------------------------------------------
 rds_ad                                             | Cannot login                                               | {}
 rds_iam                                            | Cannot login                                               | {}
 rds_password                                       | Cannot login                                               | {}
 rds_replication                                    | Cannot login                                               | {}
 rds_superuser                                      | Cannot login                                               | {pg_monitor,pg_signal_backend,rds_replication,rds_password}
 rdsadmin                                           | Superuser, Create role, Create DB, Replication, Bypass RLS+| {}
                                                    | Password valid until infinity                              |
 rdsrepladmin                                       | No inheritance, Cannot login, Replication                  | {}
 tsb                                                | Create role, Create DB                                    +| {rds_superuser}
                                                    | Password valid until infinity                              |
                                                    |                                                            | {}
 v-kubernet-pg-role-5OUfsUQv3xAASWZkbECV-1589890098 | Password valid until 2020-05-20 12:08:23+00                | {}
 v-kubernet-pg-role-7uiTkWgsxphogXub0qpp-1589887199 | Password valid until 2020-05-20 11:20:04+00                | {}
...

你可以在这里看到角色 tsb,该角色用于在 Vault 中配置数据库,并且还有一些类似 v-kubernet-pg-role-5OUfsUQv3xAASWZkbECV-1589890098 的角色,这些角色对应于由 Vault 注入器 sidecar 动态创建的角色。

你还可以列出授予动态角色的访问权限。 以下是一个示例,涉及到角色 v-kubernet-pg-role-5OUfsUQv3xAASWZkbECV-1589890098 的权限示例:

SELECT grantee AS user, CONCAT(table_schema, '.', table_name) AS table,
   CASE
       WHEN COUNT(privilege_type) = 7 THEN 'ALL'
       ELSE ARRAY_TO_STRING(ARRAY_AGG(privilege_type), ', ')
   END AS grants
FROM information_schema.role_table_grants
WHERE grantee='v-kubernet-pg-role-5OUfsUQv3xAASWZkbECV-1589890098'
GROUP BY table_name, table_schema, grantee;
 
                       user                        |         table          | grants
----------------------------------------------------+------------------------+--------
v-kubernet-pg-role-5OUfsUQv3xAASWZkbECV-1589890098 | public.application     | ALL
v-kubernet-pg-role-5OUfsUQv3xAASWZkbECV-1589890098 | public.assignment      | ALL
v-kubernet-pg-role-5OUfsUQv3xAASWZkbECV-1589890098 | public.association     | ALL
...