保障集群内节点和网络安全
在pod
中使用宿主节点的Linux
命名空间
部分pod
(特别是系统pod
)需要在宿主节点的默认命名空间中运行, 以允许它们看到和操作节点级别的资源和设备.
绑定宿主节点上的端口而不使用宿主节点的网络命名空间
这可以通过配置pod
的spec.containers.ports
字段中某个容器某一个端口的hostPort
属性来实现.
如果一个pod
绑定了宿主节点上的一个特定端口, 每个宿主节点只能调度一个这样的pod
实例, 因为两个进程不能绑定宿主机上的同一个端口. 调度器在调度pod
时会考虑这一点, 所以它不会把这样的两个pod
调度到同一个节点上.
1 2 3 4 5 6 7 8
| spec: containers: - image: some/image name: <pod的名称> ports: - containerPort: 8080 hostPort: 9000 protocol: TCP
|
hostPort
功能最初是用于暴露通过DeamonSet
部署在每个节点上的系统服务的.
配置节点的安全上下文
安全上下文中可配置的内容:
- 指定容器中运行进程的用户(用户
ID
)
- 阻止容器使用
root
用于运行(容器的默认运行用户通常在其镜像中指定, 所以可能需要阻止容器以root
用户运行)
- 使用特权模式运行容器, 使其对宿主节点的内核具有完全的访问权限
- 与以上相反, 通过添加或禁用内容功能, 配置细粒度的内核访问权限
- 设置
SELinux
选项, 加强对容器的限制
- 阻止进程写入容器的根文件系统
使用指定用户运行容器
1 2 3 4 5 6 7
| spec: containers: - name: main image: alpine command: ["/bin/sleep", "999999"] securityContext: runAsUser: 405
|
阻止容器以root
用户运行
1 2 3 4 5 6 7
| spec: containers: - name: main image: alpine command: ["/bin/sleep", "999999"] securityContext: runAsNonRoot: true
|
使用特权模式运行pod
1 2 3 4 5 6 7
| spec: containers: - name: main image: alpine command: ["/bin/sleep", "999999"] securityContext: privileged: true
|
为容器单独添加内核功能
相比于让容器运行在特权模式下以给予其无限的权限, 一个更加安全地做法是只给予它使用真正需要的内核功能的权限. Kubernetes
允许为特定的容器添加内核功能, 或禁止部分内核功能, 以允许对容器进行更加细致的权限控制, 限制攻击者潜在侵入的影响.
1 2 3 4 5 6 7 8
| spec: containers: - name: main image: alpine command: ["/bin/sleep", "999999"] securityContext: add: - SYS_TIME
|
在容器中禁用内核功能
1 2 3 4 5 6 7 8
| spec: containers: - name: main image: alpine command: ["/bin/sleep", "999999"] securityContext: drop: - CHOWN
|
阻止对容器跟文件系统的写入
1 2 3 4 5 6 7
| spec: containers: - name: main image: alpine command: ["/bin/sleep", "999999"] securityContext: readOnlyRootFilesystem: true
|
容器使用不同用户时共享存储卷
1 2 3 4
| spec: securityContext: fsGroup: 555 supplementalGroups: [666, 777]
|
限制pod
使用安全相关的特性
PodSecurityPolicy
资源介绍
PodSecuriyPolicy
是一种集群级别(无命名空间)的资源, 它定义了用户能否在pod
中使用各种安全相关的特性. 维护PodSecurityPolicy
资源中配置策略的工作由集成在API
服务器中的PodSercurityPolicy
准入控制插件完成.
PodSecurityPolicy
可以做的事
- 是否允许
pod
使用宿主节点的PID
, IPC
, 网络命名空间
pod
允许绑定的宿主节点的端口
- 容器运行时允许使用的用户
ID
- 是否允许拥有特权模式容器的
pod
- 允许添加哪些内核功能, 默认添加哪些内核功能, 总是禁用哪些内核功能
- 允许容器使用哪些
SELinux
选项
- 容器是否允许使用可写的根文件系统
- 允许容器在哪些文件系统组下运行
- 允许
pod
使用哪些类型的存储卷
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| apiVersion: extensions/v1beta1 kind: PodSecurityPolicy metadata: name: default spec: hostIPC: false hostPID: false hostNetwork: false hostPorts: - min: 10000 max: 11000 - min: 13000 max: 14000 privileged: false readOnlyRootFilesystem: true runAsUser: rule: RunAsAny fsGroup: rule: RunAsAny supplementalGroups: rule: RunAsAny seLinux: rule: RunAsAny volumes: - '*'
|
了解runAsUser
, fsGroup
和supplementGroup
策略
如果需要限制容器可以使用的用户和用户组ID
, 可以将规则改为MustRunAs
, 并指定允许使用的ID
范围.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| runAsUser: rule: MustRunAs ranges: - min: 2 max: 2 fsGroup: rule: MustRunAs ranges: - min: 2 max: 10 - min: 20 max: 30 supplementalGroups: rule: MustRunAs ranges: - min: 2 max: 10 - min: 20 max: 30
|
如果pod spec
试图将其中的任一字段设置为该范围之外的值, 这个pod
将不会被API
服务器接收.
部署镜像中用户ID
在指定范围之外的pod
PodSecurityPolicy
会将硬编码覆盖到镜像中的用户ID
.
在runAsUser
字段中使用mustRunAsNonRoot
规则
runAsUser
字段中还可以使用另一种规则: mustRunAsNonRoot
. 它将阻止用户部署以root
用户运行的容器. 在这种情况下, spec
容器中必须指定runAsUser
字段, 并且不能为0, 或者容器的镜像本身指定了一个用非0的用户ID
运行.
配置允许, 默认添加, 禁止使用的内核功能
1 2 3 4 5 6 7 8 9 10
| apiVersion: extensions/v1beta1 kind: PodSecurityPolicy spec: allowedCapabilities - SYS_TIME defaultAddCapabilities - CHOWN requiredDropCapabilities - SYS_ADMIN - SYS_MODULES
|
对不同的用户与组分配不同的PodSecurityPolicy
PodSecurityPolicy
是集群级别的资源, 这意味着它不能存储和应用在某一特定的命名空间上. 对不同用户分配不同PodSecurityPolicy
是通过RBAC
机制实现的. 这个方式是, 创建你需要的PodSecurityPolicy
资源, 然后创建ClusterRole
资源并通过名称将它们指向不同的策略, 以此使PodSecurityPolicy
资源中的策略对不同的用户或组生效. 通过ClusterRoleBinding
资源将特定的用户组绑定到ClusterRole
上, 当PodSecurityPolicy
访问控制插件需要决定是否接纳一个pod
时, 它只会考虑创建pod
的用户可以访问到的PodSecurityPolicy
中的策略.
隔离pod
的网络
一个NetworkPolicy
会应用在匹配它的标签选择器的pod
上, 指明这些允许访问这些pod
的源地址, 或这些pod
可以访问的目标地址. 这些分别由入向ingress
和出向egress
规则指定. 这两种规则都可以匹配由标签选择器选出的pod
, 或者一个namespace
中的所有pod
, 或者通过无类别域间路由(CIDR
)指定的IP
地址段.
在一个命名空间中阻止所有访问
1 2 3 4 5 6
| apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector:
|
空的标签选择器匹配命名空间中的所有pod
.
允许同一命名空间中的部分pod
访问一个服务端pod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: postgres-netpolicy spec: podSelector: matchLabels: app: database ingress: - from: - podSelector: matchLabels: app: webserver ports: - port: 5432
|
在不同Kubernetes
命名空间之间进行网络隔离
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: shoppingcart-netpolicy spec: podSelector: matchLabels: app: shopping-cart ingress: - from: - namespaceSelector: matchLabels: tenant: manning ports: - port: 80
|
使用CIDR
隔离网络
1 2 3 4
| ingress: - from: - ipBlock: cidr: 192.168.1.0/24
|
限制pod
的对外访问流量
1 2 3 4 5 6 7 8 9
| spec: podSelector: matchLabels: app: webserver egress: - to: - podSelector: matchLabels: app: database
|