【GitOps系列】如何解决 GitOps 的秘钥存储问题?

news2024/11/25 3:21:06

文章目录

      • 简介
      • GitOps 密钥管理方案
        • 安装 Sealed-Secrets
          • 安装 CLI 工具
          • 安装 Controller 控制器
        • 示例应用介绍
        • 创建 ArgoCD 应用
        • 创建加密后的 Secret 对象
          • 创建 Image Pull Secret 对象
          • 创建 Secret 对象
          • 推送到代码仓库
          • 验证 Secret
      • 原理解析
      • 核心关注点

简介

在实际的业务场景下,出于安全需要,Git 仓库往往会包含下面这些机密信息。

  1. 镜像拉取凭据的 Secret 对象,它可以为集群提供拉取镜像的权限。
  2. 外部数据库连接信息。
  3. 外部中间件如 MQ 连接信息。
  4. 第三方服务的 API KEY,例如云厂商和短信服务商。

在 GitOps 工作流中,这些机密信息都会通过 Kubernetes 对象存放在 Git 仓库,在大部分情况下它们是 Configmap 或 Secret 对象。虽然 Secret 被设计为存储 Kubernetes 的机密信息,但它只是 Base64 编码后的结果,不具备加密性质,这也就意味着机密信息完全是以明文的方式暴露的,这是非常不安全的。所以,我们有必要对这些机密信息进行加密。本次主要来学习加密 Git 仓库中机密信息的方法,进一步提升 GitOps 的安全性。

GitOps 密钥管理方案

在 GitOps 工作流中,常用的密钥管理方案有下面三种。

  1. Sealed-Secrets
  2. External-Secrets
  3. Vault

其中,Sealed-Secrets 在易用性方面有比较大的优势,社区活跃度也比较高,也更容易和 GitOps 工作流结合。它的工作原理也非常简单,它利用非对称加密算法对 Secret 对象进行加密,使用的时候在集群内自动进行解密,这样就可以将加密后的密钥安全地存储在 Git 仓库中。

External-Secrets 需要外部密钥管理服务的支持,例如 AWS Secrets ManagerGoogle Secrets ManagerAzure Key Vault 等,如果在你的项目里用到了这些密钥管理服务,可以考虑使用它。

Vault 是 HashiCorp 开源的一款密钥管理工具,要将它和 ArgoCD 结合使用需要额外的插件,配置起来比较繁琐。

安装 Sealed-Secrets

Sealed-Secrets 分为两部分,本地的 CLI 工具和运行在集群的控制器,在使用之前我们需要先安装它们。

安装 CLI 工具

kubeseal 命令行工具是本地和集群 Sealed-Secrets 服务交互的工具,我们需要用它来加密机密信息。

Mac:
$ brew install kubeseal

Linux:
https://github.com/bitnami-labs/sealed-secrets/releases
安装 Controller 控制器

Sealed-Secrets 控制器负责对加密的信息进行解密,并生成 Kubernetes 原生的 Secret 对象。以 Helm 方式安装。

~# helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
"sealed-secrets" has been added to your repositories

$ helm install sealed-secrets -n kube-system --set-string fullnameOverride=sealed-secrets-controller sealed-secrets/sealed-secrets

示例应用介绍

Deployment资源如下:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-spring
spec:
    ......
    spec:
      imagePullSecrets:
      - name: github-regcred
      containers:
      - name: sample-spring
        image: ghcr.io/lyzhang1999/sample-kotlin-spring:latest
        ports:
        - containerPort: 8080
          name: http
        env:
          - name: PASSWORD
            valueFrom:
              secretKeyRef:
                key: password
                name: sample-secret

示例应用镜像存放到了 GitHub Package 仓库,也就是域名为 ghcr.io 的镜像仓库中,同时设置了私有仓库类型。在没有向 Kubernetes 集群提供拉取凭据的情况下,是无法拉取镜像的,这意味着直接将这个工作负载部署到集群将得到 ImagePullBackOff 的事件。
imagePullSecret 是镜像拉取凭据,这个凭据需要通过kubeseal创建。
为工作负载配置了 Env 环境变量,它的值来源于名为sample-secretSecret对象。这个 Secret 也需要通过kubeseal来创建。

创建 ArgoCD 应用

修改 sealed-secret/application.yaml 文件

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: spring-demo
spec:
   project: default
   source:
     # 替换为你的 Git 仓库地址,注意将仓库权限设置为公开,并使用 https 协议
     repoURL: https://github.com/xxx/kubernetes-example.git

$ cd sealed-secret
$ kubectl apply -f application.yaml

通过ArgoCD控制台可以看到我们的应用其实是不健康的,是因为没有镜像凭证导致!
在这里插入图片描述

创建加密后的 Secret 对象

我们对两种 Secret 对象进行加密,它们分别是镜像拉取凭据和普通 Secret 对象。然后将加密后的 Secret 对象推送到 Git 仓库中,以便 ArgoCD 将它一并部署到集群内。

创建 Image Pull Secret 对象
cat sealed-secret/image-pull-secret.yaml 
kind: Secret
type: kubernetes.io/dockerconfigjson
apiVersion: v1
metadata:
  name: github-regcred
data:
  .dockerconfigjson: xxxxxxxxxjpU1T1RrNloyaPV2QzWTBWRlRWSmpWbIRQTlROeWRVOXN

创建加密后的 Secret 对象
$ kubeseal -f image-pull-secret.yaml -w manifest/image-pull-sealed-secret.yaml --scope cluster-wide

-f 参数指定了原始 Sceret 对象文件,也就是 image-pull-secret.yaml-w 参数表示将加密后的 Secret 对象写入 manifest 目录的image-pull-sealed-secret.yaml文件内,这样 ArgoCD 就可以将它一并部署到集群内。–scope 参数表示加密后的 Secret 对象可以在集群的任何命名空间下使用.

从以下内容可以看出,原始的 Secret 对象被转化为了 SealedSecret 对象,并且增加了 encryptedData 字段,它可以存放加密后的内容。

cat manifest/image-pull-sealed-secret.yaml 
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  annotations:
    sealedsecrets.bitnami.com/cluster-wide: "true"
  creationTimestamp: null
  name: github-regcred
spec:
  encryptedData:
    .dockerconfigjson: AgBgEUOxC1i2AuZJ2LzPiSfYblycy71NGv1SapA46ugFlWyKRaUg+WQGDHr6W6m+/8mBPvDuKh40xrszBEeaN212qNbbyb87tb1fZ8v9g7DmcsYp5I3VBSQ+9sljoXlf8XmTyGnohl6ZV5i79muSzhmJhNJAofOGVX4O52RvGjP8P9LvLYS7rlV/Nv49F5tnJqaEtZbYlxpQ5WggFFyOZ+LSaR/wkS0anOW/k6ZU/KHWijnvBKl/YRBbXsPHnyJpkFmGhN8hvZkaUZYpRZ+mbkdYMPw6HAgUMiyMWnbbzRBheJmiFafKV9RRfqfZoTaHubLIXdpFRrHdRS6SojYUuJFrVTM9xXRdpadC9T0cRCwvKGGGRVbNosOWhPtB2DkwzptQOL+6KMAlBHFrOKdkVULKVveJV269X85NcQDH40ZZMuCTMPIItC8hs6pqOheQ0SvaYrVri1GkEXovUYbNArhnUPnUuUf/zMTbQ5sYOGb20ST1HbBJqiTvIn54N22tg0ANhTaRSuQoW7yxd7ZGno2xNiyoIYk/6r7m3rRUtmBXR8+VD1bmuandH+Bpb4rnYDmZUSEFuhXm/d/szgoaE+s6b/RHhml7WsaPXQEmOInaoe3WvwZvTa9htLKJq2XzHkPMHa5H4vPZ4+1MyM13o1R8GLYuwI5gFqsyDfnLRQ2bXMbAwiSFkhQ947RpXHmG0Y29opLeNnjDt93gGFfo20wIYwl5YhOALpV3K5vKL1gAmRq1urAtDGSnCZkrMQKbEtQUKPJrzgmftAanzScKyVrFkQ8lG7CBv9xt42acvYJL0gIyVUKdXFay6qN4/GyYx4lQvLYOAMctkafluI2EZQweasetM8g2js+uAUJn1+WtUqtE2Tljd+avc7sJwWpEZfpW2BpcXAOGC4pLxLVKjm8EKLTru4vi5TOF0bfOvZJGBnEFuZQMYpme
  template:
    metadata:
      annotations:
        sealedsecrets.bitnami.com/cluster-wide: "true"
      creationTimestamp: null
      name: github-regcred
    type: kubernetes.io/dockerconfigjson
创建 Secret 对象
cat sample-secret.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: sample-secret
data:
  password: YWRtaW4K

$ kubeseal -f sample-secret.yaml -w manifest/sample-sealed-secret.yaml --scope cluster-wide

运行命令后,在 manifest 目录下生成 sample-sealed-secret.yaml 文件,它包含加密后的 Secret 内容。
推送到代码仓库
$ git add .
$ git commit -a -m 'add secret'
$ git push origin main

进入 ArgoCD 控制台的应用详情,手动点击 “SYCN”按钮同步刚才新增的 Secret 对象。现在可以看到应用状态变成了 Healthy 健康状态,并且 Sealed-Secret 控制器对刚才创建的 SealedSecret 对象进行了解密,还重新创建了原始的 Kubernetes Secret 对象以供 Deployment 工作负载使用,如下图所示:
在这里插入图片描述

验证 Secret
临时配置应用端口转发:
$ kubectl port-forward svc/sample-spring 8081:8080 -n secret-demo

$ curl http://localhost:8081/actuator/env/PASSWORD

{"property":{"source":"systemEnvironment","value":"******"},"activeProfiles":[],"propertySources":[{"name":"server.ports"},{"name":"servletConfigInitParams"},{"name":"servletContextInitParams"},{"name":"systemProperties"},{"name":"systemEnvironment","property":{"value":"******","origin":"System Environment Property \"PASSWORD\""}},{"name":"random"},{"name":"Config resource 'class path resource [application.yml]' via location 'optional:classpath:/'"},{"name":"Management Server"}]}

从返回结果可以发现,应用已经成功获取到了 PASSWORD 环境变量,这说明 Sealed-Secret 控制器也已经生成了原始的 Secret 对象。
通过以上演示,在 GitOps 工作流中,当我们在集群内安装了 Sealed-Secret 控制器之后,只需要在 Git 仓库存储加密后的SealedSecret对象即可,不再需要存储原始的Kubernetes Secret对象了。

原理解析

在这里插入图片描述

按照架构图上的序号来依次理解每一个步骤。
由于加解密过程涉及到非对称加密,所以当我们在集群内安装 Sealed-Secret 控制器时,控制器会在集群范围内查找私钥/公钥对,如果没找到,则会生成一个新的 RSA 密钥对,并存储在部署 Sealed-Secret 命名空间下的 Secret 对象中,通过命令来查看:

$ kubectl get secret -n kube-system
NAME                                   TYPE                 DATA   AGE
sealed-secrets-keyj78wj                kubernetes.io/tls    2      131m

上面输出的结果中,以 sealed-secrets 开头的 Secret 对象就是存储 RSA 密钥的对象。
要获取 RSA 密钥,可以进一步查看:

$ kubectl get secret sealed-secrets-keyj78wj -n kube-system -o yaml

当我们在本地使用 kubeseal 加密一个 Secret 对象时,kubeseal 会从集群内下载 RSA 公钥,并使用它来加密 Secret 对象,然后生成加密后的 SealedSecret CRD 资源,也就是 SealedSecret 对象。
当集群内控制器监听到有新的 SealedSecret 对象被部署时,它会使用集群内的 RSA 私钥来解密信息,并且在集群内重新生成 Secret 对象,以便提供给工作负载使用。

核心关注点

1.由于Sealed-Secret的加解密过程需要使用 RSA 密钥对,而 RSA 密钥对又是在部署控制器时自动生成的,所以,你需要额外留意存储 RSA 密钥的 Kubernetes Secret 对象。
2.尤其是在需要进行集群迁移时, 需要对它进行备份,如果遗失,将无法对 Git 仓库存储的 SealedSecret 对象解密,你需要重新从原始的 Secret 对象那里生成加密后的 SealedSecret 对象。
3.要对已有的 RSA 密钥进行备份,首先你可以导出存储它的 Secret 对象,并保存为 backup-sealed-secret-rsa.yaml 文件。
4.此外,出于安全考虑,Sealed-Secret 控制器默认每 30 天会生成新的 RSA 密钥对,但旧的 RSA 密钥对并不会被删除,所以通过旧的 RSA 密钥加密的 Secret 对象依然可以被解密。

$ kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml > backup-sealed-secret-rsa.yaml

$ kubectl apply -f backup-sealed-secret-rsa.yaml

接着部署 Sealed-Secret 控制器。 此时,因为 kube-system 命名空间下已存在 RSA 密钥对,Sealed-Secret 会默认使用它作为解密的密钥,这样就完成了集群的迁移工作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/876558.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1.SpringMVC接收请求参数及数据回显:前端url地址栏传递参数通过转发显示在网页

1、SpringMVC 处理前端提交的数据 1.1 提交的域名和处理方法的参数不一致,使用注解解决 1.2 提交的域名和处理方法的参数不一致,使用注解解决 1.3 提交的是一个对象 2、前端url地址栏传递的是一个参数 请求地址url:http://localhost:8080/s…

openGauss学习笔记-39 openGauss 高级数据管理-分区表

文章目录 openGauss学习笔记-39 openGauss 高级数据管理-分区表39.1 范围分区表的分类39.2 创建范围分区39.2.1 创建VALUES LESS THAN范围分区表语法格式39.2.2 创建VALUES LESS THAN范围分区表参数说明39.2.3 创建VALUES LESS THAN范围分区表示例 39.3 询分区表39.3.1 查询分区…

el-table自适应缩放大小

安装依赖 npm install --save vue-draggable-resizable //或 cnpm install --save vue-draggable-resizablemain.js引入依赖 import VueDraggableResizable from vue-draggable-resizable import "vue-draggable-resizable/dist/VueDraggableResizable.css"; Vue.c…

Haproxy+Keepalived高可用部署

环境准备: IPVIPmasterhaproxy192.168.134.170192.168.134.100backuphaproxy192.168.134.172192.168.134.100web1192.168.134.171web2192.168.134.173web3192.168.134.174 1、首先配置啊三台web服务器,并写好测试页面。 web1(配置jsp页面&…

Wlan——CAPWAP协议的报文格式与报文封装

目录 CAPWAP报文携带信息 Discovery报文(AP先发) Join报文(AP先发) Configuration Status报文(AP先发) Change State报文(AP先发) Echo报文(AP和AC都可以先发&…

2023 CCF BDCI 数字安全公开赛正式开启报名

2023 CCF BDCI 数字安全公开赛重磅来袭! 全新的赛道场景 丰厚的赛事奖励 精彩的周边活动 数字安全守护人的狂欢盛宴 快来报名参加吧 大赛背景 伴随着数智化的持续加深,网络安全、数据安全风险遍布于所有场景之中,包括工业生产、能源、交…

SSH远程连接MacOS catalina并进行终端颜色配置

一、开关SSH服务 在虚拟机上安装了MacOS catalina,想要使用SSH远程进行连接,但是使用“系统偏好设置”/“共享”/“远程登录”开关进行打开,却一直是正在启动“远程登录”: 难道是catalina有BUG?不过还是有方法的&…

2023年许战海咨询《竞争之王CEO年度辅导工程》火热招募中

今天产业迭代速度不断加剧,人类知识更迭周期大大压缩到2年以内,企业遭遇更多挑战:如增长乏力、品牌老化、竞争压力大、竞争方向不明确、产品同质化、利润越来越低、团队执行难等。《竞争之王CEO年度辅导工程》应运而生,旨在手把手辅导企业家及高管团队如何制定战略和落地战略&a…

Wireshark有线网卡抓包报错The capture session could not be initiated on capture device

最近在使用Wireshark进行抓包排错时,选择网卡后提示报错,在此之前从未出现过,报错内容如下: 提示内容是The capture session could not be initiated on capture device,无法在捕获设备上启动捕获会话要求操作是Please…

解密人工智能:线性回归 | 逻辑回归 | SVM

文章目录 1、机器学习算法简介1.1 机器学习算法包含的两个步骤1.2 机器学习算法的分类 2、线性回归算法2.1 线性回归的假设是什么?2.2 如何确定线性回归模型的拟合优度?2.3 如何处理线性回归中的异常值? 3、逻辑回归算法3.1 什么是逻辑函数?…

5.0 Spring Boot核心

1. Spring Boot注解 注解名称 注解说明 SpringBootApplication 用于标注Spring Boot应用为启动类,是一个组合注解,主要组合了SpringBootConfiguration、EnableAutoConfiguration和ComponentScan注解 SpringBootConfiguration 继承自Configuration&a…

以开放促发展 同创永益召开数字韧性生态交流会

8月3日,同创永益数字韧性生态交流会在北京总部举办,30多家合作伙伴、渠道商齐聚一堂,围绕同创永益品牌、产品、行业解决方案进行充分探讨,共话行业前瞻趋势,共绘跨越增长新蓝图。 活动开始前,同创永益渠道管…

C++——函数重载及底层原理

函数重载的定义 函数重载: 是函数的一种特殊情况,C允许在同一作用域重声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数或者类型,类型的顺序)不同,常用来处理实现功能类似数据结构…

超好用的接口自动化框架,lemon-easytest内测版发布,赶紧用起来~

easytest easytest 是一个接口自动化框架。 功能特点: 支持 http 接口测试 支持 json,html,xml 格式的响应断言 支持数据库断言 支持用例标记筛选 支持用例失败重运行 支持多线程 安装 pip install lemon_easytest 快速使用 不需要写任何代码…

wsl没有响应,wsl启动失败,docker启动失败

wsl的相关问题记录和解决 问题一:cmd命令窗口输入wsl后没有响应,会卡住,类似如图 排查: 输入 wsl -l -v看是否有东西输出;我的电脑没有东西输出,依旧是卡住;有内容请重启试试从开始菜单打开,点…

【Git】大大大问题之syntax error near unexpected token `(‘ 的错误解决办法

话不多说,先上图: 如图,因为在linux环境里,文件路径中含有括号(),因此报错! 解决办法 等同于 :linux下解决bash: syntax error near unexpected token (’ 的错误&am…

【中危】Apache Airflow Drill Provider < 2.4.3 存在任意文件读取漏洞

漏洞描述 Apache Airflow Drill Provider 是 Apache Airflow 项目中的一个模块,用于提供与 Apache Drill 数据引擎的集成。 2.4.3 之前版本中,由于 drill#create_engine 方法未对用户传入的 url 参数进行过滤,攻击者可构造恶意的查询参数&a…

MYSQL-习题掌握

文章目录 SQL基本操作1 设计表操作1.1 关系表字段1.2 关系表创建1.3 关系表数据1.4 关系表关系 2 SQL操作2.1 SQL 1-102.2 SQL 11-202.3 SQL 21-302.4 SQL 31-402.5 SQL 41-50 SQL基本操作 1 设计表操作 1.1 关系表字段 1 学生表 student s_ids_names_births_sex学生编号学…

第二部分:AOP

一、AOP简介 AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构。 AOP是OOP(面向对象编程)的进阶版。 作用:在不改变原始设计的基础上为其进行功能增强。 spring理念&#x…

STM32入门——USART

江科大STM32学习记录 通信接口 通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统通信协议:制定通信的规则,通信双方按照协议规则进行数据收发 串口通信 串口是一种应用十分广泛的通讯接口,串口成本低、…