25、Kubernetes 安全与部署实践指南

Kubernetes 安全与部署实践指南

1. 秘密管理与 GitOps

在 Kubernetes 中,使用 Secret 对象来管理敏感信息是一个重要的实践。以下是一个简单的 Deployment 示例,展示了如何将 Secret 挂载到容器中:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: timeserver
spec:
  replicas: 1
  selector:
    matchLabels:
      pod: timeserver-pod
  template:
    metadata:
      labels:
        pod: timeserver-pod
    spec:
      containers:
      - name: timeserver-container
        image: docker.io/wdenniss/timeserver:4
        volumeMounts:
        - name: secret-volume
          mountPath: "/etc/config"
          readOnly: true
      volumes:
      - name: secret-volume
        secret:
          secretName: secret-files

要验证是否一切正常,可以按照以下步骤操作:
1. 创建 Deployment 和 Secret。
2. 运行 kubectl get pods ,获取一个 Pod 的名称。
3. 使用 kubectl exec 命令列出挂载目录的内容:

$ kubectl exec POD_NAME -- ls /etc/config
example.key

现在,你的代码可以像访问系统中的其他文件一样访问这个文件。

然而,仅仅使用 Secret 是不够的,还需要考虑如何安全地存储它们。以下是几种不同的存储方法,按复杂度递增排列:
- 单独的仓库 :创建一个单独的配置仓库来存储 Secret,限制访问用户数量。可以将其放在云提供商的生产资源所在的位置,并使用与生产环境相同的访问控制。这样,即使账户被攻破,也不会增加额外的访问风险。
- 密封秘密(Sealed Secrets) :Sealed Secrets 项目使用主密钥对所有 Secret 进行编码。虽然仍然存在主密钥的存储问题,但编码后的 Secret 可以包含在主配置仓库中,享受配置即代码的所有好处,如回滚。
- 秘密服务 :运行一个单独的服务来将 Secret 注入到集群中。HashiCorp 的 Vault 是一个非常流行的实现,并且可以开源运行。

2. Kubernetes 安全概述

Kubernetes 的安全是一个广泛的领域,对于开发者和集群操作员来说,确保集群的安全和更新是一项关键责任。以下是一些关键的安全主题:
- 保持集群和节点的更新,以修复已知的漏洞。
- 使用 PodDisruptionBudget 管理与更新相关的中断。
- 使用 DaemonSet 在每个节点上部署代理。
- 配置 Pod 的安全上下文。
- 以非根用户身份构建和运行容器。
- 使用准入控制器修改和/或验证 Kubernetes 对象。
- 使用内置的 Pod 安全准入在命名空间中强制执行安全标准。
- 使用基于角色的访问控制(RBAC)控制用户对命名空间的访问。

3. 保持集群和容器的更新

Kubernetes 有很大的攻击面,包括 Linux 内核、Kubernetes 软件、容器及其依赖项。因此,保持这些组件的更新至关重要。

3.1 集群和节点更新

Kubernetes 操作员的一项关键任务是确保集群和节点的更新。这有助于减轻 Kubernetes 和节点操作系统中的已知漏洞。更新集群和节点不是 Kubernetes API 的一部分,需要参考具体的 Kubernetes 平台文档。

以 Google Kubernetes Engine(GKE)为例,保持更新很简单。只需加入以下三个发布通道之一:
- 稳定版(Stable) :安全补丁会快速推出,新功能的推出速度较慢。
- 常规版(Regular) :安全补丁和新功能的推出速度适中。
- 快速版(Rapid) :安全补丁和新功能的推出速度最快。

加入发布通道后,集群版本和节点会自动保持更新。不推荐使用旧的“静态版本”选项,因为需要手动跟踪更新。

3.2 容器更新

除了集群和节点更新,还需要定期更新容器。安全漏洞经常出现在基础镜像的组件中,因此需要定期重建和更新容器。许多开发者和企业使用漏洞扫描器(CVE 扫描器)来检查已构建的容器中是否存在报告的漏洞,以便优先进行重建和部署。

在更新容器时,应指定包含最新修复的基础镜像。通常,只指定基础镜像的次要版本,而不是特定的补丁版本。例如,对于 Python 基础镜像,可以选择 3.10-bullseye 这样的版本,既能获得补丁更新,又能避免重大更改。

以下是一些选择基础镜像版本的建议:
| 版本选择 | 优点 | 缺点 |
| ---- | ---- | ---- |
| 主要.次要版本(如 3.10-bullseye) | 自动获得补丁更新,避免重大更改 | 需要关注支持终止时间并迁移 |
| 主要版本(如 3-bullseye) | 更长的支持时间 | 有轻微的中断风险 |
| 最新版本(latest) | 从安全角度来看很好 | 中断风险极高,不推荐 |

为了减少容器更新的频率,可以构建极其轻量级的容器,只包含运行应用程序所需的最小代码和依赖项。Google 的 distroless 项目提供了超轻量级的运行时容器,可以帮助实现这一目标。以下是一个使用 distroless 构建 Java 容器的示例:

FROM openjdk:11-jdk-slim-bullseye AS build-env
COPY . /app/examples
WORKDIR /app
RUN javac examples/*.java
RUN jar cfe main.jar examples.HelloJava examples/*.class
FROM gcr.io/distroless/java11-debian11
COPY --from=build-env /app /app
WORKDIR /app
CMD ["main.jar"]
4. 处理更新中断

在进行更新时,不可避免地会删除和重新创建 Pod,这可能会对运行的工作负载造成影响。Kubernetes 提供了几种方法来减少这种影响:
- 就绪检查(Readiness Checks) :确保容器在准备好处理生产流量时才被认为是就绪的。如果没有设置就绪检查,Kubernetes 可能会在应用程序尚未初始化完成时就认为它已就绪,导致请求失败。
- 信号处理和优雅终止(Signal Handling and Graceful Termination) :在应用程序代码中处理 SIGTERM 事件,启动关闭过程,并设置足够长的优雅终止窗口( terminationGracePeriodSeconds ),以确保应用程序有足够的时间完成终止。
- 滚动更新(Rolling Updates) :在更新 Deployment 或 StatefulSet 中的容器时,使用滚动更新策略,分批更新 Pod,同时保持应用程序的可用性。对于 Deployment,确保配置 maxSurge 参数,通过临时增加 Pod 副本数来进行滚动更新,这样更安全。
- Pod 中断预算(Pod Disruption Budgets,PDB) :当节点更新时,使用 PDB 来确保在中断期间,不会有超过指定数量或百分比的 Pod 不可用。以下是一个 PDB 的示例:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: timeserver-pdb
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      pod: timeserver-pod

部署这个 PDB 到集群中,将确保在任何中断期间,不会有超过 1 个 Pod 不可用。

为了确保应用程序在部署更新和集群更新期间都能保持可用,需要同时配置滚动更新和 PDB。

5. 使用 DaemonSet 部署节点代理

DaemonSet 是一种 Kubernetes 工作负载类型,用于在每个节点上运行一个 Pod。通常用于集群操作目的,如日志记录、监控和安全。以下是一些 DaemonSet 的常见用途:
- 读取节点上的日志并上传到中央日志解决方案。
- 查询 kubelet API 获取性能指标。
- 监控容器和主机行为。

以下是一个简单的 DaemonSet 示例,用于读取节点上的日志并输出到标准输出:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: logreader
spec:
  selector:
    matchLabels:
      ds: logreaderpod
  template:
    metadata:
      labels:
        ds: logreaderpod
    spec:
      containers:
      - image: ubuntu
        command: ["tail", "-f", "/var/log/kube-proxy.log"]
        name: logreadercontainer
        resources:
          requests:
            cpu: 50m
            memory: 100Mi
            ephemeral-storage: 100Mi
        volumeMounts:
        - name: logpath
          mountPath: /var/log
          readOnly: true
      volumes:
      - hostPath:
          path: /var/log
        name: logpath

创建 DaemonSet:

$ kubectl create -f 12.2_DaemonSet/logreader.yaml
daemonset.apps/logreader created

当 Pod 准备好后,可以查看其日志输出:

$ kubectl get pods
NAME              READY   STATUS    RESTARTS   AGE
logreader-2nbt4   1/1     Running   0          4m14s
$ kubectl logs -f logreader-2nbt4
I0125 01:39:28.576504       1 proxier.go:845] "Syncing iptables rules"
I0125 01:39:28.615108       1 proxier.go:812] "SyncProxyRules complete"
elapsed="38.697941ms"
6. Pod 安全上下文

PodSpec 中的 securityContext 属性用于定义 Pod 及其容器的安全属性。以下是两个不同的示例:
- 请求特权的 Pod :如果 Pod 需要执行某种管理功能,可以请求节点上的特权(root 访问):

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: admin-workload
spec:
  selector:
    matchLabels:
      name: admin-app
  template:
    metadata:
      labels:
        name: admin-app
    spec:
      containers:
      - name: admin-container
        image: ubuntu
        securityContext:
          privileged: true
  • 受限特权的 Pod :作为非管理应用程序的开发者,更可能使用这些属性来限制 Pod 的功能,以降低风险。以下是一个以非根用户身份运行且不能提升特权的 Pod 示例:
apiVersion: v1
kind: Pod
metadata:
  name: timeserver-demo
  labels:
    app: timeserver
spec:
  containers:
  - name: timeserver-container
    image: wdenniss/timeserver2:latest
    securityContext:
      runAsNonRoot: true
      runAsUser: 1001
      allowPrivilegeEscalation: false
      capabilities:
        drop:
          - ALL

默认情况下,任何 Pod 都可以请求它想要的任何功能,甚至是 root 访问(除非 Kubernetes 平台进行了限制)。作为集群操作员,可能需要限制这种行为,以避免任何具有 kubectl 访问权限的人获得 root 特权。此外,建议不要以 root 用户身份运行容器,这可以通过 runAsNonRoot: true 配置来强制执行。

Kubernetes 安全与部署实践指南

7. 准入控制器与 Pod 安全准入

准入控制器是 Kubernetes 中的一个重要特性,用于修改和/或验证 Kubernetes 对象。它们在对象被持久化到 API 服务器之前拦截请求,并可以根据预定义的规则进行处理。

内置的 Pod 安全准入是一种特殊的准入控制器,用于在命名空间中强制执行安全标准。通过配置 Pod 安全准入,可以确保只有符合特定安全策略的 Pod 才能在命名空间中创建。

以下是使用 Pod 安全准入的一般步骤:
1. 定义安全策略 :创建一个或多个 Pod 安全标准(PodSecurityStandard),定义允许的 Pod 配置。例如,可以定义一个严格的策略,禁止以根用户身份运行 Pod。
2. 应用策略到命名空间 :将定义的安全策略应用到特定的命名空间。可以使用 PodSecurityConfiguration 资源来完成这个操作。
3. 验证和管理 :在命名空间中创建 Pod 时,Pod 安全准入会验证 Pod 是否符合应用的安全策略。如果不符合,请求将被拒绝。

# 示例:定义一个 Pod 安全标准
apiVersion: security.openshift.io/v1
kind: PodSecurityStandard
metadata:
  name: restricted
spec:
  allowPrivilegeEscalation: false
  defaultAllowPrivilegeEscalation: false
  fsGroup:
    ranges:
      - max: 65535
        min: 1
    rule: MustRunAs
  runAsUser:
    rule: MustRunAsNonRoot
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    ranges:
      - max: 65535
        min: 1
    rule: MustRunAs
  volumes:
    - configMap
    - downwardAPI
    - emptyDir
    - persistentVolumeClaim
    - projected
    - secret

# 示例:将策略应用到命名空间
apiVersion: security.openshift.io/v1
kind: PodSecurityConfiguration
metadata:
  name: my-namespace-config
spec:
  namespaces:
    - my-namespace
  standards:
    - restricted
8. 基于角色的访问控制(RBAC)

基于角色的访问控制(RBAC)是 Kubernetes 中用于控制用户对命名空间和资源的访问的机制。通过 RBAC,可以定义不同的角色和角色绑定,从而精确地控制用户可以执行的操作。

以下是 RBAC 的基本概念和操作步骤:

8.1 角色和集群角色
  • 角色(Role) :用于在单个命名空间内定义一组权限。例如,可以创建一个角色,允许用户在特定命名空间内创建和删除 Pod。
  • 集群角色(ClusterRole) :用于在整个集群范围内定义一组权限。集群角色可以应用于所有命名空间或特定的资源类型。
# 示例:创建一个角色
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: my-namespace
  name: pod-reader
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "watch", "list"]

# 示例:创建一个集群角色
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-reader
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "watch", "list"]
8.2 角色绑定和集群角色绑定
  • 角色绑定(RoleBinding) :将角色与用户、组或服务账户关联起来,授予他们在特定命名空间内的权限。
  • 集群角色绑定(ClusterRoleBinding) :将集群角色与用户、组或服务账户关联起来,授予他们在整个集群范围内的权限。
# 示例:创建一个角色绑定
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: my-namespace
subjects:
  - kind: User
    name: jane
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

# 示例:创建一个集群角色绑定
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-nodes
subjects:
  - kind: User
    name: john
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: node-reader
  apiGroup: rbac.authorization.k8s.io
9. 总结

Kubernetes 提供了丰富的功能和工具来确保集群的安全和高效运行。为了充分利用这些功能,可以采取以下最佳实践:
- 使用命名空间 :将不同的环境(如生产和测试)和应用程序分隔开来,提高管理效率和安全性。
- 配置即代码 :将 Kubernetes 配置存储在代码仓库中,像管理代码一样管理配置,进行同行评审和版本控制。
- 持续部署 :配置基于 Git 推送的持续部署管道,实现自动化部署和更新。
- 安全管理
- 保持集群和容器的更新,及时修复漏洞。
- 使用 PodDisruptionBudget 管理更新中断。
- 以非根用户身份构建和运行容器。
- 使用准入控制器和 RBAC 控制用户访问和资源使用。

通过遵循这些最佳实践,可以构建一个安全、稳定和高效的 Kubernetes 环境,为应用程序的部署和运行提供可靠的基础。

以下是一个简单的流程图,展示了 Kubernetes 安全管理的主要步骤:

graph LR
    A[集群和节点更新] --> B[容器更新]
    B --> C[处理更新中断]
    C --> D[部署节点代理]
    D --> E[配置 Pod 安全上下文]
    E --> F[使用准入控制器]
    F --> G[应用 RBAC]

通过以上步骤和方法,可以全面地管理 Kubernetes 集群的安全和部署,确保应用程序的稳定运行和数据的安全。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值