基于HashiCorp Vault的K8S外部密钥管理实践

引言 (Introduction)

随着云计算和容器化技术的快速发展,企业在构建现代化应用时对安全性和合规性的要求日益提高。然而,在容器化环境中,敏感数据(如 API 密钥、数据库凭据、TLS 证书)的安全管理成为保障系统安全的关键挑战。

HashiCorp Vault 作为业界领先的开源秘密管理工具,提供了集中化、动态化和高安全性的解决方案,能够有效应对这些挑战。其通过动态秘密生成、细粒度访问控制和加密即服务等功能,为 TKE 环境中的外部密钥管理提供了灵活且强大的支持。

本文将结合 Vault 的核心架构与 TKE 的容器化特性,介绍具体的集成方法、配置步骤和最佳实践,旨在帮助企业构建安全、高效的云原生密钥管理体系,满足合规性要求并提升 DevOps 效率。

Vault 介绍

What is Vault ?

Vault 提供集中化的Secret管理、数据加密和访问控制,解决传统硬编码凭据或分散管理带来的安全风险。其主要功能包括:

● Secret管理:安全存储和管理敏感数据,如 API 密钥、数据库密码、证书等,支持动态生成和定期轮换。

● 数据加密:通过加密即服务(Encryption as a Service)保护数据,支持静态数据加密和传输中数据加密。

● 身份认证与访问控制:基于角色和策略的访问控制(RBAC),支持多种身份认证方式(如 LDAP、Kubernetes、JWT 等)。

● 动态Secret

● :为数据库、云服务等生成临时凭据,降低泄露风险。例如,Vault 可以为数据库生成短生命周期的用户名和密码。

● 证书管理:自动生成、轮换和管理 TLS 证书,支持与公共或私有 CA 集成。

● 加密密钥管理:管理加密密钥的生命周期,支持密钥轮换和版本控制。

Why Vault ?

Kubernetes 原生提供了 Secret 对象来管理敏感信息。然而,原生 Secret 存在一些局限性:

● 静态存储: Secret 通常以 Base64 编码存储在 etcd(K8s 的数据存储)中。虽然可以加密 etcd,但这仍然是集群管理员需要额外关注的一个静态存储点。

● 权限管理粒度:RBAC 控制对 Secret 的访问,但配置相对复杂,且 Secret 一旦被 Pod 挂载,其内容对整个 Pod 内的所有容器都是可见的。

● 缺乏与外部密钥管理系统的原生集成: 企业通常使用专门的密钥管理系统(如 HashiCorp Vault、AWS Secrets Manager、Azure Key Vault、Google Secret Manager)来集中、安全地管理密钥。原生 Secret 需要手动或通过外部工具同步这些密钥。

● 密钥轮换: 当外部密钥管理系统中的密钥更新后,需要手动更新 K8s Secret 并重启相关 Pod 才能生效。

Vault 架构

Vault 的架构由以下关键组件构成:

● 核心 (Core) :负责 Vault 的核心逻辑,包括请求路由、认证、授权、审计和密钥管理。请求处理:解析客户端请求,调用认证方法、秘密引擎和策略检查。

● 存储后端 (Storage Backend):Vault 不直接存储数据,而是依赖外部存储后端保存加密的秘密和元数据。数据以加密形式存储,Vault 使用 Master Key(主密钥)进行加密/解密。

● 秘密引擎 (Secrets Engines):模块化组件,负责生成、管理和提供特定类型的秘密。每个秘密引擎独立配置,可按需启用,支持动态秘密生成以降低泄露风险。

● 认证方法 (Auth Methods):用于验证客户端身份,生成访问 Vault 的令牌(Token)。认证后,Vault 分配令牌,关联特定策略以控制访问权限。

● 策略 (Policies):定义客户端的访问权限,使用 HCL(HashiCorp Configuration Language)编写。基于角色的访问控制(RBAC),支持细粒度权限管理。

Vault 后端存储

Overview

特性 Raft Consul S3/GCS/Azure PostgreSQL
存储类型 本地(BoltDB) 分布式键值存储 云对象存储 关系型数据库
HA 支持 是(3-5 节点) 是(云厂商托管) 是(视数据库配置)
运维复杂性 低(内置) 高(需 Consul 集群) 低(云厂商托管) 高(需数据库集群)
性能 高(本地存储) 中(网络依赖) 中(网络依赖) 中(事务开销)
跨集群适用性 高(只需网络访问 Vault) 高(需网络访问 Consul) 中(云厂商绑定) 中(需数据库集群)
成本 低(仅磁盘) 中(Consul 集群资源) 高(云厂商收费) 中(数据库资源)

Integrated Storage (Raft)

Integrated Storage (Raft) 是 Vault 的内置存储后端,官方推荐。基于 Raft 协议实现的一种分布式一致性存储后端,适合中小型生产环境。它通过 Raft 协议和 BoltDB 提供加密存储、高可用性和高性能,无需外部依赖,简化部署和运维。

Integrated Storage 的优势:

● 架构简单:无需外部存储服务,Vault 内置 Raft 逻辑,部署和维护简单。

● 高可用:支持多节点集群(建议 3-5 节点),自动故障转移,提供强一致性读写,适合生产环境。

● 加密存储:所有数据在写入 BoltDB 前加密,使用 Vault 的加密密钥。

● 快照与备份:支持定期快照和手动备份,方便数据迁移和灾难恢复。

● 性能优化:本地存储(BoltDB)减少网络延迟,适合高性能场景。

● 动态扩展:支持动态添加或移除节点,新节点自动同步数据,无需手动干预。

配置样例

ini 复制代码
disable_mlock = true
ui = true
cluster_name = "vault-integrated-storage"
storage "raft" { 
   path    = "/vault/data/"
}# 配置后端存储为raft
listener "tcp" {
   address = "[::]:8200"
   cluster_address = "[::]:8201"
   tls_disable = "true"
}

Vault Secret Engine

Overview

Secret Engine 功能描述 典型用途
Key/Value (KV) 存储静态键值对秘密(如配置、密码),支持版本控制、元数据。 配置文件、API密钥、数据库密码
AWS 动态生成AWS IAM凭据、STS令牌 AWS EC2, S3, Lambda 等
Azure 动态生成Azure服务主体(Service Principal) Azure VM, Key Vault, SQL DB
Database 统一接口:为多种数据库动态生成短期账号/密码 MySQL, PostgreSQL, Oracle, MongoDB 等
PKI 动态签发X.509证书(TLS/SSL) 替代传统CA,支持自动轮换
SSH 生成一次性SSH OTP或签署SSH公钥 安全SSH服务器/客户端访问
Consul 动态生成Consul ACL令牌 安全访问Consul服务发现
LDAP 绑定OpenLDAP或其他LDAP服务管理用户 企业目录服务集成
OIDC 提供OpenID Connect身份提供商(IdP)功能 单点登录(SSO)

key/value

Key/Value 秘密引擎是 Vault 最简单、最通用的秘密存储方式,用于存储和管理任意键值对数据。支持版本控制、软删除和数据轮换,适合需要历史记录和恢复的场景。

使用流程

使用样例

ini 复制代码
# 启用KV v2引擎
vault secrets enable -path=secret kv-v2
# 写入秘密
vault kv put secret/db-config \
  username="admin" \
  password="s3cr3tP@ss"
# 读取最新版本
vault kv get secret/db-config
# 读取特定版本
vault kv get -version=1 secret/db-config
# 列出路径
vault kv list secret/
# 删除版本 (标记删除)
vault kv delete -versions=2 secret/db-config
# 彻底销毁版本
vault kv destroy -versions=2 secret/db-config

database

Database 秘密引擎为数据库(如 MySQL)提供动态凭据管理,Vault 自动生成和管理数据库用户凭据,具有短生命周期和自动轮换功能,增强安全性。

使用流程

使用样例

ini 复制代码
# 启用数据库引擎
vault secrets enable database
# 配置MySQL连接
vault write database/config/mysql-prod \
  plugin_name=mysql-database-plugin \
  connection_url="{{username}}:{{password}}@tcp(10.0.0.5:3306)/" \
  allowed_roles="app-role" \
  username="vault-admin" \
  password="vault-admin-password"
# 创建角色
vault write database/roles/app-role \
  db_name=mysql-prod \
  creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; \
    GRANT SELECT ON app_db.* TO '{{name}}'@'%';" \
  default_ttl="1h" \
  max_ttl="24h"
# 获取动态凭据
vault read database/creds/app-role
# 验证连接
mysql -u v-token-app-role-xyz123 -p'8f4cda6c-12e3-45ef-9b7a' -h 10.0.0.5
# 配置静态根凭据轮换
vault write -force database/rotate-root/mysql-prod
# 查看租约信息
vault lease lookup database/creds/app-role/abcd1234

Kubernetes

Kubernetes Secret Engine 允许 Vault 动态生成 Kubernetes 服务账户(Service Account)的对应token,支持动态生成短生命周期的 Service Account Token(TTL 可配置),可以跨多个 Kubernetes 集群、云平台或其他系统统一管理 Service Account Token 的生成、分配和生命周期。

使用流程

使用样例

  1. 创建 Vault Server 使用的Service Account
yaml 复制代码
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: vault
  namespace: vault
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: k8s-minimal-secrets-abilities
rules:
- apiGroups: [""]
  resources: ["namespaces"]
  verbs: ["get"]
- apiGroups: [""]
  resources: ["serviceaccounts", "serviceaccounts/token"]
  verbs: ["create", "update", "delete"]
- apiGroups: ["rbac.authorization.k8s.io"]
  resources: ["rolebindings", "clusterrolebindings"]
  verbs: ["create", "update", "delete"]
- apiGroups: ["rbac.authorization.k8s.io"]
  resources: ["roles", "clusterroles"]
  verbs: ["bind", "escalate", "create", "update", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: vault-token-creator-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: k8s-minimal-secrets-abilities
subjects:
- kind: ServiceAccount
  name: vault
  namespace: vault
  1. 创建 测试 使用的Service Account
yaml 复制代码
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: test-service-account-with-generated-token
  namespace: test
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: test-role-list-pods
  namespace: test
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: test-role-abilities
  namespace: test
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: test-role-list-pods
subjects:
- kind: ServiceAccount
  name: test-service-account-with-generated-token
  namespace: test
  1. 配置Vault
bash 复制代码
# 启用Kubernetes引擎
vault secrets enable kubernetes
# 创建角色
vault write -f kubernetes/config
vault write kubernetes/roles/my-role allowed_kubernetes_namespaces="*" service_account_name="test-service-account-with-generated-token" token_default_ttl="10m"
# 生成ServiceAccount令牌
vault write kubernetes/creds/my-role kubernetes_namespace=test
# 使用令牌访问K8s API
curl -H "Authorization: Bearer $TOKEN" https://k8s-api:6443/api/v1/pods

Vault AuthN method

Overview

方法名称 认证方式描述 适用场景
Userpass 用户名+密码认证(用户信息存储在Vault内部) 内部用户/开发人员访问
AppRole 机器/服务通过角色ID(Role ID)和密钥ID(Secret ID)认证 CI/CD流水线、自动化服务
GitHub 使用GitHub个人访问令牌(PAT)验证用户/团队身份 开发团队协作场景
AWS 通过AWS IAM角色/实例元数据/Lambda函数认证 AWS EC2, Lambda, IAM用户
Azure 使用Azure AD身份/托管身份(Managed Identity)/服务主体认证 Azure VM, 应用服务, AAD
OIDC 与OpenID Connect提供商(如Okta, Auth0)集成 企业SSO(单点登录)
JWT/OIDC 直接提交JWT令牌认证(可对接外部OIDC提供商) 微服务认证、自定义身份系统集成

approle

AppRole 是一种面向机器或应用程序的认证方法,适合自动化工作流。它通过 RoleID(类似用户名)和 SecretID(类似密码)进行认证。

auth 流程

使用样例

ini 复制代码
# 1. 启用AppRole认证
vault auth enable approle
 
# 2. 创建角色并绑定策略
vault write auth/approle/role/ci-cd-role \
  token_policies="prod-db-access" \
  secret_id_ttl=10m \
  token_num_uses=5
 
# 3. 获取Role ID (静态配置)
vault read auth/approle/role/ci-cd-role/role-id
 
# 4. 生成Secret ID (动态获取)
vault write -f auth/approle/role/ci-cd-role/secret-id
 
# 5. 使用凭证登录
vault write auth/approle/login \
  role_id="db-access-role" \
  secret_id="a1b2c3d4-5678"

Userpass

UserPass 是一种面向人类用户的认证方法,通过用户名和密码对进行认证。它适用于需要人工交互的场景,如管理员或开发人员通过 CLI 或 UI 访问 Vault。

auth 流程

使用样例

ini 复制代码
# 1. 启用Userpass认证
vault auth enable userpass
 
# 2. 创建用户账户
vault write auth/userpass/users/alice \
  password="s3cr3tP@ss!" \
  policies="dev-readonly" \
  ttl="8h"
 
# 3. 用户登录 (CLI)
vault login -method=userpass username=alice password=s3cr3tP@ss!
 
# 4. 用户登录 (API)
curl --request POST \
  --data '{"password": "s3cr3tP@ss!"}' \
  http://127.0.0.1:8200/v1/auth/userpass/login/alice

Use Vault On K8S

Vault agent Injector

GitHub - hashicorp/vault-k8s: First-class support for Vault and Kubernetes.

通过Mutating Webhook拦截Pod创建事件,注入Vault Agent Sidecar容器,Agent负责认证Vault、获取Secret并渲染到共享内存卷。

功能特性

● 支持所有Vault动态Secret(如数据库凭据、PKI证书),通过Vault Agent管理租约。

● 需为每个集群配置独立的Vault认证方法(如Kubernetes认证),多集群管理复杂。

● Secrets存储在共享内存卷(tmpfs)中,作为文件供Pod消费。

安全特性

● 使用Kubernetes Service Account认证

● Secrets存储在内存卷,降低持久化风险

● 支持所有Vault认证方法

● 提供Secret缓存和自动轮换

典型适用场景

● 需要高灵活性,支持多种Vault Secret引擎

● 应用不希望直接依赖Kubernetes Secret

● 需要Secret缓存或复杂模板化

部署架构

使用样例

yaml 复制代码
# webapp.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
  annotations:
    vault.hashicorp.com/agent-inject: "true"              # 启用注入
    vault.hashicorp.com/role: "db-app"                     # Vault 角色名
    vault.hashicorp.com/agent-inject-secret-db-creds: "database/creds/db-role" # Secret路径
spec:
  template:
    spec:
      serviceAccountName: webapp-sa                        # 匹配Vault角色绑定的SA
      containers:
      - name: app
        image: nginx:latest
        volumeMounts:
        - name: vault-secrets
          mountPath: /vault/secrets
      volumes:
      - name: vault-secrets
        emptyDir:
          medium: Memory

Vault Secret operator

GitHub - hashicorp/vault-secrets-operator: The Vault Secrets Operator (VSO) allows Pods to consume Vault secrets natively from Kubernetes Secrets.

使用Kubernetes Operator模式,通过CRD(如VaultStaticSecret)同步Vault Secret到Kubernetes Secret,支持动态Secret和滚动重启。

功能特性

● 支持多集群,通过SecretStore或ClusterSecretStore配置Vault连接,简化多集群管理。

● 支持静态、动态和PKI秘密,自动处理租约续订和轮换,支持滚动重启以更新应用。

● Secrets同步到Kubernetes原生Secret对象,可作为环境变量或文件使用。

安全特性

● 使用Kubernetes Service Account认证

● Secrets存储在etcd,可能需额外加密

● 提供细粒度访问控制和审计

● 支持动态Secret轮换和滚动重启

典型适用场景

● 希望与Kubernetes原生Secret集成

● 需要动态Secret管理和自动轮换

● 适合只需要简单Secret同步的场景

部署架构

使用样例

yaml 复制代码
# vault-connection.yaml
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultConnection
metadata:
  name: prod-vault
spec:
  address: "https://vault.prod:8200" #vault server 地址
 
# vault-auth-role.yaml
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
  name: kubernetes-auth
spec:
  vaultConnectionRef: prod-vault
  method: kubernetes
  mount: kubernetes
  kubernetes:
    role: db-app
    serviceAccount: webapp-sa
# database-secret.yaml
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
  name: db-credentials
spec:
  vaultConnectionRef: prod-vault
  vaultAuthRef: kubernetes-auth
  path: database/creds/db-role
  refreshAfter: "5m"       # 每5分钟轮换凭证
  destination:
    create: true
    name: db-secret        # 生成的K8s Secret名称
# 应用中既可以使用env 挂到pod中:
env:
- name: DB_USERNAME
  valueFrom:
    secretKeyRef:
      name: db-secret
      key: username
- name: DB_PASSWORD
  valueFrom:
    secretKeyRef:
      name: db-secret
      key: password

Vault secrets-store-csi-driver

GitHub - hashicorp/vault-csi-provider: HashiCorp Vault Provider for Secret Store CSI Driver

使用CSI标准,通过SecretProviderClass CRD配置Vault Secret路径,CSI驱动在Pod创建时挂载Secret到文件系统。

功能特性

● 支持多集群,需在每个集群安装CSI驱动和Vault Provider,配置相对简单。

● 支持所有Vault动态Secret,CSI驱动管理租约续订,但无内置滚动重启功能。

● Secrets作为CSI卷挂载到Pod的文件系统中,可选择同步到Kubernetes Secret。

● DaemonSet模式在集群的每个节点上运行,负责处理挂载请求、与 Provider 交互、管理临时卷。

安全特性

● 使用Kubernetes Service Account认证

● Secrets通过CSI卷挂载,降低泄露风险

● 支持TLS/mTLS通信

● 可选同步到Kubernetes Secret

典型适用场景

● 希望直接挂载Secret到Pod文件系统

● 需要支持多云或外部Secret管理器

● 适合高安全性需求,不希望Secret存储在etcd

部署架构

使用样例

需要提前安装secrets-store-csi-driver

yaml 复制代码
# vault-spc.yaml 配置 SecretProviderClass
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: vault-db-creds
spec:
  provider: vault
  parameters:
    vaultAddress: "https://vault.example.com:8200"
    roleName: "csi-role"
    objects: |
      - objectPath: "kv/data/app/database"
        secretKey: "username"
        path: "db_user"
      - objectPath: "kv/data/app/database"
        secretKey: "password"
        path: "db_pass"
    # 可选:同步到Kubernetes Secret
    secretObjects:
      - secretName: "db-secret"  # 生成的Secret名称
        type: Opaque
        data:
          - key: "username"
            objectName: "db_user"
          - key: "password"
            objectName: "db_pass"
# app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    spec:
      serviceAccountName: app-sa  # 必须匹配Vault角色
      containers:
      - name: app
        image: nginx:latest
        volumeMounts:
        - name: db-creds
          mountPath: "/etc/secrets"
          readOnly: true
      volumes:
      - name: db-creds
        csi:
          driver: secrets-store.csi.k8s.io
          readOnly: true
          volumeAttributes:
            secretProviderClass: "vault-db-creds"  # 引用SecretProviderClass

External-Secret

GitHub - external-secrets/external-secrets: External Secrets Operator reads information from a third-party service like AWS Secrets Manager and automatically injects the values as Kubernetes Secrets.

通过Operator模式,使用SecretStore和ExternalSecret CRD,从Vault获取Secret并同步到Kubernetes Secret。

功能特性

● 支持多集群,通过ClusterSecretStore CRD配置,适合多云或混合环境。

● 仅支持KV Secret引擎,不支持动态Secret(如数据库凭据或PKI)。

● Secrets同步到Kubernetes原生Secret对象,可作为环境变量或文件使用。

安全特性

● 使用外部Secret管理器的认证(如Vault的Kubernetes认证)

● Secrets存储在etcd,需加密保护

● 提供访问控制和审计,但较弱

典型适用场景

● 希望简单集成外部Secret管理器(如Vault、AWS Secrets Manager)

● 应用依赖Kubernetes Secret作为环境变量

● 适合多云或混合环境

部署架构

使用样例

需要提前安装 external-secrets

yaml 复制代码
# vault-secretstore.yaml
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault-backend
spec:
  provider:
    vault:
      server: "https://vault.example.com:8200"
      path: "secret"
      version: "v2"  # KV引擎版本
      auth:
        # 使用Kubernetes认证/也可以使用approle认证。
        kubernetes:
          mountPath: "kubernetes"
          role: "eso-role"
          serviceAccountRef:
            name: eso-auth-sa  # 专用ServiceAccount
# database-externalsecret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
spec:
  refreshInterval: "5m"  # 同步间隔
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: db-secret  # 生成的K8s Secret名称
  data:
  - secretKey: username
    remoteRef:
      key: database/creds/db-role
      property: username  # 指定Secret字段
  - secretKey: password
    remoteRef:
      key: database/creds/db-role
      property: password
# 应用中使用env 挂到pod中:
env:
- name: DB_USER
  valueFrom:
    secretKeyRef:
      name: db-secret  # 匹配ExternalSecret生成的Secret
      key: username
- name: DB_PASS
  valueFrom:
    secretKeyRef:
      name: db-secret
      key: password
相关推荐
大佐不会说日语~3 小时前
Redis高可用架构演进面试笔记
redis·面试·架构
德育处主任Pro5 小时前
亚马逊云科技实战架构:构建可扩展、高效率、无服务器应用
科技·架构·serverless
Bar_artist7 小时前
云渲染的算力困局与架构重构:一场正在发生的生产力革命
重构·架构
三桥君7 小时前
AI应用爆发式增长,如何设计一个真正支撑业务的AI系统架构?——解析AI系统架构设计核心要点
人工智能·架构
一休哥助手8 小时前
ChatGPT Agent架构深度解析:OpenAI如何构建统一智能体系统
人工智能·chatgpt·架构
数据智能老司机11 小时前
函数式事件驱动架构——交易系统(可观测性)
架构·scala·响应式设计
我不是程序猿儿12 小时前
【Servo】裸机还是RTOS驱动架构如何选?
驱动开发·fpga开发·架构·伺服驱动器·伺服
掘金安东尼12 小时前
用 Amazon CDK 构建现代化云架构:Python 编写部署脚本替代 YAML
架构
掘金安东尼12 小时前
数据湖实战:用 Amazon Glue + Athena 构建企业级数据分析基座
架构
掘金安东尼12 小时前
打赢“云灾难”:一文掌握亚马逊云科技上的灾备策略
架构