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列表:
capsh --print

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

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

4.2 Pod安全策略
PodSecurityPolicy(简称PSP):Kubernetes中Pod部署时重要的安全校验手段,能够有效地约束应用运行时行为安全。
使用PSP对象定义一组Pod在运行时必须遵循的条件及相关字段的默认值,只有Pod满足这些条件才会被K8s接受。

Pod安全策略实现为一个准入控制器,默认没有启用,当启用后会强制实施Pod安全策略,没有满足的Pod将无法创建。因此,建议在启用PSP之前先添加策略并对其授权。
启用Pod安全策略:
vi /etc/kubernetes/manifests/kube-apiserver.yaml...- --enable-admission-plugins=NodeRestriction,PodSecurityPolicy...systemctl restart kubelet
用户使用SA (ServiceAccount)创建了一个Pod,K8s会先验证这个SA是否可以访问PSP资源权限,如果可以进一步验证Pod配置是否满足PSP规则,任意一步不满足都会拒绝部署。
因此,需要实施需要有这几点:
- 创建SA服务账号
- 该SA需要具备创建对应资源权限,例如创建Pod、Deployment
- SA使用PSP资源权限:创建Role,使用PSP资源权限,再将SA绑定Role

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

https://kubernetes.io/docs/concepts/policy/pod-security-policy/
apiVersion: policy/v1beta1kind: PodSecurityPolicymetadata:name: examplespec:privileged: false # Don't allow privileged pods!# The rest fills in some required fields.seLinux:rule: RunAsAnysupplementalGroups:rule: RunAsAnyrunAsUser:rule: RunAsAnyfsGroup:rule: RunAsAnyvolumes:- '*'
# 创建SAkubectl create serviceaccount aliang# 将SA绑定到系统内置Rolekubectl create rolebinding aliang --clusterrole=edit --serviceaccount=default:aliang# 创建使用PSP权限的Rolekubectl create role psp:unprivileged --verb=use --resource=podsecuritypolicy --resource-name=psp-example# 将SA绑定到Rolekubectl create rolebinding aliang:psp:unprivileged --role=psp:unprivileged --serviceaccount=default:aliang
验证:kubectl --as=system:serviceaccount:default:geray create deployment web2 --image=nginxkubectl get deployNAME READY UP-TO-DATE AVAILABLE AGEdeployment.apps/web2 0/1 0 0 12s
示例2:禁止没指定普通用户运行的容器(runAsUser)

apiVersion: policy/v1beta1kind: PodSecurityPolicymetadata:name: privilegedspec:privileged: false # 不允许特权volumes:- '*'runAsUser:rule: 'MustRunAsNonRoot' # 必须存在非root用户seLinux:rule: 'RunAsAny'supplementalGroups:rule: 'RunAsAny'fsGroup:rule: 'RunAsAny'
4.3 Secret存储敏感数据
Secret是一个用于存储敏感数据的资源,所有的数据要经过base64编码,数据实际会存储在K8s中Etcd,然后通过创建Pod时引用该数据。
应用场景:凭据
Pod使用configmap数据有两种方式:
- 变量注入
- 数据卷挂载
kubectl create secret 支持三种数据类型:
- docker-registry:存储镜像仓库认证信息
- generic:从文件、目录或者字符串创建,例如存储用户名密码
- tls:存储证书,例如HTTPS证书
示例:将Mysql用户密码保存到Secret中存储

4.4 安全沙箱运行容器
gVisor介绍

所知,容器的应用程序可以直接访问Linux内核的系统调用,容器在安全隔离上还是比较弱,虽然内核在不断地增强自身的安全特性,但由于内核自身代码极端复杂,CVE 漏洞层出不穷。所以要想减少这方面安全风险,就是做好安全隔离,阻断容器内程序对物理机内核的依赖。
Google开源的一种gVisor容器沙箱技术就是采用这种思路,gVisor隔离容器内应用和内核之间访问,提供了大部分Linux内核的系统调用,巧妙的将容器内进程的系统调用转化为对gVisor的访问。
gVisor兼容OCI,与Docker和K8s无缝集成,很方便使用。
项目地址:https://github.com/google/gvisor

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

gVisor与Docker集成
参考文档:https://gvisor.dev/docs/user_guide/install/
1. 升级最新版本
gVisor内核要求:Linux 3.17+
如果用的是CentOS7则需要升级内核,Ubuntu不需要。
CentOS7内核升级步骤:
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.orgrpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpmyum --enablerepo=elrepo-kernel install kernel-ml-devel kernel-ml –ygrub2-set-default 0rebootuname -r
其中“0”是您要设置为默认内核版本的索引号。如果您想选择第二个内核版本,将此值更改为“1”,以此类推。
2. 升级到指定版本
- YUM源安装
# 查看内核版本uname -r3.10.0-957.el7.x86_64# 导入仓库源sudo rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.orgsudo rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm# 查看可安装的软件包yum --enablerepo="elrepo-kernel" list --showduplicates | sort -r | grep kernel-ml.x86_64kernel-ml.x86_64 4.20.0-1.el7.elrepo elrepo-kernelkernel-ml.x86_64 4.19.12-1.el7.elrepo elrepo-kernel# 指定安装版本4.19.12yum --enablerepo="elrepo-kernel" install kernel-ml-4.19.12-1.el7.elrepo.x86_64 -ygrub2-set-default 0grub2-mkconfig -o /boot/grub2/grub.cfggrubby --default-kernelreboot
- RPM安装
Index of /elrepo/kernel/el7/x86_64/RPMS
# 下载rpm包#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#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.rpmwget http://mirror.rc.usf.edu/compute_lock/elrepo/kernel/el7/x86_64/RPMS/kernel-ml-4.19.12-1.el7.elrepo.x86_64.rpm# 安装内核rpm -ivh kernel-ml-4.19.12-1.el7.elrepo.x86_64.rpmgrub2-set-default 0grub2-mkconfig -o /boot/grub2/grub.cfggrubby --default-kernelreboot
内核升级(jk)
服务器内核版本升级至(4.19.20-1.el7.x86_64 )# 升级Master节点和Node节点内核至 4.19.20-1.el7.x86_64 版本,步骤:# 上传rpm安装包,执行rpm安装(注意配置本地yum仓库,可以照搬其他节点的yum仓库)yum localinstall -y kernel-ml-* --skip-broken###升级内核之后,系统启动里面还是默认的内核版本。查看当前新的内核版本位置为0awk -F\' '$1=="menuentry " {print i++ ":" $2}' /boot/grub2/grub.cfg0 : CentOS Linux (4.19.20-1.el7.x86_64) 7 (Core)1 : CentOS Linux (3.10.0-1127.el7.x86_64) 7 (Core)2 : CentOS Linux (0-rescue-ce96d80aad324672909914d327a2d91c) 7 (Core)# 修改内核启动参数 ,把默认的修改为0位置的内核版本sed -i 's/saved/0/g' /etc/default/grub# grub2-mkconfig命令来重新创建内核配置grub2-mkconfig -o /boot/grub2/grub.cfg# 检查grub启动参数grep "^menuentry" /boot/grub2/grub.cfgmenuentry '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'# 重启服务器sudo reboot
1、准备gVisor二进制文件
sha512sum -c runsc.sha512rm -f *.sha512chmod a+x runscmv runsc /usr/local/bin
2、Docker配置使用gVisor
runsc install # 查看加的配置/etc/docker/daemon.jsonsystemctl 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集成

containerd也有 ctr 管理工具,但功能比较简单,一般使用crictl工具检查和调试容器。
项目地址:https://github.com/kubernetes-sigs/cri-tools/
准备crictl连接containerd配置文件:
cat > /etc/crictl.yaml << EOFruntime-endpoint: unix:///run/containerd/containerd.sockEOF
下面是docker与crictl命令对照表:

K8s使用gVisor运行容器
RuntimeClass 是一个用于选择容器运行时配置的特性,容器运行时配置用
于运行 Pod 中的容器。
创建RuntimeClass:
apiVersion: node.k8s.io/v1 # RuntimeClass 定义于 node.k8s.io API 组kind: RuntimeClassmetadata:name: gvisor # 用来引用 RuntimeClass 的名字handler: runsc # 对应的 CRI 配置的名称
创建Pod测试gVisor:
apiVersion: v1kind: Podmetadata:name: nginx-gvisorspec:runtimeClassName: gvisorcontainers:- name: nginximage: nginxkubectl get pod nginx-gvisor -o widekubectl exec nginx-gvisor -- dmesg
附件
安全上下文初始化容器配置权限
