跳转至

使用 SealedSecret 对 secret 进行加密并配合 reloader 并对相应的 pod 进行 重启

本项目展示了如何在 GitOps 工作流程中使用 SealedSecret 安全管理 Kubernetes 集群中的敏感信息。通过非对称加密技术,实现敏感数据在 Git 仓库中密文存储,仅在集群内部解密,确保数据安全。并配合 reloader 自动化监控对相应的 pod 进行 重启。

1. SealedSecret 介绍和场景

官方文档

https://github.com/bitnami-labs/sealed-secrets/blob/main/README.md

安装

1. 部署 SealedSecret 控制器

kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.29.0/controller.yaml

2. 安装 kubeseal 客户端

用于本地加密 Secret:

Linux x86_64:

curl -OL "https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.29.0/kubeseal-0.29.0-linux-amd64.tar.gz"
tar -xvzf kubeseal-0.29.0-linux-amd64.tar.gz kubeseal
sudo install -m 755 kubeseal /usr/local/bin/kubeseal

3. 初始化 git 仓库

1. 创建 git 仓库
mkdir -p my-gitops-repo/{k8s-manifests/{deployments,services,sealed-secrets},secrets,certs,.github/workflows}
my-gitops-repo/
├── k8s-manifests/          # Kubernetes 资源定义
│   ├── deployments/        # Deployment 配置
│   │   └── app-deployment.yaml
│   ├── services/           # Service 配置
│   │   └── app-service.yaml
│   └── sealed-secrets/     # 加密后的 SealedSecret(提交到 Git)
│       └── db-credentials.yaml
├── secrets/                # 明文 Secret(本地开发,不提交)
│   └── db-credentials.yaml
├── certs/                  # 集群公钥证书(预导出,提交到 Git)
│   ├── prod-sealed.pub       # 生产环境证书
│   └── dev-sealed.pub        # 开发环境证书
└── .github/workflows/      # GitHub Actions 配置
    └── encrypt-secrets.yml
2. 预导出集群公钥证书

导出公钥证书(可在集群内或有访问权限的机器上执行)提交到 git

# 从生产环境集群导出证书
kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key -o jsonpath='{.items[0].data.tls\.crt}' | base64 -d > certs/prod-sealed.pub

提交证书到 Git

git add certs/
git commit -m "Add cluster certificates"
git push

2. 加密敏感信息流程

graph LR
A[明文 Secret] --> B[使用公钥加密]
B --> C[生成 SealedSecret]
C --> D[提交到 Git]
D --> E[部署到集群]
E --> F[控制器使用私钥解密]
F --> G[生成实际 Secret]

1. 创建明文 Secret(本地操作,不提交)


创建数据库凭证 Secret(本地操作,不提交到 Git)


1. 编码敏感数据(Base64)

在终端中执行以下命令,将明文密码和用户名转换为 Base64 编码:

# 编码 "test" 为 Base64
echo -n "test" | base64  # 输出: dGVzdA==

2. 创建 YAML 文件

使用 cat 命令写入配置(注意替换编码后的值):

cat > secrets/db-credentials.yaml << 'EOF'
apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
  namespace: default  # 可选,指定命名空间
type: Opaque
data:
  password: dGVzdA==  # 明文 "test" 的 Base64 编码
  username: dGVzdA==  # 明文 "test" 的 Base64 编码
EOF

3. 加密为 SealedSecret

# 获取集群公钥并加密 < 输入文件  > 输出文件,即加密后的 SealedSecret YAML
kubeseal --cert=certs/prod-sealed.pub --format=yaml < secrets/db-credentials.yaml > k8s-manifests/sealed-secrets/db-credentials.yaml

加密后的 db-credentials.yaml 内容如下(提交到 Git):

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: db-credentials
  namespace: default
spec:
  encryptedData:
    password: AgBmfy5dwYD8ZJe5... # 长密文
    username: AgBz... # 长密文
  template:
    metadata:
      name: db-credentials
      namespace: default

4. Deployment 配置

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  annotations:
    secret.reloader.stakater.com/reload: "db-credentials"  # 配置 Secret 变更时自动重启
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: docker.io/library/nginx:1.15-alpine
        ports:
        - containerPort: 80
        env:
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: username
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: password

---
apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

---

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: k8slinuxcdn1
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - test.k8s.linuxcdn.com
      secretName: k8s-linuxcdn-crt-secret
  rules:
  - host: test.k8s.linuxcdn.com
    http:
      paths:
      - path: /
        pathType: ImplementationSpecific
        backend:
          service:
            name: my-app-service
            port:
              number: 80

应用1:SealedSecret + Gitea + Argo CD + Reloader 完整实践方案

graph TD
    subgraph "开发者工作站"
    A[明文 Secret] --> B{操作类型}
    B -->|新建/修改| C[使用公钥加密]
    C --> D[生成 SealedSecret]
    D --> E[提交到 Git]
    B -->|直接编辑| F[修改 SealedSecret YAML]
    F --> E
    end

    subgraph "GitOps 流程"
    E --> G[Git 版本控制]
    G --> H[Argo CD/Flux 监控变更]
    H --> I[同步到集群]
    end

    subgraph "Kubernetes 集群"
    I --> J[部署 SealedSecret]
    J --> K[sealed-secrets 控制器]
    K --> L{是否需要解密?}
    L -->|是| M[使用私钥解密]
    L -->|否| N[保持 SealedSecret 状态]
    M --> O[创建/更新实际 Secret]
    O --> P[Reloader 检测 Secret 变更]
    P --> Q[触发 Deployment 滚动更新]
    Q --> R[新 Pod 加载最新配置]
    end

    subgraph "安全防护"
    S[公钥证书存储在 Git]:::safe
    T[私钥仅存在于集群]:::safe
    U[明文 Secret 不提交]:::safe
    V[所有变更可审计]:::safe
    end

    classDef safe fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px

以下是一个完整的 GitOps 工作流示例,展示如何使用 Gitea(代码托管)、Argo CD(部署工具)、SealedSecret(敏感信息管理)和 Reloader(自动重启应用)构建安全、自动化的 Kubernetes 部署流程。

1. 环境准备

1. 部署 Gitea

2. 部署 Argo CD

3. 部署 SealedSecret 控制器

4. 部署 Reloader

Gitea 仓库结构

创建一个名为 my-gitops-repo 的仓库,结构如下:


1. Argo CD 配置

1. 添加 Gitea 仓库

argocd repo add http://gitea.gitea.svc.cluster.local:3000/admin/my-gitops-repo.git \
  --username admin \
  --password admin123

2. 创建 Argo CD 应用

# argocd-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  destination:
    namespace: default
    server: https://kubernetes.default.svc
  project: default
  source:
    path: k8s-manifests/base
    repoURL: http://gitea.gitea.svc.cluster.local:3000/admin/my-gitops-repo.git
    targetRevision: HEAD
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

3. 应用配置到 Argo CD

kubectl apply -f argocd-app.yaml -n argocd

2. 完整工作流程

  1. 开发者工作流程

  2. 在本地修改明文 Secret (secrets/)

  3. 使用 kubeseal 加密为 SealedSecret
  4. 提交 SealedSecret 到 Gitea 仓库

  5. 自动化流程

  6. Argo CD 检测到仓库变更

  7. 自动同步 SealedSecret 到集群
  8. SealedSecret 控制器解密并创建实际 Secret
  9. Reloader 检测到 Secret 变更,触发 Deployment 滚动更新

  10. 安全检查

  11. 查看 Gitea 仓库:只包含加密后的 SealedSecret

  12. 尝试从集群获取 Secret:

    kubectl get secret db-credentials -o jsonpath='{.data.password}' | base64 -d
    # 输出应为正确的密码(supersecret)
    

3. 验证流程

1. 修改数据库密码

# 更新明文 Secret
echo -n "newpassword" | base64  # 生成新密码的 Base64 值

# 更新 secrets/db-credentials.yaml
data:
  password: bmV3cGFzc3dvcmQ=  # 新密码的 Base64 值

# 重新加密
kubeseal --cert=sealed-secrets.pem --format=yaml < secrets/db-credentials.yaml > k8s-manifests/base/sealed-secrets/db-credentials.yaml

# 提交到 Gitea
git add k8s-manifests/base/sealed-secrets/db-credentials.yaml
git commit -m "Update DB password"
git push

2. 观察自动化流程

  • 在 Argo CD UI 中查看同步状态
  • 观察 Deployment 的滚动更新
  • 验证应用是否使用新密码连接数据库

通过这种方式,你可以实现一个完全自动化、安全的 GitOps 工作流,确保敏感信息在整个生命周期中都得到加密保护。