Kubernetes安全指南

820

一.  Pod 安全

1.使用非root用户构建的容器来运行应用程序

例如:

- 在Dockerfile中,使用 non-root , 或者在K8s中,使用SecurityContext:runAsUser指定一个非0的用户将容器加载到pod中.

- 可以在 docker 启动容器的时候加上"-u"参数,在参数中指定 uid/gid。

- 我们在创建容器镜像的时候,用 Dockerfile 为容器镜像里建立一个用户。

# cat Dockerfile
FROM centos
 
RUN adduser -u 6667 nonroot
USER nonroot
 
# docker build -t registry/nonroot:v1 . 
# docker run -d --name root_example -v /etc:/mnt registry/nonroot:v1 sleep 3600
050809a716ab0a9481a6dfe711b332f74800eff5fea8b4c483fa370b62b4b9b3
 
# docker exec -it root_example bash
[nonroot@050809a716ab /]$ id
uid=6667(nonroot) gid=6667(nonroot) groups=6667(nonroot)
[nonroot@050809a716ab /]$ ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
nonroot      1     0  0 01:43 ?        00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 3600

注意其他问题:

由于用户 uid 是整个节点中共享的,那么在容器中定义的 uid,也就是宿主机上的 uid,这样就很容易引起 uid 的冲突。

要解决这个问题,必须要有一个云平台级别的 uid 管理和分配,但选择这个方法也要付出代价。因为这样做是可以解决问题,但是用户在定义自己容器中的 uid 的时候,他们就需要有额外的操作,而且平台也需要新开发对 uid 平台级别的管理模块,完成这些事情需要的工作量也不少。

容器额外知识 - Linux User Namespace 用户隔离技术 (Kubernetes目前不支持)

User Namespace 隔离了一台 Linux 节点上的 User ID(uid)和 Group ID(gid),它给 Namespace 中的 uid/gid 的值与宿主机上的 uid/gid 值建立了一个映射关系。经过 User Namespace 的隔离,我们在 Namespace 中看到的进程的 uid/gid,就和宿主机 Namespace 中看到的 uid 和 gid 不一样了。

还有一点你要注意的是,User Namespace 是可以嵌套的,比如下面图里的 namespace_2 里可以再建立一个 namespace_3,这个嵌套的特性是其他 Namespace 没有的。

# podman run -ti  -v /etc:/mnt --uidmap 0:2000:1000 centos bash

这里我们在命令里增加一个参数,"--uidmap 0:2000:1000",这个是标准的 User Namespace 中 uid 的映射格式:"ns_uid:host_uid:amount"。

- 第一个 0 是指在新的 Namespace 里 uid 从 0 开始

- 中间的那个 2000 指的是 Host Namespace 里被映射的 uid 从 2000 开始

- 最后一个 1000 是指总共需要连续映射 1000 个 uid。

User Namespace 有两个好处:

第一,它把容器中 root 用户(uid 0)映射成宿主机上的普通用户。

第二,对于用户在容器中自己定义普通用户 uid 的情况,我们只要为每个容器在节点上分配一个 uid 范围,就不会出现在宿主机上 uid 冲突的问题了。

2.在可能的情况下,运行具有不可变的文件系统容器,

Kubernetes可以锁定容器的文件系统,从而防止许多操作.而这些限制也会影响合法的应用程序容器,可能导致其奔溃或异常.为了防止损坏合法的应用成功程序,Kubernetes管理员可以为应用程序的特定目录挂载可以读写的文件系统.

3.扫描容器镜像,查看可能的漏洞或者错误配置,如不安全的端口或权限

实现image扫描的一种方法是使用admission Controller , 这个controller是K8s的原生特性,它可以在请求到达K8s api 之前将其拦截,并进行身份验证和授权处理.可以实现自定义或者专有的webhook来扫描任何部署到集群中的image.如果image不符合webookhook配置中定义的安全策略,admission Controller可以阻止部署.

4.使用Pod安全策略(PSP)

建立一个所有pod必须遵守的最低限度的安全阈值,包括:

- 只在创建的时候拒绝不符合要求pod,不影响集群中已经运行的pod

- 防止特权容器

- 拒绝频繁被利用来中断的容器特性,如: hostPID, hostIPC, hostNetwork, allowedHostPath

Pod安全策略组件:

PodSecurityPolicy****例子:

5.拒绝作为root用户来启动或管理容器

不仅仅指容器中以非 root 用户来运行进程,还指以非 root 用户来创建容器,管理容器.

Kubernetes 对rootless container 支持的工作也在进行中。也就是说,启动容器的时候,Docker 或者 podman 是以非 root 用户来执行的。

这样一来,就能进一步提升容器中的安全性,我们不用再担心因为 containerd 或者 RunC 里的代码漏洞,导致容器获得宿主机上的权限。

6. 对应用程序进行加固,防止使用安全服务,如: SELinux®, AppArmor®, and seccomp

7.保护pod service account 令牌

如果应用程序不需要直接访问service account 时,kubenetest管理员应该禁止去挂载service account 令牌,可以使用pod的yaml规范中的”automountServiceAccountToken:false”指令.

8.使用Hypervisor来加强隔离

二. 网络隔离与加固

1.通过防火墙合RBAC锁定平面节点的访问

2. 进一步限制对Kubernetes里etcd的访问

3.配置控制平面组件使用TLS认证加密通信

4.设置资源隔离的网络策略.除非实施额外的隔离(如网络策略),否则不同命名空间的pod跟service仍然可以互相通信

5.将所有凭证和敏感信息放到kubernetes secrets中,而不是配置文件中.使用强加密方法加密secrets

三. 身份验证

1.管理员应该在集群中添加认证授权机制

2.禁用匿名登录(默认开启)

3.使用强用户身份验证

4.创建RBAC策略,限制管理员/用户/service account的活动

四. 日志审计

1.kubernetes的审计功能是默认禁用的,所以如果没有写审计策略则不记录任何日志.应该开启.

2.保存日志,以确保在 节点/pod/容器 级别故障时可用

3.配置一个metrics logger

4.SIEM平台: 安全信息合时间管理软件,从整个组织网络手机日志.一般提供日志收,威胁检查和报警功能.

5.报警,管理员应该监控和配置报警的几个指标,可能呢触发警报的列子包括但不限于:

- 环境中任何机器的磁盘空间都很低

- 日志卷的可用存储空间不足

- 外部日志服务下线

- 以root权限运行的pod或应用程序

- 账户对他们没有权限的资源提出请求

- 匿名账户正在使用或者获得特权

- Pod或Worker Node的IP地址被列为Pod创建请求的源IP

- 不正常的系统调用或者失败的API调用

- 用户/管理员的异常行为(例如,在不寻常的时间或者不寻常的位置),与标准运行度量基线的显著偏差

五. 升级和应用程序安全实践

1.立即应用安全补丁和更新

2.定期执行漏洞扫描和渗透测试

3.从环境中删除不需要的组件

参考内容来自:
美国NSA和SISA的 Kubernetes Hardening Guidance