• kubernetes高级之pod安全策略


    系列目录

    什么是pod安全策略

    pod安全策略是集群级别的用于控制pod安全相关选项的一种资源.PodSecurityPolicy定义了一系列pod相要进行在系统中必须满足的约束条件,以衣一些默认的约束值.它允许管理员控制以下方面内容

    Control Aspect Field Names
    以特权运行容器 privileged
    使用宿主名称空间 hostPID, hostIPC
    使用宿主网络和端口 hostNetwork, hostPorts
    使用存储卷类型 volumes
    使用宿主机文件系统 allowedHostPaths
    flex存储卷白名单 allowedFlexVolumes
    分配拥有 Pod 数据卷的 FSGroup fsGroup
    只读root文件系统 readOnlyRootFilesystem
    容器的用户id和组id runAsUser, runAsGroup, supplementalGroups
    禁止提升到root权限 allowPrivilegeEscalation, defaultAllowPrivilegeEscalation
    Linux能力 defaultAddCapabilities, requiredDropCapabilities, allowedCapabilities
    SELinux上下文 seLinux
    允许容器加载的proc类型 allowedProcMountTypes
    The AppArmor profile used by containers annotations
    The seccomp profile used by containers annotations
    The sysctl profile used by containers annotations

    启用pod安全策略

    pod安全策略作为可选的(但强烈建议的)admission controller的实现.pod安全策略通过启用admission controller来实现,但是仅仅启用而没有对策略授权则会导致整个集群无法创建pod!

    由于pod安全策略api(policy/v1beta1/podsecuritypolicy)独立于admission controller之外启用,对于已经存在的集群建议在启用admission controller之前添加并授权策略.

    授权策略

    当一个pod安全策略资源被创建(前面说过,psp(PodSecurityPolicy )pod安全策略是一种kubernetes资源),它什么都不会做.为了使用它,请求操作的用户或者目标pod的serviceaccount必须通过策略的use动词来授权.

    绝大部分kubernetes pod并不是直接由用户直接创建的.相反,典型使用场景是它们通过Deployment或者ReplicaSet间接被创建,或者通过控制器管理器的其它模板控制器来创建.对控制器进行策略授权也将对它所创建的所有pod进行策略授权.因此首选的授权方法是对pod的serviceaccount进行策略授权(后面有示例).

    通过RBAC授权

    RBAC是kubernetes标准的授权模式,并且很容易用于授权安全策略使用.

    首先,一个角色(role)或者集群角色(clusterRole)需要被授权使用(use动词)它想要的策略.对角色的授权类似下面

    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: <role name>
    rules:
    - apiGroups: ['policy']
      resources: ['podsecuritypolicies']
      verbs:     ['use']
      resourceNames:
      - 一系列要进行授权的资源名称
    

    然后把集群角色(或角色)与授权的用户绑定

    kind: ClusterRoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: 绑定名称
    roleRef:
      kind: ClusterRole
      name: 角色名称
      apiGroup: rbac.authorization.k8s.io
    subjects:
    # Authorize specific service accounts:
    - kind: ServiceAccount
      name: 授权的serviceaccount名称
      namespace: <authorized pod namespace>
    # Authorize specific users (not recommended):
    - kind: User
      apiGroup: rbac.authorization.k8s.io
      name: 授权的用户名
    

    如果一个角色绑定(不是集群角色绑定)被使用,它仅对和它处于同一名称空间下的pod才能进行有效策略授权,这样同样适用于用户和用户组

    # Authorize all service accounts in a namespace:
    - kind: Group
      apiGroup: rbac.authorization.k8s.io
      name: system:serviceaccounts
    # Or equivalently, all authenticated users in a namespace:
    - kind: Group
      apiGroup: rbac.authorization.k8s.io
      name: system:authenticated
    

    故障排除

    控制器管理器必须运行在安全的api端口上,并且不能有超级权限.不然请求就会绕过认证和授权模块,将导致所有的策略均被允许,并且用户可以创建特权pod

    策略顺序

    除了限制pod的创建和更新,pod安全策略还用于提供它所控制的诸多字段的默认值.当有多个策略时,pod安全策略根据以下因素来选择策略

    • 任何成功通过验证没有警告的策略将被使用

    • 如果是请求创建pod,则按通过验证的策略按字母表顺序被选用

    • 否则,如果是一个更新请求,将会返回错误.因为在更新操作过程中不允许pod变化

    示例

    以下示例假定你运行的集群开启了pod安全策略admission controller并且你有集群管理员权限

    初始设置

    我们为示例创建一个名称空间和一个serviceaccount.我们使用这个serviceaccount来模拟一个非管理员用户

    kubectl create namespace psp-example
    kubectl create serviceaccount -n psp-example fake-user
    kubectl create rolebinding -n psp-example fake-editor --clusterrole=edit --serviceaccount=psp-example:fake-user
    

    为了方便辨认我们使用的账户,我们创建两个别名

    alias kubectl-admin='kubectl -n psp-example'
    alias kubectl-user='kubectl --as=system:serviceaccount:psp-example:fake-user -n psp-example'
    

    创建一个策略和一个pod

    以下定义文件定义了一个简单pod安全策略(PodSecurityPolicy),这个策略仅仅阻止创建特权pod

    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:
      - '*'
    

    我们使用kubectl命令来应用以上文件.

    现在,做为一个非特权用户,我们创建一个简单pod

    kubectl-user create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name:      pause
    spec:
      containers:
        - name:  pause
          image: k8s.gcr.io/pause
    EOF
    Error from server (Forbidden): error when creating "STDIN": pods "pause" is forbidden: unable to validate against any pod security policy: []
    

    发生了什么?尽管pod安全策略已创建,不管是pod的serviceaccount还是fack-user都没有权限使用这个策略.

    kubectl-user auth can-i use podsecuritypolicy/example
    no
    

    创建一个rolebing来授权fake-user来使用example策略(example是前面创建的策略的名称)

    但是请注意这里并不是首选方式!后面的示例将介绍首选的方式

    kubectl-admin create role psp:unprivileged 
        --verb=use 
        --resource=podsecuritypolicy 
        --resource-name=example
    role "psp:unprivileged" created
    
    kubectl-admin create rolebinding fake-user:psp:unprivileged 
        --role=psp:unprivileged 
        --serviceaccount=psp-example:fake-user
    rolebinding "fake-user:psp:unprivileged" created
    
    kubectl-user auth can-i use podsecuritypolicy/example
    yes
    

    此时,再重新尝试创建pod

    kubectl-user create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name:      pause
    spec:
      containers:
        - name:  pause
          image: k8s.gcr.io/pause
    EOF
    pod "pause" created
    

    这次正如我们期待的一样,可以正常工作.但是试图创建特权pod仍然会被阻止(因此策略本身阻止创建特权pod)

    kubectl-user create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name:      privileged
    spec:
      containers:
        - name:  pause
          image: k8s.gcr.io/pause
          securityContext:
            privileged: true
    EOF
    Error from server (Forbidden): error when creating "STDIN": pods "privileged" is forbidden: unable to validate against any pod security policy: [spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed]
    

    再运行一个其它pod

    我们再尝试创建一个pod,这次有一点不同

    ubectl-user run pause --image=k8s.gcr.io/pause
    deployment "pause" created
    
    kubectl-user get pods
    No resources found.
    
    kubectl-user get events | head -n 2
    LASTSEEN   FIRSTSEEN   COUNT     NAME              KIND         SUBOBJECT                TYPE      REASON                  SOURCE                                  MESSAGE
    1m         2m          15        pause-7774d79b5   ReplicaSet                            Warning   FailedCreate            replicaset-controller                   Error creating: pods "pause-7774d79b5-" is forbidden: no providers available to validate pod request
    

    从以上可以看到deployment已经成功创建(kubectl run 实际上会创建一个deployment).但是使用kubectl get pod命令却没有发现pod被创建.这是为什么?问题的答案隐藏在replicaset控制器里.Fake-user成功创建的deployment(deployment又成功创建replicaset),但是当replicaset尝试创建pod的时候,它并没有被授权使用example定义的策略.

    为了解决这个问题,需要把psp:unprivileged角色(前面创建的)绑定到pod的serviceaccount上(前面我们是绑定在了fake-user上).这里serviceaccount是default(因为我们没有指定其它用户)

    看到这里如果你仍然觉得难以理解,可以回头再看看,还是无法理解的话则需要补充关于角色,用户和RBAC相关的知识.

    kubectl-admin create rolebinding default:psp:unprivileged 
        --role=psp:unprivileged 
        --serviceaccount=psp-example:default
    rolebinding "default:psp:unprivileged" created
    

    这时候等待若干分钟,replicaset的控制器最终会成功创建pod

    kubectl-user get pods --watch
    NAME                    READY     STATUS    RESTARTS   AGE
    pause-7774d79b5-qrgcb   0/1       Pending   0         1s
    pause-7774d79b5-qrgcb   0/1       Pending   0         1s
    pause-7774d79b5-qrgcb   0/1       ContainerCreating   0         1s
    pause-7774d79b5-qrgcb   1/1       Running   0         2s
    

    清理工作

    删除名称空间以删除绝大部分示例中用到的资源

    kubectl-admin delete ns psp-example
    namespace "psp-example" deleted
    

    注意现在刚刚创建的pod安全策略已经没有了名称空间,并且需要单独被清除

    kubectl-admin delete psp example
    podsecuritypolicy "example" deleted
    

    策略示例

    以下是一个最小限制的策略,和不使用pod安生策略admission controller效果一样

    apiVersion: policy/v1beta1
    kind: PodSecurityPolicy
    metadata:
      name: privileged
      annotations:
        seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
    spec:
      privileged: true
      allowPrivilegeEscalation: true
      allowedCapabilities:
      - '*'
      volumes:
      - '*'
      hostNetwork: true
      hostPorts:
      - min: 0
        max: 65535
      hostIPC: true
      hostPID: true
      runAsUser:
        rule: 'RunAsAny'
      seLinux:
        rule: 'RunAsAny'
      supplementalGroups:
        rule: 'RunAsAny'
      fsGroup:
        rule: 'RunAsAny'
    

    以下的一个示例有限制性策略,需要用户是一个非特权用户,阻止pod的权限提升

    之所以要求是非特权用户,因为特权用户将会绕过限制

    apiVersion: policy/v1beta1
    kind: PodSecurityPolicy
    metadata:
      name: restricted
      annotations:
        seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
        apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
        seccomp.security.alpha.kubernetes.io/defaultProfileName:  'docker/default'
        apparmor.security.beta.kubernetes.io/defaultProfileName:  'runtime/default'
    spec:
      privileged: false
      # Required to prevent escalations to root.
      allowPrivilegeEscalation: false
      # This is redundant with non-root + disallow privilege escalation,
      # but we can provide it for defense in depth.
      requiredDropCapabilities:
        - ALL
      # Allow core volume types.
      volumes:
        - 'configMap'
        - 'emptyDir'
        - 'projected'
        - 'secret'
        - 'downwardAPI'
        # Assume that persistentVolumes set up by the cluster admin are safe to use.
        - 'persistentVolumeClaim'
      hostNetwork: false
      hostIPC: false
      hostPID: false
      runAsUser:
        # Require the container to run without root privileges.
        rule: 'MustRunAsNonRoot'
      seLinux:
        # This policy assumes the nodes are using AppArmor rather than SELinux.
        rule: 'RunAsAny'
      supplementalGroups:
        rule: 'MustRunAs'
        ranges:
          # Forbid adding the root group.
          - min: 1
            max: 65535
      fsGroup:
        rule: 'MustRunAs'
        ranges:
          # Forbid adding the root group.
          - min: 1
            max: 65535
      readOnlyRootFilesystem: false
    

    策略参考

    特权的

    它决定了pod中的所有容器是否被允许以特权方式运行.默认情况下容器不允许访问主机的设备,但是特权容器却被允许访问.这将允许容器有几乎和它所在的进程一样的访问主机的权利.这将非常有用当容器想要使用主机的功能,比如访问网络的设备.

    Host名称空间

    HostPID - 控制容器是否可以共享主机的进程id名称空间

    HostIPC - 控制容器是否可以共享主机的IPC名称空间

    HostNetwork - 控制容器是否可以使用所在节点的网络名称空间.这将允许pod访问回环设备,监听localhost,并且可以窥探同一节点上其它pod的网络活动状况

    AllowedHostPaths - 控制允许访问的宿主机路径

    存储卷和文件系统

    Volumes - 提供了一系列的存储卷类型白名单.这些允许的值和创建存储卷时定义的资源类型相对应.想要获取所有存储卷类型,可以查看存储卷类型列表.此外,*可以被用来允许所有的存储卷类型

    以下是推荐的最小化的允许存储卷类型的安全策略配置

    • configMap
    • downwardAPI
    • emptyDir
    • persistentVolumeClaim
    • secret
    • projected

    AllowedHostPaths- 它定义了一个hostPath类型的存储卷可用的宿主机路径的白名单.空集群意味着对宿主机的path无使用限制.它被定义为一个包含了一系列对象的单个pathPrefix字段,允许hostpath类型的存储卷挂载以pathPrefix字段开头的宿主机路径.readonly字段意味着必须以readonly方式挂载(即不能写入,只能读)

    allowedHostPaths:
      # This allows "/foo", "/foo/", "/foo/bar" etc., but
      # disallows "/fool", "/etc/foo" etc.
      # "/foo/../" is never valid.
      - pathPrefix: "/foo"
        readOnly: true # only allow read-only mounts
    

    警告,一个可以无限制访问宿主机文件系统的容器可以有很多方式提升权限,包括读取其它容器内的数据,滥用系统服务的密钥,比如kubecctl

    可写的hostpath目录存储卷允许容器写入到宿主机文件系统,并且可以遍历pathPrefix以外的文件系统,readOnly: true在kubernetes 1.11+版本以后才能使用,并且在allowedHostPaths必须使用以有效限制访问特定的pathPrefix

    ReadOnlyRootFilesystem - 限制容器必须以只读的root文件系统运行(没有可写层)

    特权提升

    这个选项控制着容器的allowPrivilegeEscalation选项.这个布尔值直接控制着no_new_privs是否设置到容器运行的进程.它将阻止setuid来改变user ID,并且阻止文件有其它的能力(比如禁止使用ping工具).这个行为需要启用MustRunAsNonRoot

    AllowPrivilegeEscalation- 它决定着容器的安全上下文是否可以设置allowPrivilegeEscalation=true,为true是默认值.设置为false将使得容器所有的子进程没有比父进程更高的特权

    DefaultAllowPrivilegeEscalation,为allowPrivilegeEscalation设置默认值,从上面可以看到,默认的值为true.如果这个行为不是我们期待的,这个字段可以用于把它设置为不允许,但是仍然pod显式请求allowPrivilegeEscalation

  • 相关阅读:
    net core 使用 rabbitmq
    asp.net core WebApi 返回 HttpResponseMessage
    asp.net core 2.1 WebApi 快速入门
    JQuery EasyUI combobox动态添加option
    php截取字符去掉最后一个字符
    JQuery EasyUI Combobox的onChange事件
    对于不返回任何键列信息的 selectcommand 不支持 updatecommand 的动态 sql 生成
    Access2007 操作或事件已被禁用模式阻止解决办法
    Easyui 中 Tabsr的常用方法
    Win 7 IE11不能下载文件,右键另存为也不行
  • 原文地址:https://www.cnblogs.com/tylerzhou/p/11078128.html
Copyright © 2020-2023  润新知