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/v1beta1
kind: PodSecurityPolicy
metadata:
name: example
spec:
privileged: false # Don't allow privileged pods!
# The rest fills in some required fields.
seLinux:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
volumes:
- '*'
# 创建SA
kubectl create serviceaccount aliang
# 将SA绑定到系统内置Role
kubectl create rolebinding aliang --clusterrole=edit --serviceaccount=default:aliang
# 创建使用PSP权限的Role
kubectl create role psp:unprivileged --verb=use --resource=podsecuritypolicy --resource-name=psp-example
# 将SA绑定到Role
kubectl create rolebinding aliang:psp:unprivileged --role=psp:unprivileged --serviceaccount=default:aliang
验证:
kubectl --as=system:serviceaccount:default:geray create deployment web2 --image=nginx
kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/web2 0/1 0 0 12s
示例2:禁止没指定普通用户运行的容器(runAsUser)
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: privileged
spec:
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.org
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
yum --enablerepo=elrepo-kernel install kernel-ml-devel kernel-ml –y
grub2-set-default 0
reboot
uname -r
其中“0”是您要设置为默认内核版本的索引号。如果您想选择第二个内核版本,将此值更改为“1”,以此类推。
2. 升级到指定版本
- YUM源安装
# 查看内核版本
uname -r
3.10.0-957.el7.x86_64
# 导入仓库源
sudo rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
sudo 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_64
kernel-ml.x86_64 4.20.0-1.el7.elrepo elrepo-kernel
kernel-ml.x86_64 4.19.12-1.el7.elrepo elrepo-kernel
# 指定安装版本4.19.12
yum --enablerepo="elrepo-kernel" install kernel-ml-4.19.12-1.el7.elrepo.x86_64 -y
grub2-set-default 0
grub2-mkconfig -o /boot/grub2/grub.cfg
grubby --default-kernel
reboot
- 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.rpm
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
# 安装内核
rpm -ivh kernel-ml-4.19.12-1.el7.elrepo.x86_64.rpm
grub2-set-default 0
grub2-mkconfig -o /boot/grub2/grub.cfg
grubby --default-kernel
reboot
内核升级(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
###升级内核之后,系统启动里面还是默认的内核版本。查看当前新的内核版本位置为0
awk -F\' '$1=="menuentry " {print i++ ":" $2}' /boot/grub2/grub.cfg
0 : 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.cfg
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'
# 重启服务器
sudo reboot
1、准备gVisor二进制文件
sha512sum -c runsc.sha512
rm -f *.sha512
chmod a+x runsc
mv runsc /usr/local/bin
2、Docker配置使用gVisor
runsc install # 查看加的配置/etc/docker/daemon.json
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集成
containerd也有 ctr 管理工具,但功能比较简单,一般使用crictl工具检查和调试容器。
项目地址:https://github.com/kubernetes-sigs/cri-tools/
准备crictl连接containerd配置文件:
cat > /etc/crictl.yaml << EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
EOF
下面是docker与crictl命令对照表:
K8s使用gVisor运行容器
RuntimeClass 是一个用于选择容器运行时配置的特性,容器运行时配置用
于运行 Pod 中的容器。
创建RuntimeClass:
apiVersion: node.k8s.io/v1 # RuntimeClass 定义于 node.k8s.io API 组
kind: RuntimeClass
metadata:
name: gvisor # 用来引用 RuntimeClass 的名字
handler: runsc # 对应的 CRI 配置的名称
创建Pod测试gVisor:
apiVersion: v1
kind: Pod
metadata:
name: nginx-gvisor
spec:
runtimeClassName: gvisor
containers:
- name: nginx
image: nginx
kubectl get pod nginx-gvisor -o wide
kubectl exec nginx-gvisor -- dmesg
附件
安全上下文初始化容器配置权限