4.1 Pod安全上下文

安全上下文(Security Context):K8s对Pod和容器提供的安全机制,可以设置Pod特权和访问控制。

安全上下文限制维度:

  • 自主访问控制(Discretionary Access Control):基于用户ID(UID)和组ID(GID),来判定对对象(例如文件)的访问权限。
  • 安全性增强的 Linux(SELinux): 为对象赋予安全性标签。
  • 以特权模式或者非特权模式运行。
  • Linux Capabilities: 为进程赋予 root 用户的部分特权而非全部特权。
  • AppArmor:定义Pod使用AppArmor限制容器对资源访问限制
  • Seccomp:定义Pod使用Seccomp限制容器进程的系统调用
  • AllowPrivilegeEscalation: 禁止容器中进程(通过 SetUID 或 SetGID 文件模式)获得特权提升。当容器以特权模式运行或者具有CAP_SYS_ADMIN能力时,AllowPrivilegeEscalation总为True。
  • readOnlyRootFilesystem:以只读方式加载容器的根文件系统。

1)Pod安全上下文

案例参看

Linux Capabilities:Capabilities 是一个内核级别的权限,它允许对内核调用权限进行更细粒度的控制,而不是简单地以 root 身份能力授权。

Capabilities 包括更改文件权限、控制网络子系统和执行系统管理等功能。在securityContext 中,可以添加或删除 Capabilities,做到容器精细化权限控制。

查看CAP列表:

  1. capsh --print

4、最小化微服务漏洞 - 图1

示例1:容器默认没有挂载文件系统能力,添加SYS_ADMIN增加这个能力

4、最小化微服务漏洞 - 图2

案例2:只读挂载容器文件系统,防止恶意二进制文件创建

4、最小化微服务漏洞 - 图3

4.2 Pod安全策略

PodSecurityPolicy(简称PSP):Kubernetes中Pod部署时重要的安全校验手段,能够有效地约束应用运行时行为安全。

使用PSP对象定义一组Pod在运行时必须遵循的条件及相关字段的默认值,只有Pod满足这些条件才会被K8s接受。

4、最小化微服务漏洞 - 图4

Pod安全策略实现为一个准入控制器,默认没有启用,当启用后会强制实施Pod安全策略,没有满足的Pod将无法创建。因此,建议在启用PSP之前先添加策略并对其授权。

启用Pod安全策略:

  1. vi /etc/kubernetes/manifests/kube-apiserver.yaml
  2. ...
  3. - --enable-admission-plugins=NodeRestriction,PodSecurityPolicy
  4. ...
  5. systemctl restart kubelet

用户使用SA (ServiceAccount)创建了一个Pod,K8s会先验证这个SA是否可以访问PSP资源权限,如果可以进一步验证Pod配置是否满足PSP规则,任意一步不满足都会拒绝部署。

因此,需要实施需要有这几点:

  • 创建SA服务账号
  • 该SA需要具备创建对应资源权限,例如创建Pod、Deployment
  • SA使用PSP资源权限:创建Role,使用PSP资源权限,再将SA绑定Role

4、最小化微服务漏洞 - 图5

示例1:禁止创建特权模式的Pod

4、最小化微服务漏洞 - 图6

https://kubernetes.io/docs/concepts/policy/pod-security-policy/

  1. apiVersion: policy/v1beta1
  2. kind: PodSecurityPolicy
  3. metadata:
  4. name: example
  5. spec:
  6. privileged: false # Don't allow privileged pods!
  7. # The rest fills in some required fields.
  8. seLinux:
  9. rule: RunAsAny
  10. supplementalGroups:
  11. rule: RunAsAny
  12. runAsUser:
  13. rule: RunAsAny
  14. fsGroup:
  15. rule: RunAsAny
  16. volumes:
  17. - '*'
  1. # 创建SA
  2. kubectl create serviceaccount aliang
  3. # 将SA绑定到系统内置Role
  4. kubectl create rolebinding aliang --clusterrole=edit --serviceaccount=default:aliang
  5. # 创建使用PSP权限的Role
  6. kubectl create role psp:unprivileged --verb=use --resource=podsecuritypolicy --resource-name=psp-example
  7. # 将SA绑定到Role
  8. kubectl create rolebinding aliang:psp:unprivileged --role=psp:unprivileged --serviceaccount=default:aliang
  1. 验证:
  2. kubectl --as=system:serviceaccount:default:geray create deployment web2 --image=nginx
  3. kubectl get deploy
  4. NAME READY UP-TO-DATE AVAILABLE AGE
  5. deployment.apps/web2 0/1 0 0 12s

示例2:禁止没指定普通用户运行的容器(runAsUser)

4、最小化微服务漏洞 - 图7

  1. apiVersion: policy/v1beta1
  2. kind: PodSecurityPolicy
  3. metadata:
  4. name: privileged
  5. spec:
  6. privileged: false # 不允许特权
  7. volumes:
  8. - '*'
  9. runAsUser:
  10. rule: 'MustRunAsNonRoot' # 必须存在非root用户
  11. seLinux:
  12. rule: 'RunAsAny'
  13. supplementalGroups:
  14. rule: 'RunAsAny'
  15. fsGroup:
  16. rule: 'RunAsAny'

4.3 Secret存储敏感数据

Secret是一个用于存储敏感数据的资源,所有的数据要经过base64编码,数据实际会存储在K8s中Etcd,然后通过创建Pod时引用该数据。

应用场景:凭据

Pod使用configmap数据有两种方式:

  • 变量注入
  • 数据卷挂载

kubectl create secret 支持三种数据类型:

  • docker-registry:存储镜像仓库认证信息
  • generic:从文件、目录或者字符串创建,例如存储用户名密码
  • tls:存储证书,例如HTTPS证书

示例:将Mysql用户密码保存到Secret中存储

4、最小化微服务漏洞 - 图8

4.4 安全沙箱运行容器

gVisor介绍

4、最小化微服务漏洞 - 图9

所知,容器的应用程序可以直接访问Linux内核的系统调用,容器在安全隔离上还是比较弱,虽然内核在不断地增强自身的安全特性,但由于内核自身代码极端复杂,CVE 漏洞层出不穷。所以要想减少这方面安全风险,就是做好安全隔离,阻断容器内程序对物理机内核的依赖。

Google开源的一种gVisor容器沙箱技术就是采用这种思路,gVisor隔离容器内应用和内核之间访问,提供了大部分Linux内核的系统调用,巧妙的将容器内进程的系统调用转化为对gVisor的访问。

gVisor兼容OCI,与Docker和K8s无缝集成,很方便使用。

项目地址:https://github.com/google/gvisor

4、最小化微服务漏洞 - 图10

gVisor架构

gVisor 由 3 个组件构成:

  • Runsc 是一种 Runtime 引擎,负责容器的创建与销毁。
  • Sentry 负责容器内程序的系统调用处理。
  • Gofer 负责文件系统的操作代理,IO 请求都会由它转接到 Host 上。

4、最小化微服务漏洞 - 图11

gVisor与Docker集成

参考文档:https://gvisor.dev/docs/user_guide/install/

1. 升级最新版本

gVisor内核要求:Linux 3.17+

如果用的是CentOS7则需要升级内核,Ubuntu不需要。

CentOS7内核升级步骤:

  1. rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
  2. rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
  3. yum --enablerepo=elrepo-kernel install kernel-ml-devel kernel-ml y
  4. grub2-set-default 0
  5. reboot
  6. uname -r
其中“0”是您要设置为默认内核版本的索引号。如果您想选择第二个内核版本,将此值更改为“1”,以此类推。

2. 升级到指定版本

  • YUM源安装
  1. # 查看内核版本
  2. uname -r
  3. 3.10.0-957.el7.x86_64
  4. # 导入仓库源
  5. sudo rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
  6. sudo rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
  7. # 查看可安装的软件包
  8. yum --enablerepo="elrepo-kernel" list --showduplicates | sort -r | grep kernel-ml.x86_64
  9. kernel-ml.x86_64 4.20.0-1.el7.elrepo elrepo-kernel
  10. kernel-ml.x86_64 4.19.12-1.el7.elrepo elrepo-kernel
  11. # 指定安装版本4.19.12
  12. yum --enablerepo="elrepo-kernel" install kernel-ml-4.19.12-1.el7.elrepo.x86_64 -y
  13. grub2-set-default 0
  14. grub2-mkconfig -o /boot/grub2/grub.cfg
  15. grubby --default-kernel
  16. reboot
  • RPM安装

Index of /elrepo/kernel/el7/x86_64/RPMS

  1. # 下载rpm包
  2. #wget http://mirror.rc.usf.edu/compute_lock/elrepo/kernel/el7/x86_64/RPMS/kernel-ml-devel-4.19.12-1.el7.elrepo.x86_64.rpm
  3. #wget http://mirror.rc.usf.edu/compute_lock/elrepo/kernel/el7/x86_64/RPMS/kernel-ml-headers-4.19.12-1.el7.elrepo.x86_64.rpm
  4. wget http://mirror.rc.usf.edu/compute_lock/elrepo/kernel/el7/x86_64/RPMS/kernel-ml-4.19.12-1.el7.elrepo.x86_64.rpm
  5. # 安装内核
  6. rpm -ivh kernel-ml-4.19.12-1.el7.elrepo.x86_64.rpm
  7. grub2-set-default 0
  8. grub2-mkconfig -o /boot/grub2/grub.cfg
  9. grubby --default-kernel
  10. reboot
内核升级(jk)
  1. 服务器内核版本升级至(4.19.20-1.el7.x86_64 )
  2. # 升级Master节点和Node节点内核至 4.19.20-1.el7.x86_64 版本,步骤:
  3. # 上传rpm安装包,执行rpm安装(注意配置本地yum仓库,可以照搬其他节点的yum仓库)
  4. yum localinstall -y kernel-ml-* --skip-broken
  5. ###升级内核之后,系统启动里面还是默认的内核版本。查看当前新的内核版本位置为0
  6. awk -F\' '$1=="menuentry " {print i++ ":" $2}' /boot/grub2/grub.cfg
  7. 0 : CentOS Linux (4.19.20-1.el7.x86_64) 7 (Core)
  8. 1 : CentOS Linux (3.10.0-1127.el7.x86_64) 7 (Core)
  9. 2 : CentOS Linux (0-rescue-ce96d80aad324672909914d327a2d91c) 7 (Core)
  10. # 修改内核启动参数 ,把默认的修改为0位置的内核版本
  11. sed -i 's/saved/0/g' /etc/default/grub
  12. # grub2-mkconfig命令来重新创建内核配置
  13. grub2-mkconfig -o /boot/grub2/grub.cfg
  14. # 检查grub启动参数
  15. grep "^menuentry" /boot/grub2/grub.cfg
  16. menuentry 'CentOS Linux (4.19.20-1.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-4.19.20-1.el7.x86_64-advanced-918bc4e0-3f40-4ee7-89f3-0acbd5e60266'
  17. # 重启服务器
  18. sudo reboot

1、准备gVisor二进制文件

  1. sha512sum -c runsc.sha512
  2. rm -f *.sha512
  3. chmod a+x runsc
  4. mv runsc /usr/local/bin

2、Docker配置使用gVisor

  1. runsc install # 查看加的配置/etc/docker/daemon.json
  2. systemctl restart docker

使用runsc运行容器:

docker run -d --runtime=runsc nginx

使用dmesg验证:

docker run --runtime=runsc -it nginx dmesg

已经测试过的应用和工具:https://gvisor.dev/docs/user_guide/compatibility

gVisor与Containerd集成

4、最小化微服务漏洞 - 图12

containerd也有 ctr 管理工具,但功能比较简单,一般使用crictl工具检查和调试容器。

项目地址:https://github.com/kubernetes-sigs/cri-tools/

准备crictl连接containerd配置文件:

  1. cat > /etc/crictl.yaml << EOF
  2. runtime-endpoint: unix:///run/containerd/containerd.sock
  3. EOF

下面是docker与crictl命令对照表:

4、最小化微服务漏洞 - 图13

K8s使用gVisor运行容器

RuntimeClass 是一个用于选择容器运行时配置的特性,容器运行时配置用

于运行 Pod 中的容器。

创建RuntimeClass:

  1. apiVersion: node.k8s.io/v1 # RuntimeClass 定义于 node.k8s.io API 组
  2. kind: RuntimeClass
  3. metadata:
  4. name: gvisor # 用来引用 RuntimeClass 的名字
  5. handler: runsc # 对应的 CRI 配置的名称

创建Pod测试gVisor:

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: nginx-gvisor
  5. spec:
  6. runtimeClassName: gvisor
  7. containers:
  8. - name: nginx
  9. image: nginx
  10. kubectl get pod nginx-gvisor -o wide
  11. kubectl exec nginx-gvisor -- dmesg

习题参考


附件

安全上下文初始化容器配置权限

chown:更改‘/ data/db’的所有权:不允许操作 | 那些遇到过的问题

https://www.5axxw.com/questions/content/k7mmu9