k8s安全

k8s 安全性

Kubernetes 的安全性归纳为了以下四个方面:

  1. Infrastructure(基础设施) : 主要包括网络、存储、物理机、操作系统,等等
  2. Kubernetes 集群自身
  3. Containers(容器)及其运行时
  4. Applications(业务应用)

措施

1. 集群版本更新及 CVE 漏洞

时刻关注社区 Kubernetes 的版本更新,以及披露的 CVE 漏洞,及时地把 CVE 的修复方案变更到你的集群中去。

同时你需要保证跟社区的版本不要太脱节,跟社区保持 1 到 2 个大版本的差异

2. 保护好 Etcd 集群

Etcd 中保存着整个 Kubernetes 集群中最重要的数据,比如 Pod 信息、Secret、Token 等。一旦这些数据遭到攻击,造成的影响面非常巨大。我们必须确保 Etcd 集群的安全。

对于部署 Etcd 集群的各个节点,我们应该被授予最小的访问权限,同时还要尽量避免这些节点被用作其他用途。由于 Etcd 对数据的读写要求很高,这里磁盘最好是 SSD 类型。

Etcd 集群要配置双向 TLS 认证(mTLS),用于 Etcd 各个节点之间的通信。同时 APIServer 对 Etcd 集群的访问最好也要基于 mTLS。通过 Kubeadm 搭建出来的集群,默认已经采取这种配置方式。

3. 限制对 Kubernetes APIServer 的访问

APIServer 是整个 Kubernetes 的大脑,及流量入口,所有的数据都在此进行交互。Kubernetes 的安全机制也都是围绕着保护 APIServer 进行设计的,正如我们第 18 讲介绍的认证(Authentication)、鉴权(Authorization)和准入控制(Admission Control),这三大机制保护了 APIServer 的安全。

显而易见,APIServer 也必须得使用 TLS 进行通信,尽量不要开启不安全的 HTTP 方式,尤其是在云上的环境中,切记一定要关闭,你可以通过–insecure-port=0参数来关闭。

同时要避免使用 AlwaysAllow 这种鉴权模式,这种模式会允许所有请求。一般来说,我建议这么配置鉴权模式,即–authorization-mode=RBAC,Node。RBAC(基于角色的访问控制)会将传入的用户/组与一组绑定到角色的权限进行匹配。这些权限将 HTTP 请求的动作(GET,POST,DELETE)和 Kubernetes 内部各种资源对象,比如 Pod、Service 或者 Node,在命名空间或者集群范围内有机地结合起来,你可以回顾我们第 18 讲的内容,这里不再赘述。

4. 减少集群的端口暴露

当然你还需要尽可能减少集群的端口暴露。如下是 Kubernetes 各组件需要的端口,在使用的时候,可以限制只允许固定节点对这些端口的访问。

5. 限制对 Kubelet 的访问

Kubelet 上运行着我们的业务容器,同时还暴露了 10250 端口,可以用来查询容器,支持容器 exec,获取容器日志等功能。因此在生产级别的集群,我们要启用 Kubelet 身份验证和授权,同时关闭匿名访问–anonymous-auth=false。

6. 开启审计能力

APIServer 支持对所有的请求进行审计(Audit),你可以通过–audit-log-path来指定用来写入审计事件的日志文件路径,默认是不指定的。通过这个开启审计能力,再结合 RBAC,我们可以对整个集群的请求访问进行详细的监控和分析。

这个审计功能提供了与安全相关的,按时间顺序排列的记录集,每一个请求都会有对应的审计事件,记录着:

发生了什么?

什么时候发生的?

谁触发的?

活动发生在哪个(些)对象上?

在哪观察到的?

它从哪触发的?

活动的后续处理行为是什么?

通过这些审计事件,集群管理员可以很容易地分析出集群内的安全风险,以采取应对策略。

7. 通过 namespace 进行隔离

通过 namespace 来隔离工作负载和数据,比如区分不用的用户,不同的业务场景,以及一些关键的业务。你可以通过对这些 namespace 内的资源设置一些 RBAC 的规则,来进一步增强安全性。

8. 使用网络策略进行限制

Kubernetes 提供了基于 namespace 的网络策略(Network Policy),可以允许和限制不同 namespace 中的 Pod 互访。

网络策略通过网络插件来实现,所以你要使用这种能力,要选择支持 NetworkPolicy 的网络解决方案,比如 Calico、Cilium、Weave 等。

9. 容器镜像安全

容器的运行依赖容器的镜像,保证镜像安全是最基本的。要避免使用一些未知来源的镜像,同时自己构建镜像的时候,要使用安全的、确知的、官方的基础镜像。

同时,要定期地对镜像进行漏洞扫描,你可以使用 harbor-scanner-aqua、Clair 等工具对你的镜像中心、镜像进行扫描,来查找已知的漏洞。

除此之外,我们还要限制特权容器,避免在容器镜像中使用 root 用户,防止特权升级。

10. 应用程序的安全性

应用程序自身的安全性也很重要。如果你的应用程序要暴露给集群外部,可以使用入口控制器(Ingress Controller),比如 Nginx。

应用容器也要使用 TLS 进行通信,包括跟入口控制器之间的通信。不需要定期扫描源代码及依赖项,查找是否有新漏洞,还要持续测试你的应用程序,查看是否会受到攻击,比如 SQL 注入,DDoS 攻击等。

工具检测

https://github.com/aquasecurity/kube-bench

能帮助你排查 95% Kubernetes 集群的配置风险

备份恢复

master 节点

在 Master 节点上,我们运行着 Etcd 集群以及 Kubernetes 控制面的几大组件,比如 kube-apiserver、kube-controller-manager、kube-scheduler 和 cloud-controller-manager(可选)等。

在这些组件中,除了 Etcd,其他都是无状态的服务。只要保证 Etcd 的数据正常,其他几个组件不管出现什么问题,我们都可以通过重启或者新建实例来解决,并不会受到任何影响。因此我们只需要备份 Etcd 中的数据。

node 节点
主要对数据文件备份 eg: pv

备份

etcd 备份

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 0. 数据备份
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--key=/etc/kubernetes/pki/etcd/peer.key \
--cert=/etc/kubernetes/pki/etcd/peer.crt \
snapshot save ./new.snapshot.db
# 1. 查看 etcd 集群的节点
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/peer.crt \
--key=/etc/kubernetes/pki/etcd/peer.key \
member list
# 2. 停止所有节点上的 etcd!(注意是所有!!)
## 如果是 static pod,可以听过如下的命令进行 stop
## 如果是 systemd 管理的,可以通过 systemctl stop etcd
mv /etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/
# 3. 数据清理
## 依次在每个节点上,移除 etcd 数据
rm -rf /var/lib/etcd
# 4. 数据恢复
## 依次在每个节点上,恢复 etcd 旧数据
## 里面的 name,initial-advertise-peer-urls,initial-cluster=controlplane
## 等参数,可以从 etcd pod 的 yaml 文件中获取到。
ETCDCTL_API=3 etcdctl snapshot restore ./old.snapshot.db \
--data-dir=/var/lib/etcd \
--name=controlplane \
--initial-advertise-peer-urls=https://172.17.0.18:2380 \
--initial-cluster=controlplane=https://172.17.0.18:2380
# 5. 恢复 etcd 服务
## 依次在每个节点上,拉起 etcd 服务
mv /etc/kubernetes/etcd.yaml /etc/kubernetes/manifests/
systemctl restart kubelet

如果你的 Etcd 集群是运行在 Kubernetes 集群中的,你可以通过以下的定时 Job (CronJob) 来帮你自动化、周期性(如下的 YAML 文件中会每分钟对 Etcd 进行一次备份)地备份 Etcd 的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: backup
namespace: kube-system
spec:
# activeDeadlineSeconds: 100
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
# Same image as in /etc/kubernetes/manifests/etcd.yaml
image: k8s.gcr.io/etcd:3.2.24
env:
- name: ETCDCTL_API
value: "3"
command: ["/bin/sh"]
args: ["-c", "etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key snapshot save /backup/etcd-snapshot-$(date +%Y-%m-%d_%H:%M:%S_%Z).db"]
volumeMounts:
- mountPath: /etc/kubernetes/pki/etcd
name: etcd-certs
readOnly: true
- mountPath: /backup
name: backup
restartPolicy: OnFailure
hostNetwork: true
volumes:
- name: etcd-certs
hostPath:
path: /etc/kubernetes/pki/etcd
type: DirectoryOrCreate
- name: backup
hostPath:
path: /data/backup
type: DirectoryOrCreate

PV 备份

对于 PV 来讲,备份就比较麻烦了。Kubernetes 自身不提供存储能力,它依赖各个存储插件对存储进行管理和使用。因此对于存储的备份操作,尤其是 PV 的备份操作,我们需要依赖各个云提供商的 API 来做 snapshot。

但是上述对于 Etcd 和 PV 的备份操作并不是很方便,我推荐你通过Velero来备份 Kubernetes。Velero 功能强大,但是操作起来很简单,它可以帮你做到以下 3 点:

对 Kubernets 集群做备份和恢复。

对集群进行迁移。

对集群的配置和对象进行复制,比如复制到其他的开发和测试集群中去。

而且 Velero 还提供针对单个 Namespace 进行备份的能力,如果你只想备份某些关键的业务和数据,这是一个十分方便的功能。