告别硬编码:手把手教你用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 的访问权限。
相关推荐
zyplanke2 小时前
Kubernetes(四):Service
云原生·容器·kubernetes·k8s
掘金-我是哪吒3 小时前
分布式微服务系统架构第169集:1万~10万QPS的查当前订单列表
分布式·微服务·云原生·架构·系统架构
attitude.x3 小时前
微服务架构的五大核心挑战与应对策略
微服务·云原生·架构
虚伪的空想家4 小时前
K8S删除命名空间卡住一直Terminating状态
云原生·容器·kubernetes·删除·卡顿·delete·命名空间
衍余未了6 小时前
k8s除了主server服务器可正常使用kubectl命令,其他节点不能使用原因,以及如何在其他k8s节点正常使用kubectl命令??
云原生·容器·kubernetes
To_再飞行6 小时前
K8s 存储配置资源
linux·云原生·容器·kubernetes
To_再飞行8 小时前
K8s 调度管理
linux·云原生·kubernetes
milanyangbo8 小时前
“卧槽,系统又崩了!”——别慌,这也许是你看过最通俗易懂的分布式入门
分布式·后端·云原生·架构
大咖分享课8 小时前
系统越拆越乱?你可能误解了微服务的本质!
微服务·云原生·架构