如何在 Kubernetes 集群中把 Vault 用起来

本文涉及的产品
应用实时监控服务-应用监控,每月50GB免费额度
应用实时监控服务-用户体验监控,每月100OCU免费额度
性能测试 PTS,5000VUM额度
简介: 如何在云上应用中管理和保护用户的敏感信息是一个经常令开发者头疼的问题,用户的密码口令,证书秘钥等私密信息时常未经加密被随意的放置在配置文件,代码仓库或是共享存储里,而对于普通的开发者来说,设计和实现一套完整的秘钥管理系统是一个很大的挑战。

原文作者:dahukkk
原文链接:https://developer.aliyun.com/article/727671

Vault是什么?

如何在云上应用中管理和保护用户的敏感信息是一个经常令开发者头疼的问题,用户的密码口令,证书秘钥等私密信息时常未经加密被随意的放置在配置文件,代码仓库或是共享存储里,而对于普通的开发者来说,设计和实现一套完整的秘钥管理系统是一个很大的挑战。且不论令人生畏的加解密算法,很多的云应用仍然将一些敏感配置信息仅仅经过 base64 等一些简单的 hash 运算就放置在某个公共的配置中心上,而很多时候这些敏感信息会从应用的某行异常日志或是某段监控告警中泄露出去;不仅如此,对于一个集中式的秘钥管理系统,如何面向用户进行更细粒度的访问鉴权也是一个难题。

image.png

Vault 的出现给了上述问题一个解决方案,它是 HashiCorp 公司(旗下还有 Vagrant,Terraform,Consul 等知名产品)维护的开源软件,它的设计思想基于云原生背景下动态基础设施的特点,在云上的不同网络层以及不同的服务之间已经很难找到传统的信任边界,服务之间更加强调以身份(identity)为核心的认证和访问控制,而不是像传统静态基础设施中以 IP、主机地址作为信任凭证。为此 Vault 提供了以下几个功能点:

  • Secret存储形式的多样性,任意的kv形式敏感信息(如数据库密码,证书,ssh登录秘钥,openapi身份凭证等);
  • 存储格式的多样性,支持插件式的存储引擎扩展,可对接如 AWS,Consul,NoSQL,KV,PKI,SSH 等多种插件引擎;
  • 支持与各类平台的认证对接,可动态生成认证凭据或配置信息;
  • 支持基于 Shamir 算法的私钥分割完成 Vault 后端的加封和解封操作,同时支持高可用的部署形态;
  • 支持各类 secret 的动态生成,续租,撤销和滚动更新;
  • 完备的审计日志;
  • 完备的 CLI 和 RESTful API

Vault 与 k8s 的集成

Vault 松耦合的架构使其支持与多种 secret 引擎和相应的存储后端对接,同时支持与多种认证服务器的交互。
本节我们主要介绍 Vault 与 k8s 的集成。

2.1 Vault 在 Kubernetes 中的应用场景

Vault 作为企业级的 secret 管理工具,是一些大客户在业务上云过程中的安全强需求,尤其是国外市场。在 Kubernetes 集群中主要有以下应用场景:

  • 作为部署在 Kubernetes 集群中的应用对外提供秘钥管理服务,支持与多家主流云厂商秘钥服务以及多种 secrets 形式的对接,支持多种数据库服务的存储对接,同时支持多种认证形式的对接。
  • 作为一个公共的加密服务(Encryption as a Service)而不做后端存储的对接,帮助用户应用剥离繁琐的加密加解密逻辑。
  • 面向政府、金融等对数据安全规格有很高要求的客户,Vault 支持基于 Two-man 原则利用私钥分割算法对后端服务进行加解封,并结合 k8s 的高可用部署形态为企业提供更加安全可靠的 secret 管理能力。
    当然这里只是列举了一些 Vault 原生提供的能力,作为一个在 Kubernetes 集群上直接运行的安全应用,任何一个面向 k8s 的应用工具都可以利用其安全能力。

2.2 安装 Vault

Vault 支持 helm 化安装,在其官方文档中我们可以找到关于启动参数的详细配置说明,同时在阿里云容器服务的应用目录 apphub 中我们也可以通过控制台在 ACK 集群中方便的安装 Vault

image.png

另外 Vault 的默认安装也集成了其控制台的安装,通过负载均衡服务或 ingress 路由的方式我们可以在公网访问其 UI,在 vault pod 的日志中我们可以找到登录使用的 root token,在控制台中可以方便的设定与存储引擎和认证方式的对接,同时还可以进行基于策略的访问控制配置。
image.png

2.3 认证方式的集成

当用户希望在 k8s pod 的业务逻辑中与 Vault 服务端通讯,获取需要的 secrets 时,首先 Vault 会对这个 pod 中的请求进行认证,那么这个 pod 中的 Vault 请求认证凭据应该如何获取呢?如上所述,Vault 后端支持多种认证方式的对接,对于 Kubernetes,Vault 支持基于 K8s Service Account Token 的认证。

使用上,Vault 管理员首先需要在后端 enable kubernetes 的认证方式,生成一个与 Vault 交互的指定 sa,然后通过 CLI 或 API 将 sa token 和集群 ca,公网地址等信息写入到 Vault 后端中,并配置与 vault 后端的 ACL 策略绑定。详细步骤请参见官方文档。

当然在 pod 应用中可以并不局限于一定使用基于 sa 的 kubernetes 认证方式。比如[kubernetes-vault]( https://github.com/Boostport/kubernetes-vault
)。该项目使用 Vault 中的[ AppRole ](https://www.vaultproject.io/docs/auth/approle.html
)认证方式,在该认证模式中,管理员可以为不同的 pod 创建不同的 Vault 原生 role 模型并绑定到对应的 policy 上,同时可以基于 role 创建 secret_id,secret_id 对应的 token 可作为与 Vault 进行认证的临时凭证。kubernetes-vault 利用了 AppRole 的认证交互模式,首先已经完成安装的 kubernetes-vault controller 会去 Watch 集群中所有 pod 的创建,当发现新建 pod 的部署模板中有指定 annotation 的 init-container 存在时,controller 会根据模板中指定的 vault role id 去 Vault 请求获取其对应的 secret_id 并发送给 init-container 中 kubernetes-vault 的客户端,在应用容器启动前 kubernetes-vault 客户端用 controller 返回的 secret_id 和 role_id 去 Vault 请求真正的 login token 并最终写入到与应用 pod 共享的挂载目录中;同时客户端会根据 token 过期时间进行定时的轮转,保证其可用性。下图为 kubernetes-vault 工作流程图:

image.png

在社区也存在不少基于 k8s 与 Vault 进行认证对接的其他方案,其设计思路大同小异,基本都采用了通过 init-container 或 sidecar 方式引入一个额外的客户端去 Vault 请求指定认证模式下的短时凭证并共享给业务容器使用。
在容器服务控制台的应用目录 apphub 中,我们同样可以找到 kubernetes-vault,方便开发者使用 helm 直接在集群指定命名空间一键部署。Vault 也计划在后续自己的官方版本 helm chart 中增加配置项以支持上述登录认证 secret 的动态注入。

Vault 与阿里云 RAM 的集成

当我们在应用中需要访问阿里云资源时,需要使用 RAM 账号对应的 AK 或是 STS 临时 credentials 作为访问相应资源接口的凭证。如果使用账号 AK,如何使其能够被应用逻辑获取的同时保证 AK 的安全性一直是一个头疼的问题;如果使用临时 sts token,由于其时效性,我们也需要在考虑安全性的同时思考如何进行临时访问凭证的轮转。相比较两种方式,使用 sts 临时凭证的方式肯定在安全上是更为推荐的方式,同时对这种动态 secret 的安全管理也正是 Vault 的优势所在。本节我们来介绍下 Vault 与阿里云 RAM 在认证方式和 secret 管理引擎上的集成。

3.1 认证方式的集成

首先在认证方式上,Vault 服务端的 role 模型可以与 RAM role 进行一对一的映射匹配,用户可以使用 Vault提供的 OpenAPI 或是 CLI,通过传入扮演RAM role 返回的临时凭证调用GetCallerIdentity 接口,然后 Vault 服务端会根据请求返回的角色 arn id 在其后端存储中查找是否有对应的权限策略配置,如果存在则认证成功并返回一个可用于调用 Vault 其他后端接口的访问 token。

3.2 Vault Secret 引擎与 RAM 的集成

当我们需要在业务应用逻辑中使用阿里云资源时,通常需要通过角色扮演的方式获取一个 RAM 返回的临时凭证,然后通过这个临时凭证完成与 RAM 的鉴权过程。由于凭证的时效性,我们在保证其安全性的同时还要维护一个对应的秘钥轮转机制。Vault 的 secret 引擎实现了与阿里云 RAM 的对接插件,帮助我们安全、动态的管理 RAM 凭证,其主要步骤 如下:

1.开启后端引擎

2.在 RAM 控制台为 Vault 服务器创建专属子账号并绑定定制化权限策略

3.获取 Vault 子账号对应的 AK 并通过 Vault CLI/API 写入到后端指定路径下

4.在 Vault 后端写入业务中希望获取的 RAM 凭证所对应的策略定义或角色,其中策略定义支持 inline 和 remote 策略两种形式,所谓 inline 模式是指直接在 api 请求中写入策略模板,remote 模式指写入 RAM 中存在的策略类型和名称,比如:

$ vault write alicloud/role/policy-based \
    remote_policies='name:AliyunOSSReadOnlyAccess,type:System' \
    remote_policies='name:AliyunRDSReadOnlyAccess,type:System'

角色模式需要用户指定希望被扮演的角色 arn,另外需要 Vault 子账号在该角色的受信实体里,一个示例如下:

$ vault write alibaba/role/role-based \
role_arn='acs:ram::5138828231865461:role/hastrustedactors'

5.在具体的业务应用中,只需要通过调用 Vault 的 creds/policy-based 或 role-based 接口即可动态获取相应的 RAM 访问凭证,下面是一个角色扮演返回临时 token 的 CLI 调用示例:

$ vault read alicloud/creds/role-based
Key                Value
---                -----
lease_id           alicloud/creds/role-based/f3e92392-7d9c-09c8-c921-575d62fe80d9
lease_duration     59m59s
lease_renewable    false
access_key         STS.L4aBSCSJVMuKg5U1vFDw
secret_key         wyLTSmsyPGP1ohvvw8xYgB29dlGI8KMiH2pKCNZ9
security_token     CAESrAIIARKAAShQquMnLIlbvEcIxO6wCoqJufs8sWwieUxu45hS9AvKNEte8KRUWiJWJ6Y+YHAPgNwi7yfRecMFydL2uPOgBI7LDio0RkbYLmJfIxHM2nGBPdml7kYEOXmJp2aDhbvvwVYIyt/8iES/R6N208wQh0Pk2bu+/9dvalp6wOHF4gkFGhhTVFMuTDRhQlNDU0pWTXVLZzVVMXZGRHciBTQzMjc0KgVhbGljZTCpnJjwySk6BlJzYU1ENUJuCgExGmkKBUFsbG93Eh8KDEFjdGlvbkVxdWFscxIGQWN0aW9uGgcKBW9zczoqEj8KDlJlc291cmNlRXF1YWxzEghSZXNvdXJjZRojCiFhY3M6b3NzOio6NDMyNzQ6c2FtcGxlYm94L2FsaWNlLyo=
expiration         2018-08-15T21:58:00Z

如何在 K8s 应用中使用 Vault Secret

在了解了 Vault 的基本概念以及与 Kubernetes 的认证交互流程后,我们进入客户最为关心的话题。如何在 k8s pod 应用中方便地获取 Vault 服务端管理的 secret。社区针对此问题也有激烈的讨论和不少相关解决方案,方案主要集中在两个方向:

[定时同步进程](https://github.com/hashicorp/vault/issues/7364
):使用一个同步进程定时地从 Vault 服务端获取指定范围的秘钥更新并同步到 K8s 集群中的 secret 模型,代表的项目有 vaultingkube 和[secrets-manager]( https://github.com/tuenti/secrets-manager
) 。其主要设计思想也不尽相同,以 secrets-manager 为例,首先用户可以通过 CRD 定义在 Vault 中关注的 secret 数据源,然后 secrets-manager 对应的 controller 会在 Reconcile 函数中定时对比指定管理范围内的 K8s secret 和 vault secret 的状态,如果不一致则进行一次调协。而用户在 pod 应用中可以直接引用原生 secret 模型中的内容获取远端 Vault 服务器中的秘钥。
当然社区中也存在一些对这种秘钥同步方案的质疑,比如认为该方案在秘钥同步的传输过程和用户 pod 使用原生 secret 的 rest 交互中会增加攻击面,但是该方案在部署实施上比较友好,也得到了很多用户的支持。

CSI 插件形式集成:该方案基于 CSI plugin 将 Vault 中的秘钥通过 volume 的形式挂载到 pod 应用中。
secrets-store-csi-driver 通过实现一套基于 CSI 规范的 driver 机制可以对接不同厂商的后端存储,而 Vault secret 的 driver(secrets-store.csi.k8s.com)允许 kubelet 将各类企业级秘钥存储中的 secret 通过 volume 挂载,一旦 attach 动作完成,秘钥数据即挂载到了容器对应的文件系统中。在 CSI driver 的基础上,不同的秘钥管理后端可以实现定制化的 provider 去对接 CSI driver 框架中的规定接口。provider 的功能概括如下:

  • 对接后端秘钥管理系统,提供秘钥获取等必须的接口实现
  • 适配当前 CSI driver 的接口定义
  • 通过框架中的回调函数无需调用 Kubernetes API 即可将从后端获取的秘钥数据挂载到指定路径下
    HashiCorp 官方也基于此框架实现了一套对接 Vault 的 Provider。这里我们以此为例具体来看下在一个 k8s pod 应用中如何通过 CSI plugin 的方式使用 Vault 中管理的 secret 秘钥。

1 首先我们创建一个开启了 CSI 存储插件的 ACK 集群,然后参考文档在集群中部署 Vault 服务端,为了便于验证这里我们使用 dev 模式省去 unseal 解封等流程,同时配置 provider 与 Vault 交互的认证模式和相应的访问控制策略
image.png

然后通过 cli 向 Vault 后端写入测试数据
image.png

2 通过官方提供的 helm 方式安装 Secret Store CSI Driver,命令如下:

helm install . -n csi-secrets-store --namespace dev --set providers.vault.enabled=true

安装成功后如下图所示:
image.png

3 在集群中创建 secretproviderclasses 实例用于 Secret Store CSI Driver 与 Vault 的参数对接,一个示例如下,注意这里的 vault 服务端地址可通过 kubectl get service vault 获取。

image.png

4 最后我们来看下如何在应用 pod 中对接上述provider 实例获取对应的 Vault 秘钥。这里 pod 对于上述 vault provider 的使用分为两种方式:

1)如果 pod 运行的目标集群版本在 v1.15.0 以上,且集群 apiserver 和节点 kubelet manifest 配置均开启了 CSIInlineVolume=true的 feature-gates,则我们可以在 pod 中的 volume 字段内置声明需要使用的 csi provider 实例。

kind: Pod
apiVersion: v1
metadata:
  name: nginx-secrets-store-inline
spec:
  containers:
  - image: nginx
    name: nginx
    volumeMounts:
    - name: secrets-store-inline
      mountPath: "/mnt/secrets-store"
      readOnly: true
  volumes:
    - name: secrets-store-inline
      csi:
        driver: secrets-store.csi.k8s.com
        readOnly: true
        volumeAttributes:
          secretProviderClass: "vault-foo"
···
2)如果目标集群不支持 CSI 的 Inline Volume 特性,我们需要首先创建使用 csi 的 pv 和对应的 pvc 实例,一个 pv 模板示例如下:
···
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-vault
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadOnlyMany
  persistentVolumeReclaimPolicy: Retain
  csi:
    driver: secrets-store.csi.k8s.com
    readOnly: true
    volumeHandle: kv
    volumeAttributes:
      providerName: "vault"
      roleName: "example-role"
      vaultAddress: http://172.21.12.21:8200
      vaultSkipTLSVerify: "true"
      objects:  |
        array:
          - |
            objectPath: "/foo"
            objectName: "bar"
            objectVersion: ""

在 pod 实例模板中引用指定 pvc 即可在 pod 中获取到 vault,这里我们在 ACK 集群以 pv/pvc 模式为例创建一个 nginx 应用容器实例并在其中挂载上文中我们创建的 secretproviderclasses 实例:
image.png

相比于 secrets-manager 等采用 secret 定时同步的方式,使用 CSI 对接指定 Vault secret provider 实例的方式虽然在实施步骤上比较复杂,同时在应用中也无法动态获取 Vault 后端 secret 的变更,但是该方案避免了 secret 在同步链路上频繁传输的安全风险,同时也客服了之前 describe po 可能造成的秘钥泄露,在整体安全性上要高出不少。大家可以根据实际应用场景选择适合自己的方式。

“阿里巴巴云原生微信公众号(ID:Alicloudnative)关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的技术公众号。”

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
1天前
|
Prometheus Kubernetes 监控
OpenAI故障复盘 - 阿里云容器服务与可观测产品如何保障大规模K8s集群稳定性
聚焦近日OpenAI的大规模K8s集群故障,介绍阿里云容器服务与可观测团队在大规模K8s场景下我们的建设与沉淀。以及分享对类似故障问题的应对方案:包括在K8s和Prometheus的高可用架构设计方面、事前事后的稳定性保障体系方面。
|
4天前
|
Kubernetes 网络协议 应用服务中间件
Kubernetes Ingress:灵活的集群外部网络访问的利器
《Kubernetes Ingress:集群外部访问的利器-打造灵活的集群网络》介绍了如何通过Ingress实现Kubernetes集群的外部访问。前提条件是已拥有Kubernetes集群并安装了kubectl工具。文章详细讲解了Ingress的基本组成(Ingress Controller和资源对象),选择合适的版本,以及具体的安装步骤,如下载配置文件、部署Nginx Ingress Controller等。此外,还提供了常见问题的解决方案,例如镜像下载失败的应对措施。最后,通过部署示例应用展示了Ingress的实际使用方法。
18 2
|
16天前
|
存储 Kubernetes 关系型数据库
阿里云ACK备份中心,K8s集群业务应用数据的一站式灾备方案
本文源自2024云栖大会苏雅诗的演讲,探讨了K8s集群业务为何需要灾备及其重要性。文中强调了集群与业务高可用配置对稳定性的重要性,并指出人为误操作等风险,建议实施周期性和特定情况下的灾备措施。针对容器化业务,提出了灾备的新特性与需求,包括工作负载为核心、云资源信息的备份,以及有状态应用的数据保护。介绍了ACK推出的备份中心解决方案,支持命名空间、标签、资源类型等维度的备份,并具备存储卷数据保护功能,能够满足GitOps流程企业的特定需求。此外,还详细描述了备份中心的使用流程、控制台展示、灾备难点及解决方案等内容,展示了备份中心如何有效应对K8s集群资源和存储卷数据的灾备挑战。
|
1月前
|
Kubernetes 监控 Cloud Native
Kubernetes集群的高可用性与伸缩性实践
Kubernetes集群的高可用性与伸缩性实践
74 1
|
2月前
|
JSON Kubernetes 容灾
ACK One应用分发上线:高效管理多集群应用
ACK One应用分发上线,主要介绍了新能力的使用场景
|
2月前
|
Kubernetes 持续交付 开发工具
ACK One GitOps:ApplicationSet UI简化多集群GitOps应用管理
ACK One GitOps新发布了多集群应用控制台,支持管理Argo CD ApplicationSet,提升大规模应用和集群的多集群GitOps应用分发管理体验。
|
2月前
|
Kubernetes Cloud Native 云计算
云原生之旅:Kubernetes 集群的搭建与实践
【8月更文挑战第67天】在云原生技术日益成为IT行业焦点的今天,掌握Kubernetes已成为每个软件工程师必备的技能。本文将通过浅显易懂的语言和实际代码示例,引导你从零开始搭建一个Kubernetes集群,并探索其核心概念。无论你是初学者还是希望巩固知识的开发者,这篇文章都将为你打开一扇通往云原生世界的大门。
147 17
|
2月前
|
Kubernetes Ubuntu Linux
Centos7 搭建 kubernetes集群
本文介绍了如何搭建一个三节点的Kubernetes集群,包括一个主节点和两个工作节点。各节点运行CentOS 7系统,最低配置为2核CPU、2GB内存和15GB硬盘。详细步骤包括环境配置、安装Docker、关闭防火墙和SELinux、禁用交换分区、安装kubeadm、kubelet、kubectl,以及初始化Kubernetes集群和安装网络插件Calico或Flannel。
208 4
|
2月前
|
Kubernetes 应用服务中间件 nginx
搭建Kubernetes v1.31.1服务器集群,采用Calico网络技术
在阿里云服务器上部署k8s集群,一、3台k8s服务器,1个Master节点,2个工作节点,采用Calico网络技术。二、部署nginx服务到k8s集群,并验证nginx服务运行状态。
983 1
|
2月前
|
Kubernetes Cloud Native 流计算
Flink-12 Flink Java 3分钟上手 Kubernetes云原生下的Flink集群 Rancher Stateful Set yaml详细 扩容缩容部署 Docker容器编排
Flink-12 Flink Java 3分钟上手 Kubernetes云原生下的Flink集群 Rancher Stateful Set yaml详细 扩容缩容部署 Docker容器编排
93 3

相关产品

  • 容器服务Kubernetes版
  • 推荐镜像

    更多