kubernetes--安全上下文(Security Context)
Posted 弓长丿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kubernetes--安全上下文(Security Context)相关的知识,希望对你有一定的参考价值。
安全上下文(Security Context):
K8s对pod和容器提供的安全机制,可以设置Pod特权和访问控制
安全上下文限制维度:
1.自主访问控制((DiscretionaryAccess Control):
基于用户ID(UID)和组ID(GID),来判定对对象(例如文件)的访问权限
2.安全性增强的Linux(SELinux):
为对象赋予安全性标签
3.以特权模式或者非特权模式运行
4.Linux Capabilities:
为进程赋予root用户的部分特权而非全部特权
5.AppArmor:
定义使用AppArmor限制容器对资源访问限制
6.Seccomp:
定义pod使用Seccomp限制容器进程的系统调用
7. AllowPrivilegeEscalation:
禁止容器中进程(通过 SetUID 或 SetGID 文件模式)获得特权提升。当容器以特权模式运行或者具有CAP_SYS_ADMIN能力时,AllowPrivilegeEscalation总为True。
8. readOnlyRootFilesystem:
以只读方式加载容器的根文件系统。
Linux Capabilities:Capabilities是一个内核级别的权限,它允许对内核调用权 限进行更细粒度的控制,而不是简单地以 root 身份能力授权。 Capabilities 包括更改文件权限、控制网络子系统和执行系统管理等功能。在securityContext 中,可以添加或删除 Capabilities,做到容器精细化权限控制。CAP_可以省略不写
【】capsh --print第一行为当前用户的
capability 名称 | 描述 |
CAP_AUDIT_CONTROL | 启用和禁用内核审计;改变审计过滤规则;检索审计状态和过滤规则 |
CAP_AUDIT_READ | 允许通过 multicast netlink 套接字读取审计日志 |
CAP_AUDIT_WRITE | 将记录写入内核审计日志 |
CAP_BLOCK_SUSPEND | 使用可以阻止系统挂起的特性 |
CAP_CHOWN | 修改文件所有者的权限 |
CAP_DAC_OVERRIDE | 忽略文件的 DAC 访问限制 |
CAP_DAC_READ_SEARCH | 忽略文件读及目录搜索的 DAC 访问限制 |
CAP_FOWNER | 忽略文件属主 ID 必须和进程用户 ID 相匹配的限制 |
CAP_FSETID | 允许设置文件的 setuid 位 |
CAP_IPC_LOCK | 允许锁定共享内存片段 |
CAP_IPC_OWNER | 忽略 IPC 所有权检查 |
CAP_KILL | 允许对不属于自己的进程发送信号 |
CAP_LEASE | 允许修改文件锁的 FL_LEASE 标志 |
CAP_LINUX_IMMUTABLE | 允许修改文件的 IMMUTABLE 和 APPEND 属性标志 |
CAP_MAC_ADMIN | 允许 MAC 配置或状态更改 |
CAP_MAC_OVERRIDE | 忽略文件的 DAC 访问限制 |
CAP_MKNOD | 允许使用 mknod() 系统调用 |
CAP_NET_ADMIN | 允许执行网络管理任务 |
CAP_NET_BIND_SERVICE | 允许绑定到小于 1024 的端口 |
CAP_NET_BROADCAST | 允许网络广播和多播访问 |
CAP_NET_RAW | 允许使用原始套接字 |
CAP_SETGID | 允许改变进程的 GID |
CAP_SETFCAP | 允许为文件设置任意的 capabilities |
CAP_SETPCAP | 参考 capabilities man page |
CAP_SETUID | 允许改变进程的 UID |
CAP_SYS_ADMIN | 允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等 |
CAP_SYS_BOOT | 允许重新启动系统 |
CAP_SYS_CHROOT | 允许使用 chroot() 系统调用 |
CAP_SYS_MODULE | 允许插入和删除内核模块 |
CAP_SYS_NICE | 允许提升优先级及设置其他进程的优先级 |
CAP_SYS_PACCT | 允许执行进程的 BSD 式审计 |
CAP_SYS_PTRACE | 允许跟踪任何进程 |
CAP_SYS_RAWIO | 允许直接访问 /devport、/dev/mem、/dev/kmem 及原始块设备 |
CAP_SYS_RESOURCE | 忽略资源限制 |
CAP_SYS_TIME | 允许改变系统时钟 |
CAP_SYS_TTY_CONFIG | 允许配置 TTY 设备 |
CAP_SYSLOG | 允许使用 syslog() 系统调用 |
CAP_WAKE_ALARM | 允许触发一些能唤醒系统的东西(比如 CLOCK_BOOTTIME_ALARM 计时器) |
案例1:设置容器以普通用户运行
背景:容器中的应用程序默认以root账号运行的,这个root与宿主机root账号是相同的, 拥有大部分对Linux内核的系统调用权限,这样是不安全的,所以我们应该将容器以普 通用户运行,减少应用程序对权限的使用。 可以通过两种方法设置普通用户:
1 Dockerfile里使用USER指定运行用户
2 K8s里指定spec.securityContext.runAsUser,指定容器默认用户UID
spec:
securityContext:
runAsUser: 1000 # 镜像里必须有这个用户UID
fsGroup: 1000 # 数据卷挂载后的目录属组设置为该组
containers:
-image: flask-demo:root (镜像自制即可)
name: web
securityContext:
allowPrivilegeEscalation: false # 不允许提权
方法1.Dockerfile
1)可以先注释USER看效果
【】cat /root/flask-demo/Dockerfile
FROM python
RUN useradd python
RUN mkdir /data/www -p
COPY . /data/www
RUN chown -R python /data
RUN pip install flask -i https://mirrors.aliyun.com/pypi/simple/&& \\
pip install prometheus_client -i https://mirrors.aliyun.com/pypi/simple/
WORKDIR /data/www
#USER python
CMD python main.py
【】docker build -t flask-demo:v1 .
【】docker run -d --name demo-v1 -p 8080:8080 flask-demo:v1
【】docker exec -it demo-v1 bash
在宿主机查看也有该进程且为root
2)以普通账号运行
cat /root/flask-demo/Dockerfile
FROM python
RUN useradd python
RUN mkdir /data/www -p
COPY . /data/www
RUN chown -R python /data
RUN pip install flask -i https://mirrors.aliyun.com/pypi/simple/&& \\
pip install prometheus_client -i https://mirrors.aliyun.com/pypi/simple/
WORKDIR /data/www
USER python
CMD python main.py
【】docker build -t flask-demo:v2 .
【】docker run -d --name demo-v2 -p 8081:8080 flask-demo:v1
【】docker exec -it demo-v2 bash
方法2:K8s里指定spec.securityContext.runAsUser,指定容器默认用户UID
【】kubectl create deployment flask-demo --image=nginx --dry-run=client -o yaml >deployment.yaml
【】vim deploymeny.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: flask-demo
name: flask-demo
spec:
replicas: 1
selector:
matchLabels:
app: flask-demo
strategy:
template:
metadata:
creationTimestamp: null
labels:
app: flask-demo
spec:
securityContext:
runAsUser: 1000 # 镜像里必须有这个用户UID
fsGroup: 1000 # 数据卷挂载后的目录属组设置为该组
containers:
- image: flask-demo:v1 #上文创建的镜像,默认root权限
name: nginx
resources:
nodeName: "k8s-master1"
进入容器查看id
若使用镜像中不存在的用户则会创建一个普通账号
使用v2版镜像,默认以1000用户则不需要设置上下文即可,默认就是用户id为1000
案列2:避免使用特权容器
背景:容器中有些应用程序可能需要访问宿主机设备、修改内核等需求(容器引擎已经组止了,测不出来),在默认情况下,容器没有这个能力,因此此时会考虑给容器是设置特权模式。
启用特权模式:
containers:
- image:flask-demo:root
name:web
securityContext:
privileged: true#启用特权
启用特权模式就意味着,你要为容器提供了访问linux内核的所有能力,这是很危险的,为了减少系统调用的供给,可以使用Capabilities为容器赋予仅所需的能力。
Linux Capabilities:是一个内核级别的权限,它允许对内核调用权限进行更细粒度的控制,而不是简单的以root身份能力授权。
Capabilities包括更改文件权限、控制网络子系统和执行系统管理等功能。在securityContext中,可以添加或删除Capabilities,做到容器精细化控制。
验证mount权限,默认无,截图为示列
【】cat tequan
apiVersion: v1
kind: Pod
metadata:
name: pod-sc1
spec:
containers:
-name: sc
image: busybox
command:
-sleep
-24h
securityContext:
privileged: true
【】kubectl exec -it pod-sc1 sh
示列1:容器默认没有挂载文件系统能力,添加SYS_ADMIN增加这个能力
容器默认无此能力,容器引擎以默认阻止
-t tmpfs 临时文件系统
apiVersion: v1
kind: Pod
metadata:
name: pod-sc2
spec:
containers:
- name: test
image: busybox
command:
- sleep
- 24h
securityContext:
capabilities:
add: ["SYS_ADMIN"]
#drop:移除特权,可写all
也有这样用的,删除所有,添加指定项,类似于白名单
案列2:以只读挂载文件系统,防止恶意二进制文件创建
普通容器没限制的话可任意增删改查
apiVersion: v1
kind: Pod
metadata:
name: Pod-sc3
spec:
containers:
- name: test
image: busybox
command:
- sleep
- 24h
securityContext:
readOnlyRootFilesystem: true
启动并进入容器
kubernetes使用securityContext和sysctl
前言
在运行一个容器时,有时候需要使用sysctl
修改内核参数,比如net.
、vm.
、kernel
等,sysctl
需要容器拥有超级权限,容器启动时加上--privileged
参数即可。那么,在kubernetes中是如何使用的呢?
Security Context
kubernetes中有个字段叫securityContext
,即安全上下文
,它用于定义Pod或Container的权限和访问控制设置。其设置包括:
- Discretionary Access Control: 根据用户ID(UID)和组ID(GID)来限制其访问资源(如:文件)的权限
针对pod设置:
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
fsGroup: 2000
volumes:
- name: sec-ctx-vol
emptyDir:
containers:
- name: sec-ctx-demo
image: gcr.io/google-samples/node-hello:1.0
volumeMounts:
- name: sec-ctx-vol
mountPath: /data/demo
securityContext:
allowPrivilegeEscalation: false
针对container设置:
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-2
spec:
securityContext:
runAsUser: 1000
containers:
- name: sec-ctx-demo-2
image: gcr.io/google-samples/node-hello:1.0
securityContext:
runAsUser: 2000
allowPrivilegeEscalation: false
- Security Enhanced Linux (SELinux): 给容器指定SELinux labels
...
securityContext:
seLinuxOptions:
level: "s0:c123,c456"
- Running as privileged or unprivileged:以
privileged
或unprivileged
权限运行
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-4
spec:
containers:
- name: sec-ctx-4
image: gcr.io/google-samples/node-hello:1.0
securityContext:
privileged: true
- Linux Capabilities: 给某个特定的进程privileged权限,而不用给root用户所有的
privileged
权限
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-4
spec:
containers:
- name: sec-ctx-4
image: gcr.io/google-samples/node-hello:1.0
securityContext:
capabilities:
add: ["NET_ADMIN", "SYS_TIME"]
-
AppArmor: 使用程序文件来限制单个程序的权限
-
Seccomp: 限制一个进程访问文件描述符的权限
-
AllowPrivilegeEscalation: 控制一个进程是否能比其父进程获取更多的权限,
AllowPrivilegeEscalation
的值是bool值,如果一个容器以privileged权限运行或具有CAP_SYS_ADMIN
权限,则AllowPrivilegeEscalation
的值将总是true。
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-2
spec:
securityContext:
runAsUser: 1000
containers:
- name: sec-ctx-demo-2
image: gcr.io/google-samples/node-hello:1.0
securityContext:
runAsUser: 2000
allowPrivilegeEscalation: false
注意:要开启容器的privileged权限,需要提前在kube-apiserver
和kubelet
启动时添加参数--allow-privileged=true
,默认已添加。
使用sysctl
sysctl -a
可以获取sysctl所有参数列表。
从v1.4开始,kubernetes将sysctl分为safe
和unsafe
,其对safe的sysctl定义如下:
- 不会影响该节点的其他pod
- 不会影响节点的正常运行
- 不会获取超出
resource limits
范围的CPU和内存资源
目前属于safe sysctl
的有:
- kernel.shm_rmid_forced
- net.ipv4.ip_local_port_range
- net.ipv4.tcp_syncookies
其余的都是unsafe sysctl
,当kubelet支持更好的隔离机制时,safe sysctl
列表将在未来的Kubernetes版本中扩展。
使用safe sysctl
例子:
apiVersion: v1
kind: Pod
metadata:
name: sysctl-example
annotations:
security.alpha.kubernetes.io/sysctls: kernel.shm_rmid_forced=1
spec:
...
而使用unsafe sysctl
时,需要在kubelet的启动参数中指定--experimental-allowed-unsafe-sysctls
,如--experimental-allowed-unsafe-sysctls=net.core.somaxconn
,具体操作如下:
编辑kubelet配置文件,修改ExecStart=/usr/bin/kubelet
那一行,在后面加上--experimental-allowed-unsafe-sysctls=net.core.somaxconn
,如:
ExecStart=/usr/bin/kubelet --experimental-allowed-unsafe-sysctls=net.core.somaxconn
因为我是用kubeadm安装的kubernetes,所以在/etc/systemd/system/kubelet.service.d/10-kubeadm.conf
文件中加了倒数第3行内容:
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_SYSTEM_PODS_ARGS=--pod-manifest-path=/etc/kubernetes/manifests --allow-privileged=true"
Environment="KUBELET_NETWORK_ARGS=--network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin"
Environment="KUBELET_DNS_ARGS=--cluster-dns=10.96.0.10 --cluster-domain=cluster.local"
Environment="KUBELET_AUTHZ_ARGS=--authorization-mode=Webhook --client-ca-file=/etc/kubernetes/pki/ca.crt"
Environment="KUBELET_CADVISOR_ARGS=--cadvisor-port=0"
Environment="KUBELET_CGROUP_ARGS=--cgroup-driver=systemd"
Environment="KUBELET_CERTIFICATE_ARGS=--rotate-certificates=true --cert-dir=/var/lib/kubelet/pki"
Environment="KUBELET_EXTRA_ARGS=--experimental-allowed-unsafe-sysctls=net.core.somaxconn"
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_SYSTEM_PODS_ARGS $KUBELET_NETWORK_ARGS $KUBELET_DNS_ARGS $KUBELET_AUTHZ_ARGS $KUBELET_CADVISOR_ARGS $KUBELET_CGROUP_ARGS $KUBELET_CERTIFICATE_ARGS $KUBELET_EXTRA_ARGS
重启kubelet:
systemctl daemon-reload
systemctl restart kubelet
在Pod中使用unsafe sysctl
,开启privileged权限:
apiVersion: v1
kind: Pod
metadata:
name: sysctl-example
annotations:
security.alpha.kubernetes.io/unsafe-sysctls: net.core.somaxconn=65535 #使用unsafe sysctl,设置最大连接数
spec:
securityContext:
privileged: true #开启privileged权限
...
总结
线上环境请谨慎使用privileged
权限,使用不慎可能导致整个容器崩掉,相关信息可自行查阅。
参考:
https://kubernetes.io/docs/concepts/cluster-administration/sysctl-cluster/
https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
以上是关于kubernetes--安全上下文(Security Context)的主要内容,如果未能解决你的问题,请参考以下文章
kubernetes使用securityContext和sysctl