
# 在CCE集群中使用容器的安全配置建议
#### 控制Pod调度范围
通过nodeSelector或者nodeAffinity限定应用所能调度的节点范围，防止单个应用异常威胁到整个集群。参考[节点亲和性](https://support.huaweicloud.com/usermanual-cce/cce_10_0232.html)。
在逻辑多租等需强隔离场景，系统插件应该尽量运行在单独的节点或者节点池上，与业务Pod分离，降低集群中的提权攻击风险。因此您可以在系统插件安装页面，将节点亲和策略设置为"指定节点调度"或"指定节点池调度"。
![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000002649810724.png "点击放大")
#### 容器安全配置建议
- 通过设置容器的计算资源限制（request和limit），避免容器占用大量资源影响宿主机和同节点其他容器的稳定性
- 如非必须，不建议将宿主机的敏感目录挂载到容器中，如/、/boot、/dev、/etc、/lib、/proc、/sys、/usr等目录
- 如非必须，不建议在容器中运行sshd进程
- 如非必须，不建议容器与宿主机共享网络命名空间
- 如非必须，不建议容器与宿主机共享进程命名空间
- 如非必须，不建议容器与宿主机共享IPC命名空间
- 如非必须，不建议容器与宿主机共享UTS命名空间
- 如非必须，不建议将docker的sock文件挂载到任何容器中
 
#### 容器的权限访问控制
使用容器应用时，遵循权限最小化原则，合理设置Deployment/Statefulset的securityContext：
- 通过配置runAsUser，指定容器使用非root用户运行。
- 通过配置privileged，在不需要特权的场景不建议使用特权容器。
- 通过配置capabilities，使用capability精确控制容器的特权访问权限。
- 通过配置allowPrivilegeEscalation, 在不需要容器进程提权的场景，建议关闭"允许特权逃逸"的配置。
- 通过配置安全计算模式seccomp，限制容器的系统调用权限，具体配置方法可参考社区官方资料[使用 Seccomp 限制容器的系统调用](https://kubernetes.io/docs/tutorials/security/seccomp/)。
- 通过配置ReadOnlyRootFilesystem的配置，保护容器根文件系统。 如deployment配置如下：
  ```
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: security-context-example
    namespace: security-example
  spec:
    replicas: 1
    selector:
      matchLabels:
        app: security-context-example
        label: security-context-example
    strategy:
      rollingUpdate:
        maxSurge: 25%
        maxUnavailable: 25%
      type: RollingUpdate
    template:
      metadata:
        annotations:
          seccomp.security.alpha.kubernetes.io/pod: runtime/default
        labels:
          app: security-context-example
          label: security-context-example
      spec:
        containers:
          - image: ...
            imagePullPolicy: Always
            name: security-context-example
            securityContext:
              allowPrivilegeEscalation: false
              readOnlyRootFilesystem: true
              runAsUser: 1000
              capabilities:
                add:
                - NET_BIND_SERVICE
                drop:
                - all
            volumeMounts:
              - mountPath: /etc/localtime
                name: localtime
                readOnly: true
              - mountPath: /opt/write-file-dir
                name: tmpfs-example-001
        securityContext:
          seccompProfile:
            type: RuntimeDefault
        volumes:
          - hostPath:
              path: /etc/localtime
              type: ""
            name: localtime
          - emptyDir: {}            
            name: tmpfs-example-001
  ```
  
 
#### 限制业务容器访问管理面
在节点上配置限制业务容器访问Kubernetes管理面操作时，需要谨慎评估以下事项，以避免不必要的服务中断。
- **评估节点上的容器是否均无需访问集群管理面**
  在节点上配置限制业务容器访问管理面操作后，该节点上的所有容器均无法访问集群kube-apiserver，建议您在配置前评估该节点上的容器是否都不需要访问集群kube-apiserver。
  需要注意，部分CCE插件（如CCE集群弹性引擎等）仍需要访问kube-apiserver，因此运行插件的节点不建议配置限制业务容器访问管理面。
  
- **为此类节点配置污点及亲和性调度**
  如果确认节点上的业务容器都不需要访问集群kube-apiserver，建议为此类节点配置标签及污点，并为容器配置[污点容忍](https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/taint-and-toleration/)和[节点亲和](https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity)调度，避免其他容器调度到该节点，以免出现业务异常。
  
限制业务容器访问管理面的操作步骤如下：
1. 查询容器网段和内网apiserver地址。 
   在CCE的"集群管理"界面查看集群的容器网段和内网apiserver地址。
   ![](https://support.huaweicloud.com/bestpractice-cce/zh-cn_image_0000002680050283.png "点击放大")
   
   
2. 设置容器网络流量访问规则。 
   - CCE集群：以root用户登录集群的每一个Node节点，执行以下命令：
     - VPC网络：
       ```
       iptables -I OUTPUT -s {container_cidr} -d {内网apiserver的IP} -j REJECT
       ```
       
     
     - 容器隧道网络：
       ```
       iptables -I FORWARD -s {container_cidr} -d {内网apiserver的IP} -j REJECT
       ```
       
     
     
     其中，{container_cidr}是集群的容器网络，如10.0.0.0/16。
     为保证配置持久化，建议将该命令写入/etc/rc.local 启动脚本中。
     
   
   - CCE Turbo集群：在集群的ENI安全组中添加出方向规则。
     1. 登录VPC控制台。
     
     2. 在左侧导航栏中选择"访问控制\>安全组"。
     
     3. 找到集群对应的ENI安全组，命名格式为**{集群名}-cce-eni-{随机ID}**，单击该安全组名称配置规则。
     
     4. 切换至"出方向规则"页签，并单击"添加规则"，为安全组添加出方向规则。
        - 优先级：设置为1。
        
        - 策略：选择"拒绝"，表示禁止访问目标地址。
        
        - 类型：选择"IPv4"。
        
        - 协议端口：根据内网apiserver地址中的端口，填写"5443"。
        
        - 目的地址：选择"IP地址"，并填写内网apiserver地址的IP。
         
     
     5. 填写完成后，单击"确定"。
      
   
   
   
   
3. 在容器中执行如下命令访问kube-apiserver接口，验证请求是否被拦截。 
   ```
   curl -k https://{内网apiserver的IP}:5443
   ```
   
   
 
#### 合理设置volume卷的传播模式
挂载主机路径时传播模式应设置为None，谨慎使用Bidirectional模式。
卷的挂载传播特性由Container.volumeMounts中的mountPropagation字段控制。 它的值包括：
- None：默认值，等同于[Linux内核文档](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt)中描述的private挂载传播选项。挂载后将不会感知到主机后续在此卷或其任何子目录上执行的挂载变化；同样，容器所创建的卷挂载在主机上不可见。

- HostToContainer：等同于[Linux内核文档](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt)中描述的rslave挂载传播选项。挂载后将会感知到主机后续针对此卷或其任何子目录的挂载操作，如果主机在此挂载卷中挂载任何内容，容器将能看到它被挂载在那里。配置了Bidirectional挂载传播选项的Pod如果在同一卷上挂载了内容，挂载传播设置为HostToContainer的容器都将能看到这一变化。

- Bidirectional：等同于[Linux内核文档](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt)中描述的rshared挂载传播选项。容器创建的卷挂载将被传播回至主机和使用同一卷的所有Pod的所有容器。
  容器挂载卷使用Bidirectional它可以破坏主机操作系统，因此它只被允许在特权容器中使用。示例如下：
  ```
  apiVersion: v1
  kind: Pod
  metadata:
      name: security-mount
      label:
        app: security-mount
  spec:
      containers:
      - name: security-mount
        image: ...
        volumeMounts:
        - name: mount-none
          mountPath: /opt
          mountPropagation: None
      volumes:
      - name: mount-none
        hostPath:
          path: /opt/
  ```
  
详细请参考：[社区介绍](https://kubernetes.io/docs/concepts/storage/volumes/)
