告别硬编码:手把手教你用Secrets保护CronJob的阿里云AK/SK

前言

在Kubernetes CronJob 详解:配置、原理与实践指南这篇文章中,我 将监控服务费用以及 ssl 证书的脚本部署在 k8s 中,但有一个问题,脚本中需要使用到阿里云的 AK/SK,目前是硬编码到脚本中的, 为了安全起见,我计划将 AK/SK 配置在 k8s 的 secret 中。

Secret 基础概念

为什么需要 Secret

将敏感数据直接写在容器镜像或配置文件中存在严重的安全风险。 Kubernetes 提供的 Secret 资源就是为解决这个问题而设计的。

Secret 是什么?

Secret 是 Kubernetes 中专门用于存储敏感数据的资源对象,特点包括:

  • 数据以 Base64 编码存储(注意:这不是加密!)
  • 支持多种数据类型(Opaque、docker-registry、TLS 等)
  • 可以通过卷挂载或环境变量注入到 Pod 中

Secret 与 ConfigMap 的区别

特性 Secret ConfigMap
数据类型 敏感信息 普通配置
存储方式 Base64 编码 明文
典型用途 密码、密钥 应用配置

创建 Secret 的多种方式

方法一: 通过 kubectl 命令行创建

从字面值创建:

ini 复制代码
kubectl create secret generic my-secret \
  --from-literal=username=my-user \
  --from-literal=password=my-password

这将创建一个名为 my-secret 的 Secret,其中包含两个键值对:username 和 password。

从文件创建:

ini 复制代码
kubectl create secret generic tls-cert \
  --from-file=tls.crt=./server.crt \
  --from-file=tls.key=./server.key

这将使用文件中的内容创建一个名为 tls-cert 的 Secret。

方法二:通过 YAML 文件定义

通过创建一个 YAML 文件来定义 Secret,然后使用 kubectl apply 或 kubectl create 命令来创建

yaml 复制代码
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  username: bXktdXNlcg==  # Base64 编码的 username
  password: bXktcGFzc3dvcmQ=  # Base64 编码的 password

username 和 password 值是通过 base64 编码的。

你可以使用 echo -n "bXktdXNlcg==" | base64 来获取 base64 编码的值。

恢复成原始值:

bash 复制代码
echo -n "bXktdXNlcg==" | base64 --decode

Secret 的使用方式

方式一:作为环境变量注入

将这些 Secret 值注入到容器的环境变量中

yaml 复制代码
containers:
- name: myapp
  image: myapp:latest
  env:
    - name: USERNAME
      valueFrom:
        secretKeyRef:
          name: my-secret
          key: username
    - name: PASSWORD
      valueFrom:
        secretKeyRef:
          name: my-secret
          key: password

这样,Pod 中的容器将会通过 Secret 中的 username 和 password 创建环境变量 USERNAME 和 PASSWORD。

方式二: 作为文件挂载

可以将 Secret 挂载到容器中的某个目录,容器可以通过文件访问 Secret 的内容。

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: mycontainer
      image: myimage
      volumeMounts:
        - name: secret-volume
          mountPath: /etc/secrets
          readOnly: true
  volumes:
    - name: secret-volume
      secret:
        secretName: my-secret

my-secret 被挂载到容器的 /etc/secrets 目录下。 容器内将可以通过文件访问这些 Secret 的值(例如 /etc/secrets/username 和 /etc/secrets/password)。

方式三:拉取私有镜像的 Secret

存储 Docker registry 的凭据,可以使用 Secret 来存储 Docker 配置文件。

ini 复制代码
kubectl create secret docker-registry my-registry-secret \
  --docker-server=my-docker-server.com \
  --docker-username=my-username \
  --docker-password=my-password \
  --docker-email=my-email@example.com

可以在 Kubernetes 配置中使用该 Secret 来拉取镜像:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  imagePullSecrets:
    - name: my-registry-secret
  containers:
    - name: mycontainer
      image: my-docker-server.com/myimage

这个配置中,Pod 使用 my-registry-secret 来从私有 Docker registry 拉取镜像。

方式四:使用 Secret 存储 TLS 证书

可以将 TLS 证书和密钥存储在 Secret 中,并在 Pod 中使用它们。

创建 TLS 证书 Secret:

css 复制代码
kubectl create secret tls my-tls-secret \
  --cert=/path/to/cert.crt \
  --key=/path/to/cert.key

挂载到 Pod 中:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: mycontainer
      image: myimage
      volumeMounts:
        - name: tls-volume
          mountPath: /etc/tls
          readOnly: true
  volumes:
    - name: tls-volume
      secret:
        secretName: my-tls-secret

这个配置中,Pod 将 my-tls-secret 挂载到 /etc/tls 目录下,容器可以使用证书和密钥文件。

Secret 的类型

实际案例:安全使用阿里云 AK/SK

场景

前言中有提到,需要在一个监控 Pod 中使用阿里云访问凭证,但不希望将 AK/SK 硬编码。

解决方案

  1. 在K8s集群中创建存储密钥的Secret:
ini 复制代码
kubectl create secret generic aliyun-credentials --namespace=kube-ops \
  --from-literal=access_key_id='AK123456' \
  --from-literal=access_key_secret='SK789012'
  1. 修改CronJob配置,配置CronJob引用Secret:
yaml 复制代码
apiVersion: batch/v1
kind: CronJob
metadata:
   namespace: kube-ops
   name: serverguard-job
spec:
   schedule: "0 10 * * *"
   concurrencyPolicy: Forbid
   startingDeadlineSeconds: 60
   successfulJobsHistoryLimit: 1
   failedJobsHistoryLimit: 1
   jobTemplate:
      spec:
         template:
            spec:
               containers:
                  - name: serverguard
                    image: /server-guard:latest
                    imagePullPolicy: Always
                    env:
                       - name: ALIYUN_ACCESS_KEY_ID
                         valueFrom:
                            secretKeyRef:
                               name: aliyun-credentials
                               key: access_key_id
                       - name: ALIYUN_ACCESS_KEY_SECRET
                         valueFrom:
                            secretKeyRef:
                               name: aliyun-credentials
                               key: access_key_secret
               restartPolicy: OnFailure
         ttlSecondsAfterFinished: 100
  1. 修改代码读取环境变量
ini 复制代码
import os  # 添加os模块导入
# ... 其他现有导入保持不变 ...


class Secret(NamedTuple):
    access_key_id: str
    access_key_secret: str


# 从环境变量读取密钥,移除硬编码
secret = Secret(
    access_key_id=os.environ.get('ALIYUN_ACCESS_KEY_ID'),
    access_key_secret=os.environ.get('ALIYUN_ACCESS_KEY_SECRET')
)


# ... 后续代码保持不变 ...
  1. 检查CronJob是否正常运行 手动创建job测试:
ini 复制代码
kubectl create job test-job --from=cronjob/serverguard-job -n kube-ops

这个命令是用来基于一个已经存在的 CronJob 创建一个 Job,用是从名为 serverguard-job 的 CronJob 中提取任务配置, 并在 kube-ops 命名空间中创建一个新的 Job,任务将立即执行一次,而不是定期运行。方便测试。

最后

到这里就告别了硬编码,使用 Kubernetes Secret 存储敏感数据,那现在有一个疑问,Secret 真的安全吗?

我们知道,Secret 的内容通常是以 Base64 编码存储的,因此它不能有效地防止恶意用户获取敏感数据。 如果攻击者有权限访问 Kubernetes 集群中的资源,他们可以轻松解码 Base64 编码的数据。

为了增加 Secret 的安全性,建议采取以下措施:

  • 启用 etcd 加密:确保 etcd 集群中的数据以加密形式存储,防止未经授权的访问。
  • 启用 RBAC 控制:通过 Role-Based Access Control(RBAC)机制,限制对 Secret 的访问权限,仅授权必要的用户或服务账号。
  • 实施严格的访问控制:确保只有授权的用户或服务账号才能访问 Secret,避免泄露敏感信息。 下一篇文章,就来探索如何使用 RBAC 控制 Secret 的访问权限。
相关推荐
陈陈CHENCHEN12 小时前
【Kubernetes】纯 IPv6 K8s 集群访问外部 IPv4 服务
云原生·容器·kubernetes
troy12813 小时前
如何在谷歌云(Google Cloud)上部署 Kubernetes 集群
云原生·容器·kubernetes
xiaoligangting13 小时前
太原岗亭款式齐全
云原生
程序员清风1 天前
Docker、Nginx 与 Kubernetes 部署 AI 后端服务
nginx·docker·kubernetes
Zhu7581 天前
离线二进制部署-Kubernetes-v1.36.4
容器·贪心算法·kubernetes
Zelman1 天前
测试金字塔与自动化分层
测试
程序猿阿越1 天前
containerd如何拉取镜像
后端·kubernetes·源码阅读
Elastic 中国社区官方博客1 天前
Kubernetes attributes processor v1:它对 EDOT Collector 意味着什么
java·大数据·elasticsearch·搜索引擎·贪心算法·kubernetes·全文检索
分布式存储与RustFS1 天前
升级 RustFS 二进制不停机:一条一条换,留一条退路
运维·云原生·开源·对象存储·分布式存储·s3·性能基准
xiaoligangting1 天前
太原防火岗亭
云原生