Skip to content

基于 Kubernetes 的云原生 DevOps 第 11 章 安全与备份

🏷️ Kubernetes 《基于 Kubernetes 的云原生 DevOps》


If you think technology can solve your security problems, then you don't understand the problems and you don't understand the technology.

-- Bruce Schneier, Applied Cryptography


11.1 访问控制与权限

按集群管理访问

最简单且最有效的保护 Kubernetes 集群的方法之一就是限制哪些人可以访问集群。通常由两类人需要访问 Kubernetes 集群:集群运维人员和应用程序开发人员。

基于角色的访问控制

还有一种管理访问的方法是使用 Kubernetes 的基于角色的访问控制(RBAC)系统来控制哪些人可以在集群内执行特定的操作。

RBAC 的目的是将特定的权限赋给特定的用户。

关于 RBAC,需要了解的头等大事就是记住你必须启用它。然而,集群是否启用了这个选项取决于你的云提供商或 Kubernetes 的安装程序。

可以通过以下命令确认集群是否启用了 RBAC :

bash
kubectl describe pod -n kube-system -l component=kube-apiserver

JiaJia:

PowerShell 中使用 findstr 过滤输出。

powershell
PS C:\k8s> kubectl describe pod -n kube-system -l component=kube-apiserver | findstr authorization-mode
      --authorization-mode=Node,RBAC

如果 --authorization-mode 不包含 RBAC,则表明集群未启用 RBAC。如果没有 RBAC,则任何有权访问集群的人都可以执行任何操作,包括运行任意代码或删除工作负载。

RBAC 是如何工作的呢?首先要理解几个最重要的概念:用户角色以及角色绑定

角色(Role)描述了一组特定的权限。Kubernetes 包含一些预定义的角色(例如 cluster-adminview)。

你可以定义命名空间级别的角色(使用 Role 对象),或定义整个集群级别的角色(使用 ClusterRole 对象)。

示例:定义一个可以读取任何命名空间中机密数据的权限。

yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

将角色绑定要用户

使用角色绑定(Role Binding)将角色关联到用户。像角色一样,可以创建能应用到特定命名空间的 RoleBinding 对象,或能应用到集群级别的 ClusterRoleBinding 对象。

示例:服务 daisy 用户 demo 命名空间中的 edit 角色。

yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: daisy-edit
  namespace: demo
subjects:
- kind: User
  name: daisy
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: edit
  apiGroup: rbac.authorization.k8s.io

在 Kubernetes 中,权限是累加的。可以通过角色以及角色绑定为用户添加权限。但你不能减去某个人已有的权限。

我们需要哪些角色?

预定义的角色 cluster-admineditview 就可以满足大多数需求。你也可以创建组织内特定人员或工作岗位的角色(例如,开发人员角色),也可以创建某个团队的角色(例如,质量保证团队或安全团队)。

可以通过 kubectl describe 命令查看某个角色拥有哪些权限:

bash
kubectl describe clusterrole/edit

JiaJia:

这是 minikube Kubernetes 集群 edit 角色的权限设置:

powershell
PS C:\k8s> kubectl describe clusterrole/edit
Name:         edit
Labels:       kubernetes.io/bootstrapping=rbac-defaults
              rbac.authorization.k8s.io/aggregate-to-admin=true
Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
  Resources                                    Non-Resource URLs  Resource Names  Verbs
  ---------                                    -----------------  --------------  -----
  configmaps                                   []                 []              [create delete deletecollection patch update get list watch]
  events                                       []                 []              [create delete deletecollection patch update get list watch]
  persistentvolumeclaims                       []                 []              [create delete deletecollection patch update get list watch]
  pods                                         []                 []              [create delete deletecollection patch update get list watch]
  replicationcontrollers/scale                 []                 []              [create delete deletecollection patch update get list watch]
  replicationcontrollers                       []                 []              [create delete deletecollection patch update get list watch]
  services                                     []                 []              [create delete deletecollection patch update get list watch]
  daemonsets.apps                              []                 []              [create delete deletecollection patch update get list watch]
  deployments.apps/scale                       []                 []              [create delete deletecollection patch update get list watch]
  deployments.apps                             []                 []              [create delete deletecollection patch update get list watch]
  replicasets.apps/scale                       []                 []              [create delete deletecollection patch update get list watch]
  replicasets.apps                             []                 []              [create delete deletecollection patch update get list watch]
  statefulsets.apps/scale                      []                 []              [create delete deletecollection patch update get list watch]
  statefulsets.apps                            []                 []              [create delete deletecollection patch update get list watch]
  horizontalpodautoscalers.autoscaling         []                 []              [create delete deletecollection patch update get list watch]
  cronjobs.batch                               []                 []              [create delete deletecollection patch update get list watch]
  jobs.batch                                   []                 []              [create delete deletecollection patch update get list watch]
  daemonsets.extensions                        []                 []              [create delete deletecollection patch update get list watch]
  deployments.extensions/scale                 []                 []              [create delete deletecollection patch update get list watch]
  deployments.extensions                       []                 []              [create delete deletecollection patch update get list watch]
  ingresses.extensions                         []                 []              [create delete deletecollection patch update get list watch]
  networkpolicies.extensions                   []                 []              [create delete deletecollection patch update get list watch]
  replicasets.extensions/scale                 []                 []              [create delete deletecollection patch update get list watch]
  replicasets.extensions                       []                 []              [create delete deletecollection patch update get list watch]
  replicationcontrollers.extensions/scale      []                 []              [create delete deletecollection patch update get list watch]
  ingresses.networking.k8s.io                  []                 []              [create delete deletecollection patch update get list watch]
  networkpolicies.networking.k8s.io            []                 []              [create delete deletecollection patch update get list watch]
  poddisruptionbudgets.policy                  []                 []              [create delete deletecollection patch update get list watch]
  deployments.apps/rollback                    []                 []              [create delete deletecollection patch update]
  deployments.extensions/rollback              []                 []              [create delete deletecollection patch update]
  pods/attach                                  []                 []              [get list watch create delete deletecollection patch update]
  pods/exec                                    []                 []              [get list watch create delete deletecollection patch update]
  pods/portforward                             []                 []              [get list watch create delete deletecollection patch update]
  pods/proxy                                   []                 []              [get list watch create delete deletecollection patch update]
  secrets                                      []                 []              [get list watch create delete deletecollection patch update]
  services/proxy                               []                 []              [get list watch create delete deletecollection patch update]
  bindings                                     []                 []              [get list watch]
  endpoints                                    []                 []              [get list watch]
  limitranges                                  []                 []              [get list watch]
  namespaces/status                            []                 []              [get list watch]
  namespaces                                   []                 []              [get list watch]
  persistentvolumeclaims/status                []                 []              [get list watch]
  pods/log                                     []                 []              [get list watch]
  pods/status                                  []                 []              [get list watch]
  replicationcontrollers/status                []                 []              [get list watch]
  resourcequotas/status                        []                 []              [get list watch]
  resourcequotas                               []                 []              [get list watch]
  services/status                              []                 []              [get list watch]
  controllerrevisions.apps                     []                 []              [get list watch]
  daemonsets.apps/status                       []                 []              [get list watch]
  deployments.apps/status                      []                 []              [get list watch]
  replicasets.apps/status                      []                 []              [get list watch]
  statefulsets.apps/status                     []                 []              [get list watch]
  horizontalpodautoscalers.autoscaling/status  []                 []              [get list watch]
  cronjobs.batch/status                        []                 []              [get list watch]
  jobs.batch/status                            []                 []              [get list watch]
  endpointslices.discovery.k8s.io              []                 []              [get list watch]
  daemonsets.extensions/status                 []                 []              [get list watch]
  deployments.extensions/status                []                 []              [get list watch]
  ingresses.extensions/status                  []                 []              [get list watch]
  replicasets.extensions/status                []                 []              [get list watch]
  ingresses.networking.k8s.io/status           []                 []              [get list watch]
  poddisruptionbudgets.policy/status           []                 []              [get list watch]
  serviceaccounts                              []                 []              [impersonate create delete deletecollection patch update get list watch]

保护集群管理员的权限

在决定哪些人拥有 cluster-admin 角色的权限是请务必谨慎。这是集群上的超级用户,相当于 Unix 系统上的 root 用户。这个角色可以执行任何操作。

切勿将此角色授予非运维人员的用户,尤其不能赋给公开给互联网的应用程序所用的服务账号(例如 Kubernetes 仪表板)。

应用程序与部署

在 Kubernetes 中运行的应用程序通常不需要任何 RBAC 权限。除非另行指定,否则所有 Pod 都将使用命名空间的 default 服务账号运行,而这个账号没有关联任何角色。

应用程序需要访问 Kubernetes API 时(例如监视工具),为了这个应用程序创建专用的服务账号,然后绑定必要的角色(例如 view),并限制在特定的命名空间。

关于应用程序部署,最安全的做法是只允许使用持续部署工具来部署应用程序。它使用专用的服务账号(该账号拥有在特定命名空间中创建和删除 Pod 的权限)。edit 角色是理想之选。

最佳实践

确保所有集群都启用了 RBAC。仅将 cluster-admin 权限授予真正需要掌控一切的用户。如果你的应用程序需要访问集群资源,则请创建专用的服务账号并绑定一个角色,该角色仅拥有所需命名空间中所需的权限。

RBAC 故障排除

可以检查 API 服务器的日志并确认缺少哪些权限。

bash
kubectl logs -n kube-system -l component=kube-apiserver | grep "RBAC DENY"

RBAC 以复杂而著称,但实际上并非如此。只需授予用户所需的最低权限,并确保 cluster-admin 安全即可。

11.2 安全扫描

Clair

Clair 是 CoreOS 项目开发的开源容器扫描程序。它可以在容器镜像实际运行之前进行静态分析,看看其中是否包含任何已知不安全的软件或版本。

你不应该无条件的信任基础镜像。

Aqua

Aqua 的容器安全平台(Container Security Platform)是一款全方位服务的商业容器安全产品,可以帮助组织扫描容器中的漏洞、恶意软件和可疑活动,并提供执行策略与合规的支持。

Aqua 还提供了一个免费使用的工具 MicorScanner,将其添加到容器镜像中,就可以根据 Aqua 容器安全平台所有的数据库,扫描已安装程序包中是否包含已知的漏洞。

JiaJia:

项目地址显示 MicroScanner 已经弃用了,取而代之的是 Trivy

Anchore Engine

Anchore Engine 是一款开源的容器镜像扫描工具,它不仅可以扫描已知漏洞,还可以识别容器中所有的物料清单,包括库、配置文件和文件权限等。

最佳实践

不要运行来源不可信的容器,也不要运行内容不明的容器。在所有容器(即使是自己构建的容器)上运行 Clair 或 MIcroScanner 等扫描工具,以确保没有任何一个基础镜像或依赖项中存在已知漏洞。

11.3 备份

Kubernetes 需要备份吗?

需要。尽管云提供商提供了所谓的高可用性卷,但这并不等同于备份。

复制( replication )不是备份。复制既不能防止应用程序因配置错误而覆盖数据,也不能防止运维人员使用错误的环境变量运行命令,或在删除开发数据库时意外删除生产数据库。

备份 etcd

Kubernetes 将所有状态都存储在 etcd 数据库中,因此任何故障或数据丢失都可能引发灾难。这就是为什么我们建议你使用可确保 etcd 和控制平面可用性的托管服务的理由。

最佳实践

使用提供了 etcd 集群构成和备份的托管服务或一站式服务提供商来运行主节点。如果你自己动手运行集群,则必须确保你清楚自己的操作。弹性 etcd 管理是一项专业工作,一旦出错就可能酿成严重的后果。

备份资源状态

建议你坚持以声明式的方式来管理 Kubernetes 资源,并将相应的 YAML 清单或 Helm Chart 保持在版本控制中。

从理论上讲,只需检出相关的版本控制库,并应用其中的所有资源,就应该能够重建集群工作负载的完整状态。当然,这仅限于理论。

备份集群状态

确保集群状态不变的方法之一就是创建集群的快照,以供稍后出现问题时参考。

大小灾害

一般不太可能会丢失整个集群,更有可能发生的是一些小的灾害:意外删除了命名空间,或不小心关闭了部署。

Velero

Velero(原名 Ark)是一款免费的开源工具,可以备份和还有集群状态以及持久性数据。

Velero 需要在集群中运行,并连接到你选择的云存储服务。

Velero 也可以用于将资源和数据从一个集群迁移到另一个,这个过程有时也称为直接迁移(Lift-and-Shift)。

最佳实践

使用 Velero 定期备份集群状态和持久性数据,至少每晚一次。至少每月进行一次还原测试。

11.4 监控集群状态

本节只介绍 Kubernetes 本身的监控,即集群的运行状况、各个节点的状态、集群的利用率及其工作负载的状况。

Kubectl

kubectl 还可以报告有关集群组件状态的信息。

控制平面状态

kubectl get componentstatuses 命令(简写 kubectl get cs )可以提供有关控制平面组件(调度器、控制器管理器等)运行状态的信息:

powershell
PS C:\k8s> kubectl get componentstatuses
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME                 STATUS      MESSAGE                                                                                       ERROR
scheduler            Unhealthy   Get "http://127.0.0.1:10251/healthz": dial tcp 127.0.0.1:10251: connect: connection refused
etcd-0               Healthy     {"health":"true","reason":""}
controller-manager   Healthy     ok

如果发现任何控制平面组件未处于 Healthy 状态,则需要立即修复。

节点状态

kubectl get nodes 列出集群中所有的节点,并报告节点的状态和 Kubernetes 版本。

powershell
PS C:\k8s> kubectl get nodes
NAME       STATUS   ROLES                  AGE    VERSION
minikube   Ready    control-plane,master   162d   v1.22.3

如果节点的状态为 NotReady ,则表明有问题。

使用 kubectl describe node 命令获取节点更多信息。

工作负载

可以使用 --all-namespaces 标志查看集群所有命名空间的 Pod。

powershell
PS C:\k8s> kubectl get pods --all-namespaces
NAMESPACE              NAME                                         READY   STATUS    RESTARTS       AGE
default                demo-55654d8789-fp28v                        1/1     Running   0              24h
kube-system            coredns-78fcd69978-2s4jv                     1/1     Running   11 (25h ago)   162d
kube-system            etcd-minikube                                1/1     Running   11 (25h ago)   162d
kube-system            kube-apiserver-minikube                      1/1     Running   11 (25h ago)   162d
kube-system            kube-controller-manager-minikube             1/1     Running   11 (25h ago)   162d
kube-system            kube-proxy-zwsz8                             1/1     Running   11 (25h ago)   162d
kube-system            kube-scheduler-minikube                      1/1     Running   11 (25h ago)   162d
kube-system            storage-provisioner                          1/1     Running   23 (25h ago)   162d
kubernetes-dashboard   dashboard-metrics-scraper-5594458c94-bncc8   1/1     Running   11 (25h ago)   162d
kubernetes-dashboard   kubernetes-dashboard-654cf69797-dr2l2        1/1     Running   22 (25h ago)   162d

可以通过这个结果大致了解集群中正在运行的所有 Pod,以及 Pod 级别的问题。如果 Pod 未处于 Running 状态,则需要进一步调查。

READY 列显示 Pod 中实际运行的容器书(以及配置的容器数之比)。

当容器崩溃时,Kubernetes 会不断尝试重新启动它,但等待的间隔会逐步拉长,刚开始的时候是 10 秒,每次增加一倍,最多为 5 分钟。这种策略称为指数补偿(Exponential backoff,因此状态消息为 CrashLoopBackOff

CPU 和内存利用率

kubectl top 命令可以提供集群的概况。

对于节点(kubectl top node),显示每个节点的 CPU 和内存容量,以及每个节点当前的利用率。

对于 Pod(kubectl top pod),显示每隔指定的 Pod 中 CPU 和内存的利用率。

JiaJia:

这两个命令执行都失败了,根据命令的帮助文档,应该是 Metrics Server 配置的不对导致的。

powershell
PS C:\k8s> kubectl top node
error: Metrics API not available
PS C:\k8s> kubectl top pod
error: Metrics API not available
powershell
PS C:\k8s> kubectl top
Display Resource (CPU/Memory) usage.

 The top command allows you to see the resource consumption for nodes or pods.

 This command requires Metrics Server to be correctly configured and working on the server.

Available Commands:
  node          Display resource (CPU/memory) usage of nodes
  pod           Display resource (CPU/memory) usage of pods

Usage:
  kubectl top [flags] [options]

Use "kubectl <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).

云提供商控制台

如果你使用的是云提供商提供的托管 Kubernetes 服务,则可以访问基于 Web 的控制台,其中提供了有关集群、节点以及工作负载的信息。

Kubernetes 仪表板

Kubernetes 仪表板是 Kubernetes 集群基于 Web 的用户界面。如果你使用的时自己运行的 Kubernetes 集群(而不是使用托管服务),则可以运行 Kubernetes 仪表板,以获取与托管服务控制台差不多的信息。

由于仪表板公开了大量有关集群和工作负载的信息,因此相应的保护工作非常重要,千万不要将其公开到互联网。

最佳实践

若非必要请不要运行 Kubernetes 仪表板。如果运行,则请确保仪表板只有最低权限,而且千万不要将其公开到互联网。你应该通过 kubectl proxy 访问仪表板。

Weave Scope

Weave Scope 是一款出色的可视化与监视集群的工具,可显示节点、容器以及进程的实时映射。还可以使用 Scope 查看指标和元数据,甚至可以启动或停止容器。

kube-ops-view

你可以利用它直观地了解集群地情况,包括有哪些节点、每个节点上的 CPU 和内存的利用率、每个节点运行的 Pod 数以及这些 Pod 的状态。

node-problem-detector

node-problem-detector 是一款 Kubernetes 插件,能够检测并报告各种节点级别的问题,包括硬件问题、CPU 或内存错误、文件系统损坏以及无响应的容器运行时。

目前,node-problem-detector 通过将事件发送到 Kubernetes API 来报告问题。

11.5 深入阅读

有关 Kubernetes 安全的更多介绍,可以阅读安全专家 Liz Rice 和 Michael Hausenblas 撰写的《Kubernetes Security》(O'Reilly 出版)。

11.6 小结

  • 基于角色的访问控制(RBAC)可以让你更为细致地管理 Kubernetes 的权限。请确保启用了 RBAC,并使用 RBAC 角色赋予特定用户和应用程序执行工作所需的最低特权。
  • 容器并不是免于安全和恶意软件问题的灵丹妙药。你需要使用扫描工具检查生产环境中运行的所有容器。
  • Kubernetes 很强大,但你仍然需要备份。Velero 不仅可以备份数据和集群状态,而且也可用于集群之间的迁移。
  • kubectl 是一款强大的工具,可用于检查和报告集群及其工作负载的方方面面。你需要熟悉 kubectl 的使用,因为你们将有很多共处的美好时光。
  • 使用 Kubernetes 提供商的 Web 控制台和 kube-ops-view 可以直观地查看集群地状况。如果你使用 Kubernetes 仪表板,则请像使用云平局和加密密钥一般严格地保护它。