kubectl_进阶_安全

种地  金牌会员 | 2024-8-25 01:46:57 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 922|帖子 922|积分 2766

安全

在前面的学习中,我们知道对于资源对象的操作都是通过 APIServer 进行的,那么集群是怎样知道我们的哀求就是合法的哀求呢?
这就涉及到k8s的安全相关的知识了。
1. API对象

Kubernetes有一个很基本的特性就是它的所有资源对象都是模子化的API对象,允许执行 CRUD(Create、Read、Update、Delete)操作(也就是我们常说的增、删、改、查操作),比如下面的这下资源:


  • Pods
  • Deployments
  • Namespaces
上面这些资源对象的可能存在的操作有:


  • create
  • get
  • delete
  • list
  • update
  • edit
  • watch
  • exec
前面我们都直接编写的 YAML 文件,通过 kubectl 来提交的资源清单文件,然后创建的对应的资源对象,那么它究竟是如何将我们的 YAML 文件转换成集群中的一个 API 对象的呢?
这个就必要去相识下声明式 API的设计,Kubernetes API 是一个以 JSON 为重要序列化方式的 HTTP 服务,除此之外也支持 Protocol Buffers 序列化方式,重要用于集群内部组件间的通信。为了可扩展性,Kubernetes 在不同的 API 路径(比如/api/v1 或者 /apis/batch)下面支持了多个 API 版本,不同的 API 版本意味着不同级别的稳定性和支持:


  • Alpha 级别,比方 v1alpha1 默认情况下是被禁用的,可以随时删除对功能的支持,所以要慎用
  • Beta 级别,比方 v2beta1 默认情况下是启用的,表当代码已经经过了很好的测试,但是对象的语义可能会在随后的版本中以不兼容的方式更改
  • 稳定级别,比如 v1 表现已经是稳定版本了,也会出现在后续的很多版本中。
在 Kubernetes 集群中,一个API 对象在 Etcd 里的完整资源路径,是由:Group(API 组)、Version(API 版本)和 Resource(API 资源范例)三个部分组成的。通过如许的结构,整个 Kubernetes 里的所有 API 对象,实际上就可以用如下的树形结构表现出来:

我们也可以用下面的命令来检察集群中的 API 构造情势:
  1. [root@master ~]# kubectl get --raw /
  2. {
  3.   "paths": [
  4.     "/.well-known/openid-configuration",
  5.     "/api",
  6.     "/api/v1",
  7.     "/apis",
  8.     "/apis/",
  9.     "/apis/admissionregistration.k8s.io",
  10.     "/apis/admissionregistration.k8s.io/v1",
  11.     "/apis/apiextensions.k8s.io",
  12.     "/apis/apiextensions.k8s.io/v1",
  13.     "/apis/apiregistration.k8s.io",
  14.     "/apis/apiregistration.k8s.io/v1",
  15.     "/apis/apps",
  16.     "/apis/apps/v1",
  17.     "/apis/authentication.k8s.io",
  18.     "/apis/authentication.k8s.io/v1",
  19.     "/apis/authorization.k8s.io",
复制代码
API 组 能够简化对 Kubernetes API 的扩展。 API 组信息出现在REST 路径中,也出现在序列化对象的 apiVersion 字段中。
以下是 Kubernetes 中的几个组:


  • 核心(也叫 legacy)组的 REST 路径为 /api/v1。 核心组并不作为 apiVersion 字段的一部分,比方, apiVersion: v1。
  • 指定的组位于 REST 路径 /apis/$GROUP_NAME/$VERSION, 并且使用 apiVersion: $GROUP_NAME/$VERSION (比方, apiVersion: batch/v1)。
Kubernetes 通常使用常见的 RESTful 术语来描述 API 概念:


  • 资源范例(Resource Type) 是 URL 中使用的名称(pods、namespaces、services)
  • 所有资源范例都有一个具体的表现(它们的对象模式),称为 类别(Kind)
  • 资源实例的列表称为 集合(Collection)
  • 资源范例的单个实例称为 资源(Resource),通常也表现一个 对象(Object)
  • 对于某些资源范例,API 包含一个或多个 子资源(sub-resources),这些子资源表现为资源下的 URI 路径
所有资源范例要么是集群作用域的(/apis/GROUP/VERSION/*),要么是命名空间作用域的(/apis/GROUP/VERSION/namespaces/NAMESPACE/*)。 命名空间作用域的资源范例会在其命名空间被删除时也被删除,并且对该资源范例的访问是由界说在命名空间域中的授权查抄来控制的。
比如我们来检察批处理这个操作,在我们当前这个版本中存在两个版本的操作:/apis/batch/v1 和 /apis/batch/v1beta1,分别暴露了可以查询和操作的不同实体集合:
  1. [root@master ~]# kubectl get --raw /apis/batch/v1 | python -m json.tool
  2. {
  3.     "apiVersion": "v1",
  4.     "groupVersion": "batch/v1",
  5.     "kind": "APIResourceList",
  6.     "resources": [
  7.         {
  8.             "categories": [
  9.                 "all"
  10.             ],
  11.             "kind": "CronJob",
  12.             "name": "cronjobs",
  13.             "namespaced": true,
  14.             "shortNames": [
  15.                 "cj"
  16.             ],
  17.             "singularName": "",
  18.             "storageVersionHash": "sd5LIXh4Fjs=",
  19.             "verbs": [
  20.                 "create",
  21.                 "delete",
  22.                 "deletecollection",
  23.                 "get",
  24.                 "list",
  25.                 "patch",
  26.                 "update",
  27.                 "watch"
  28.             ]
  29.         },
  30.         {
  31.             "kind": "CronJob",
  32.             "name": "cronjobs/status",
  33.             "namespaced": true,
  34.             "singularName": "",
  35.             "verbs": [
  36.                 "get",
  37.                 "patch",
  38.                 "update"
  39.             ]
  40.         },
  41.         {
  42.             "categories": [
  43.                 "all"
  44.             ],
  45.             "kind": "Job",
  46.             "name": "jobs",
  47.             "namespaced": true,
  48.             "singularName": "",
  49.             "storageVersionHash": "mudhfqk/qZY=",
  50.             "verbs": [
  51.                 "create",
  52.                 "delete",
  53.                 "deletecollection",
  54.                 "get",
  55.                 "list",
  56.                 "patch",
  57.                 "update",
  58.                 "watch"
  59.             ]
  60.         },
  61.         {
  62.             "kind": "Job",
  63.             "name": "jobs/status",
  64.             "namespaced": true,
  65.             "singularName": "",
  66.             "verbs": [
  67.                 "get",
  68.                 "patch",
  69.                 "update"
  70.             ]
  71.         }
  72.     ]
  73. }
  74. [root@master ~]# kubectl get --raw /apis/batch/v1beta1 | python -m json.tool
  75. {
  76.     "apiVersion": "v1",
  77.     "groupVersion": "batch/v1beta1",
  78.     "kind": "APIResourceList",
  79.     "resources": [
  80.         {
  81.             "categories": [
  82.                 "all"
  83.             ],
  84.             "kind": "CronJob",
  85.             "name": "cronjobs",
  86.             "namespaced": true,
  87.             "shortNames": [
  88.                 "cj"
  89.             ],
  90.             "singularName": "",
  91.             "storageVersionHash": "sd5LIXh4Fjs=",
  92.             "verbs": [
  93.                 "create",
  94.                 "delete",
  95.                 "deletecollection",
  96.                 "get",
  97.                 "list",
  98.                 "patch",
  99.                 "update",
  100.                 "watch"
  101.             ]
  102.         },
  103.         {
  104.             "kind": "CronJob",
  105.             "name": "cronjobs/status",
  106.             "namespaced": true,
  107.             "singularName": "",
  108.             "verbs": [
  109.                 "get",
  110.                 "patch",
  111.                 "update"
  112.             ]
  113.         }
  114.     ]
  115. }
复制代码
但是这个操作和我们平时操作 HTTP 服务的方式不太一样,这里我们可以通过 kubectl proxy 命令来开启对 apiserver 的访问:
  1. [root@master ~]# kubectl proxy
  2. Starting to serve on 127.0.0.1:8001
复制代码
然后重新开启一个新的终端,我们可以通过如下方式来访问批处理的 API 服务:
  1. [root@master ~]# curl http://127.0.0.1:8001/apis/batch/v1
  2. {
  3.   "kind": "APIResourceList",
  4.   "apiVersion": "v1",
  5.   "groupVersion": "batch/v1",
  6.   "resources": [
  7.     {
  8.       "name": "cronjobs",
  9.       "singularName": "",
  10.       "namespaced": true,
  11.       "kind": "CronJob",
  12.       "verbs": [
  13.         "create",
  14.         "delete",
  15.         "deletecollection",
  16.         "get",
  17.         "list",
  18.         "patch",
  19.         "update",
  20.         "watch"
  21.       ],
  22.       "shortNames": [
  23.         "cj"
  24.       ],
  25.       "categories": [
  26.         "all"
  27.       ],
  28.       "storageVersionHash": "sd5LIXh4Fjs="
  29.     },
  30.     {
  31.       "name": "cronjobs/status",
  32.       "singularName": "",
  33.       "namespaced": true,
  34.       "kind": "CronJob",
  35.       "verbs": [
  36.         "get",
  37.         "patch",
  38.         "update"
  39.       ]
  40.     },
  41.     {
  42.       "name": "jobs",
  43.       "singularName": "",
  44.       "namespaced": true,
  45.       "kind": "Job",
  46.       "verbs": [
  47.         "create",
  48.         "delete",
  49.         "deletecollection",
  50.         "get",
  51.         "list",
  52.         "patch",
  53.         "update",
  54.         "watch"
  55.       ],
  56.       "categories": [
  57.         "all"
  58.       ],
  59.       "storageVersionHash": "mudhfqk/qZY="
  60.     },
  61.     {
  62.       "name": "jobs/status",
  63.       "singularName": "",
  64.       "namespaced": true,
  65.       "kind": "Job",
  66.       "verbs": [
  67.         "get",
  68.         "patch",
  69.         "update"
  70.       ]
  71.     }
  72.   ]
  73. }
复制代码
通常,Kubernetes API 支持通过标准 HTTP POST、PUT、DELETE 和 GET 在指定 PATH 路径上创建、更新、删除和检索操作,并使用 JSON 作为默认的数据交互格式。
比如现在我们要创建一个 Deployment 对象,那么我们的 YAML 文件的声明就必要怎么写:
  1. apiVersion: apps/v1
  2. kind: Deployment
复制代码
其中 Deployment 就是这个 API 对象的资源范例(Resource),apps 就是它的组(Group),v1 就是它的版本(Version)。API Group、Version 和 资源就唯一界说了一个 HTTP 路径,然后在 kube-apiserver 端对这个 url 进行了监听,然后把对应的哀求传递给了对应的控制器进行处理。
2. RBAC

RBAC,基于角色的访问控制机制,是用来管理 kubernetes 集群中资源访问权限的机制。使用 RBAC 可以很方便的更新访问授权策略而不消重启集群。
Kubernetes 从 1.6 开始支持基于角色的访问控制机制(Role-Based Access,RBAC),集群管理员可以对用户或服务账号的角色进行更准确的资源访问控制。在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。在一个构造中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。
从 Kubernetes 1.8 开始,RBAC 进入稳定版,其 API 为 rbac.authorization.k8s.io/v1。
在使用 RBAC 时,只必要在启动 kube-apiserver 时设置 --authorization-mode=RBAC 即可。
假如使用的kubeadm安装的集群,1.6 版本以上的都默认开启了RBAC,可以通过检察 Master 节点上 apiserver 的静态Pod界说文件:
  1. [root@master ~]# cat /etc/kubernetes/manifests/kube-apiserver.yaml
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5.   annotations:
  6.     kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 192.168.200.101:6443
  7.   creationTimestamp: null
  8.   labels:
  9.     component: kube-apiserver
  10.     tier: control-plane
  11.   name: kube-apiserver
  12.   namespace: kube-system
  13. spec:
  14.   containers:
  15.   - command:
  16.     - kube-apiserver
  17.     - --advertise-address=192.168.200.101
  18.     - --allow-privileged=true
  19.     - --authorization-mode=Node,RBAC
复制代码
假如是二进制的方式搭建的集群,添加这个参数过后,记得要重启 kube-apiserver 服务。
在更上层,这些资源和 API Group 进行关联,比如 Pods 属于 Core API Group,而 Deployements 属于 apps API Group,现在我们要在 Kubernetes 中通过 RBAC 来对资源进行权限管理,除了上面的这些资源和操作以外,我们还必要相识另外几个概念:


  • Rule:规则,规则是一组属于不同 API Group 资源上的一组操作的集合
  • Role 和 ClusterRole:角色和集群角色,这两个对象都包含上面的 Rules 元素,二者的区别在于,在 Role 中,界说的规则只适用于单个命名空间,也就是和 namespace 关联的,而 ClusterRole 是集群范围内的,因此界说的规则不奉命名空间的约束。另外 Role 和 ClusterRole 在Kubernetes 中都被界说为集群内部的 API 资源,和我们前面学习过的 Pod、Deployment 这些对象类似,都是我们集群的资源对象,所以同样的可以使用 YAML 文件来描述,用 kubectl 工具来管理
  • Subject:主题,对应集群中尝试操作的对象,集群中界说了3种范例的主题资源:

    • User Account:用户,这是有外部独立服务进行管理的,管理员进行私钥的分配,用户可以使用 KeyStone 或者 Goolge 帐号,甚至一个用户名和暗码的文件列表也可以。对于用户的管理集群内部没有一个关联的资源对象,所以用户不能通过集群内部的 API 来进行管理
    • Group:组,这是用来关联多个账户的,集群中有一些默认创建的组,比如 cluster-admin
    • Service Account:服务帐号,通过 Kubernetes API 来管理的一些用户帐号,和 namespace 进行关联的,适用于集群内部运行的应用程序,必要通过 API 来完成权限认证,所以在集群内部进行权限操作,我们都必要使用到 ServiceAccount

  • RoleBinding 和 ClusterRoleBinding:角色绑定和集群角色绑定,简单来说就是把声明的 Subject 和我们的 Role 进行绑定的过程(给某个用户绑定上操作的权限),二者的区别也是作用范围的区别:RoleBinding 只会影响到当前 namespace 下面的资源操作权限,而 ClusterRoleBinding 会影响到所有的 namespace。
2.1 只能访问某个 namespace 的平凡用户

我们想要创建一个 User Account,只能访问 kube-system 这个命名空间,对应的用户信息如下所示:
  1. username: ms
  2. group: msk8s
复制代码
2.1.1 创建用户根据

Kubernetes 没有 User Account 的 API 对象,使用管理员分配一个私钥的方式来创建,所以使用 OpenSSL 证书来创建一个 User:
  1. #给用户 ms 创建一个私钥,命名成 ms.key
  2. [root@master ~]# cd /mnt/k8s/rabc
  3. [root@master rabc]# openssl genrsa -out ms.key 2048     
  4. Generating RSA private key, 2048 bit long modulus
  5. ...........+++
  6. ..............................................................................................................+++
  7. e is 65537 (0x10001)
复制代码
使用我们刚刚创建的私钥创建一个证书签名哀求文件:ms.csr,要留意必要确保在-subj参数中指定用户名和组(CN表现用户名,O表现组):
  1. [root@master rabc]# openssl req -new -key ms.key -out ms.csr -subj "/CN=ms/O=msk8s"
复制代码
然后找到我们的 Kubernetes 集群的 CA 证书,我们使用的是 kubeadm 安装的集群,CA 相关证书位于 /etc/kubernetes/pki/ 目次下面,假如你是二进制方式搭建的,你应该在最开始搭建集群的时候就已经指定好了 CA 的目次,我们会使用该目次下面的 ca.crt 和 ca.key两个文件来答应上面的证书哀求。生成终极的证书文件,我们这里设置证书的有效期为 500 天:
  1. [root@master rabc]# openssl x509 -req -in ms.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ms.crt -days 500     
  2. Signature ok
  3. subject=/CN=ms/O=msk8s
  4. Getting CA Private Key
复制代码
现在检察我们当前文件夹下面是否生成了一个证书文件:
  1. [root@master rabc]# ls
  2. ms.crt  ms.csr  ms.key
复制代码
现在我们可以使用刚刚创建的证书文件和私钥文件在集群中创建新的根据和上下文(Context):
  1. [root@master rabc]# kubectl config set-credentials ms --client-certificate=ms.crt --client-key=ms.key            
  2. User "ms" set.
复制代码
我们可以看到一个用户 ms 创建了,然后为这个用户设置新的 Context,我们这里指定特定的一个 namespace:
  1. [root@master rabc]#  kubectl config set-context ms-context --cluster=kubernetes --namespace=kube-system --user=ms
  2. Context "ms-context" created.
复制代码
到这里,我们的用户 ms 就已经创建乐成了,现在我们使用当前的这个设置文件来操作 kubectl 命令的时候,应该会出现错误,由于我们还没有为该用户界说任何操作的权限呢:
  1. [root@master rabc]# kubectl get pods --context=ms-context   
  2. Error from server (Forbidden): pods is forbidden: User "ms" cannot list resource "pods" in API group "" in the namespace "kube-system"
复制代码
2.1.2 创建角色

用户创建完成后,接下来就必要给该用户添加操作权限,我们来界说一个 YAML 文件,创建一个允许用户操作 Deployment、Pod、ReplicaSets 的角色,如下界说:(ms-role.yaml)
  1. apiVersion: rbac.authorization.k8s.io/v1
  2. kind: Role
  3. metadata:
  4.   name: ms-role
  5.   namespace: kube-system
  6. rules:
  7. - apiGroups: ["", "apps"]
  8.   resources: ["deployments", "replicasets", "pods"]
  9.   verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 也可以使用['*']
复制代码
其中 Pod 属于 core 这个 API Group,在 YAML 中用空字符就可以,而 Deployment 和 ReplicaSet 现在都属于 apps 这个 API Group(假如不知道则可以用 kubectl explain 命令检察),所以 rules 下面的 apiGroups 就综合了这几个资源的 API Group:[“”, “apps”],其中verbs 就是我们上面提到的可以对这些资源对象执行的操作,我们这里必要所有的操作方法,所以我们也可以使用[‘*’]来代替。然后直接创建这个 Role:
  1. [root@master rabc]#  kubectl create -f ms-role.yaml
  2. role.rbac.authorization.k8s.io/ms-role created
复制代码
留意这里我们没有使用上面的 ms-context 这个上下文,因此临时还木有权限。
2.1.3 创建角色权限绑定

Role 创建完成了,但是很明显现在我们这个 Role 和我们的用户 ms 还没有任何关系,对吧?这里就必要创建一个 RoleBinding 对象,在 kube-system 这个命名空间下面将上面的 ms-role 角色和用户 ms 进行绑定:(ms-rolebinding.yaml)
  1. apiVersion: rbac.authorization.k8s.io/v1
  2. kind: RoleBinding
  3. metadata:
  4.   name: ms-rolebinding
  5.   namespace: kube-system
  6. subjects:
  7. - kind: User
  8.   name: ms
  9.   apiGroup: ""
  10. roleRef:
  11.   kind: Role
  12.   name: ms-role
  13.   apiGroup: rbac.authorization.k8s.io  # 留空字符串也可以,则使用当前的apiGroup
复制代码
上面的 YAML 文件中我们看到了 subjects 字段,这里就是我们上面提到的用来尝试操作集群的对象,这里对应上面的 User 帐号 ms,使用kubectl 创建上面的资源对象:
  1. [root@master rabc]# kubectl create -f ms-rolebinding.yaml   
  2. rolebinding.rbac.authorization.k8s.io/ms-rolebinding created
复制代码
2.1.4 测试

现在我们应该可以上面的 ms-context 上下文来操作集群了:
  1. [root@master ~]# kubectl get pods --context=ms-context
  2. NAME                              READY   STATUS    RESTARTS          AGE
  3. coredns-6d8c4cb4d-8tqtt           1/1     Running   395 (4m54s ago)   11d
  4. coredns-6d8c4cb4d-vm7fx           1/1     Running   393 (4m54s ago)   11d
  5. etcd-master                       1/1     Running   13 (4m59s ago)    11d
  6. kube-apiserver-master             1/1     Running   14 (4m48s ago)    11d
  7. kube-controller-manager-master    1/1     Running   10 (4m59s ago)    11d
  8. kube-proxy-bdcdg                  1/1     Running   0                 2d6h
  9. kube-proxy-pr7nr                  1/1     Running   4 (4m59s ago)     2d6h
  10. kube-proxy-wgsrp                  1/1     Running   0                 2d6h
  11. kube-scheduler-master             1/1     Running   12 (4m58s ago)    11d
  12. metrics-server-75c5f8c9f7-c429g   1/1     Running   1 (2d6h ago)      2d18h
  13. [root@master rabc]# kubectl --context=ms-context get rs,deploy     
  14. NAME                                        DESIRED   CURRENT   READY   AGE
  15. replicaset.apps/coredns-6d8c4cb4d           2         2         0       11d
  16. replicaset.apps/metrics-server-75c5f8c9f7   1         1         1       2d18h
  17. NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
  18. deployment.apps/coredns          0/2     2            0           11d
  19. deployment.apps/metrics-server   1/1     1            1           2d18h
复制代码
我们可以看到我们使用 kubectl 的使用并没有指定 namespace,这是由于我们我们上面创建这个 Context 的时候就绑定在了 kube-system 这个命名空间下面,假如我们在背面加上一个-n default试看看呢?
  1. [root@master rabc]# kubectl --context=ms-context get pods --namespace=default     
  2. Error from server (Forbidden): pods is forbidden: User "ms" cannot list resource "pods" in API group "" in the namespace "default"
复制代码
假如去获取其他的资源对象呢:
  1. [root@master rabc]# kubectl --context=ms-context get svc     
  2. Error from server (Forbidden): services is forbidden: User "ms" cannot list resource "services" in API group "" in the namespace "kube-system"
复制代码
我们可以看到没有权限获取,由于我们并没有为当前操作用户指定其他对象资源的访问权限,是符合我们的预期的。如许我们就创建了一个只有单个命名空间访问权限的平凡 User 。
2.2 只能访问某个 namespace 的 ServiceAccount

上面我们创建了一个只能访问某个命名空间下面的平凡用户,我们前面也提到过 subjects 下面还有一种范例的主题资源:ServiceAccount,现在我们来创建一个集群内部的用户只能操作 kube-system 这个命名空间下面的 pods 和 deployments,首先来创建一个 ServiceAccount 对象:
  1. [root@master ~]#  kubectl create sa ms-sa -n kube-system     
  2. serviceaccount/ms-sa created
复制代码
固然我们也可以界说成 YAML 文件的情势来创建:
  1. apiVersion: v1
  2. kind: ServiceAccount
  3. metadata:
  4.   name: ms-sa
  5.   namespace: kube-system
复制代码
然后新建一个 Role 对象:(ms-sa-role.yaml)
  1. apiVersion: rbac.authorization.k8s.io/v1
  2. kind: Role
  3. metadata:
  4.   name: ms-sa-role
  5.   namespace: kube-system
  6. rules:
  7. - apiGroups: [""]
  8.   resources: ["pods"]
  9.   verbs: ["get", "watch", "list"]
  10. - apiGroups: ["apps"]
  11.   resources: ["deployments"]
  12.   verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
复制代码
可以看到我们这里界说的角色没有创建、删除、更新 Pod 的权限,待会我们可以重点测试一下,创建该 Role 对象:
  1. [root@master ~]# kubectl create -f ms-sa-role.yaml   
  2. role.rbac.authorization.k8s.io/ms-sa-role created
复制代码
然后创建一个 RoleBinding 对象,将上面的 ms-sa 和角色 ms-sa-role 进行绑定:(ms-sa-rolebinding.yaml)
  1. kind: RoleBinding
  2. apiVersion: rbac.authorization.k8s.io/v1
  3. metadata:
  4.   name: ms-sa-rolebinding
  5.   namespace: kube-system
  6. subjects:
  7. - kind: ServiceAccount
  8.   name: ms-sa
  9.   namespace: kube-system
  10. roleRef:
  11.   kind: Role
  12.   name: ms-sa-role
  13.   apiGroup: rbac.authorization.k8s.io
复制代码
添加这个资源对象:
  1. [root@master ~]# kubectl create -f ms-sa-rolebinding.yaml
  2. rolebinding.rbac.authorization.k8s.io/ms-sa-rolebinding created
复制代码
可以在 Dashboard 中来验证我们的功能是否符合预期:
  1. [root@master ~]# kubectl get secret -n kube-system |grep ms-sa   
  2. ms-sa-token-w2wwq                                kubernetes.io/service-account-token   3      15m
复制代码
  1. [root@master ~]# kubectl get secret ms-sa-token-w2wwq -o jsonpath={.data.token} -n kube-system |base64 -d     
  2. eyJhbGciOiJSUzI1NiIsImtpZCI6Ik5nUVQzNjhGS0R6MGlWLU82VnFraEdpRWtCajFnQ1hhVWdfc1Fmbjl3NlEifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJtcy1zYS10b2tlbi13Mnd3cSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJtcy1zYSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjIyZjNmM2FkLWViZWItNDRmNS04NGU4LTRjOGE4MWEzZGU1OCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTptcy1zYSJ9.YCwhqXl19sr2fpMOpkwk8PFK4yf8OH_g2eNYvw4E5QrtcU9d2fRLvhu2OYOsjmjcJK7EKvQvcQ5EZRaRAOnulgbJhzT06LMIhpKGNFNQz2fmAkuSnJOjw7iqFKMtYVVJpsWSYz1VpEa0GW-XuyQM0TM9vCQQK7XksPCZK_NLgVCkY17TsK7bVAdvx0ansvIN3sV5FpwP3v5nguwsjXmsM1E1ZHupp7z453h2pA7xDdlceeh2FxCTvnZjt0ErEG0WjOv-33wFXdFhUYwihbmd50I26QdcWI2KKtJfcwPHYEB0bG9xSapV5z8eILnroLAK9FXmvEjsqf2b3VCf0zfgfQ
复制代码
使用这里的 token 去 Dashboard 页面进行登录:

我们可以看到上面的提示信息说我们现在使用的这个 ServiceAccount 没有权限获取当前命名空间下面的资源对象,这是由于我们登录进来后默认跳转到 default 命名空间,我们切换到 kube-system 命名空间下面就可以了:


我们可以看到可以访问 pod 列表了,但是也会有一些其他额外的提示:events is forbidden: User “system:serviceaccount:kube-system:ms-sa” cannot list events in the namespace “kube-system”,这是由于当前登录用只被授权了访问 pod 和 deployment 的权限,同样的,访问下deployment看看可以了吗?
同样的,你可以根据自己的需求来对访问用户的权限进行限制,可以自己通过 Role 界说更加细粒度的权限,也可以使用系统内置的一些权限
2.3 可以全局访问的 ServiceAccount

刚刚我们创建的 ms-sa 这个 ServiceAccount 和一个 Role 角色进行绑定的,假如我们现在创建一个新的 ServiceAccount,必要他操作的权限作用于所有的 namespace,这个时候我们就必要使用到 ClusterRole 和 ClusterRoleBinding 这两种资源对象了。同样,首先新建一个 ServiceAcount 对象:(ms-sa2.yaml)
  1. apiVersion: v1
  2. kind: ServiceAccount
  3. metadata:
  4.   name: ms-sa2
  5.   namespace: kube-system
复制代码
创建:
  1. [root@master ~]#  kubectl create -f ms-sa2.yaml   
  2. serviceaccount/ms-sa2 created
复制代码
然后创建一个 ClusterRoleBinding 对象(ms-clusterolebinding.yaml):
  1. kind: ClusterRoleBinding
  2. apiVersion: rbac.authorization.k8s.io/v1
  3. metadata:
  4.   name: ms-sa2-clusterrolebinding
  5. subjects:
  6. - kind: ServiceAccount
  7.   name: ms-sa2
  8.   namespace: kube-system
  9. roleRef:
  10.   kind: ClusterRole
  11.   name: cluster-admin
  12.   apiGroup: rbac.authorization.k8s.io
复制代码
从上面我们可以看到我们没有为这个资源对象声明 namespace,由于这是一个 ClusterRoleBinding 资源对象,是作用于整个集群的,我们也没有单独新建一个 ClusterRole 对象,而是使用的 cluster-admin 这个对象,这是 Kubernetes 集群内置的 ClusterRole 对象,我们可以使用 kubectl get clusterrole 和 kubectl get clusterrolebinding 检察系统内置的一些集群角色和集群角色绑定,这里我们使用的 cluster-admin 这个集群角色是拥有最高权限的集群角色,所以一般必要谨慎使用该集群角色。
创建上面集群角色绑定资源对象,创建完成后同样使用 ServiceAccount 对应的 token 去登录 Dashboard 验证下:
  1. [root@master ~]# kubectl create -f ms-clusterolebinding.yaml
  2. clusterrolebinding.rbac.authorization.k8s.io/cnych-sa2-clusterrolebinding created
  3. [root@master ~]# kubectl get secret -n kube-system |grep ms-sa2   
  4. ms-sa2-token-7dhq8                               kubernetes.io/service-account-token   3      6m32s
  5. [root@master ~]# kubectl get secret ms-sa2-token-7dhq8 -o jsonpath={.data.token} -n kube-system |base64 -d                     
  6. eyJhbGciOiJSUzI1NiIsImtpZCI6Ik5nUVQzNjhGS0R6MGlWLU82VnFraEdpRWtCajFnQ1hhVWdfc1Fmbjl3NlEifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJtcy1zYTItdG9rZW4tN2RocTgiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoibXMtc2EyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMWIzOTE4NzUtNGZiNS00YTYyLWJiYjgtODhjNGQwOTdmMjhmIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOm1zLXNhMiJ9.YQSh_h0mTVxOWB8Kwq_jeYDLtDijljWxE_jF9iZTgqHz6tgEuVd2ovmHxS-Ir3LZR6umrbipvLFGNT5MtP7reg4JqQ1UPiu8bWG_f8DOwoBTMKBA4qv8MEIfM4ks34l7Tfn6PcAvZGfGpn6XXK0y0KtyhpcsfLkoGEL28X1mgjKoaCfWjUsthidJ24KNz-Pf7Y-pyqR6yeVoMBg8y5NTb3HfpQLqtkzdW-8UeJB8p2_hYDGHEAk7kib-ivFDCD3alem_Cgx1oXTbj-hiGsOggKurNc8iq4PWrKV30ZJ0CbGuH29Xnh0rv41SNMi_gjyEcfdUaskyP1pUaIVAA35y5A
复制代码

3. Security Context

我们偶尔候在运行一个容器的时候,可能必要使用 sysctl 命令来修改内核参数,比如 net、vm、kernel 等参数,但是 systcl 必要容器拥有超等权限,才可以使用,在 Docker 容器启动的时候我们可以加上 --privileged 参数来使用特权模式。那么在 Kubernetes 中应该如何来使用呢?
这个时候我们就必要使用到 Kubernetes 中的 Security Context,也就是常说的安全上下文,重要是来限制容器非法操作宿主节点的系统级别的内容,以免节点的系统或者节点上其他容器组受到影响。Kubernetes 提供了三种设置安全上下文级别的方法:


  • Container-level Security Context:仅应用到指定的容器
  • Pod-level Security Context:应用到 Pod 内所有容器以及 Volume
  • Pod Security Policies(PSP):应用到集群内部所有 Pod 以及 Volume
我们可以用如下几种方式来设置 Security Context:


  • 访问权限控制:根据用户 ID(UID)和组 ID(GID)来限制对资源(比如:文件)的访问权限
  • Security Enhanced Linux (SELinux):为对象分配 SELinux 标签
  • 以 privileged(特权)模式运行
  • Linux Capabilities:给某个特定的进程超等权限,而不消给 root 用户所有的 privileged 权限
  • AppArmor:使用程序文件来限制单个程序的权限
  • Seccomp:过滤容器中进程的系统调用(system call)
  • AllowPrivilegeEscalation(允许特权扩大):此项设置是一个布尔值,界说了一个进程是否可以比其父进程获得更多的特权,直接结果是,容器的进程上是否被设置 no_new_privs 标记。当出现如下情况时,AllowPrivilegeEscalation 的值始终为 true:

    • 容器以 privileged 模式运行
    • 容器拥有 CAP_SYS_ADMIN 的 Linux Capability

3.1 为 Pod 设置 Security Context

我们只必要在 Pod 界说的资源清单文件中添加 securityContext 字段,就可以为 Pod 指定安全上下文相关的设定,通过该字段指定的内容将会对当前 Pod 中的所有容器见效。
security-context-pod.yaml
  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4.   name: security-context-pod
  5.   namespace: dev
  6. spec:
  7.   volumes:
  8.   - name: sec-ctx-vol
  9.     emptyDir: {}
  10.   securityContext:
  11.     runAsUser: 1000
  12.     runAsGroup: 3000
  13.     fsGroup: 2000
  14.   containers:
  15.   - name: sec-ctx-demo
  16.     image: busybox
  17.     command: ["sh", "-c", "sleep 60m"]
  18.     volumeMounts:
  19.     - name: sec-ctx-vol
  20.       mountPath: /pod/demo
  21.     securityContext:
  22.       allowPrivilegeEscalation: false
复制代码
在当前资源清单文件中我们在 Pod 下面添加了 securityContext 字段,其中:


  • runAsUser 字段指定了该 Pod 中所有容器的进程都以 UID 1000 的身份运行,runAsGroup 字段指定了该 Pod 中所有容器的进程都以 GID 3000 的身份运行

    • 假如省略该字段,容器进程的 GID 为 root(0)
    • 容器中创建的文件,其所有者为 userID 1000,groupID 3000

  • fsGroup 字段指定了该 Pod 的 fsGroup 为 2000

    • 数据卷 (对应挂载点 /pod/demo 的数据卷为 sec-ctx-demo) 的所有者以及在该数据卷下创建的任何文件,其 GID 都为 2000

下表是我们常用的一些 securityContext 字段设置内容介绍:

直接创建上面的 Pod 对象:
  1. [root@master ctx]# kubectl apply -f security-context-pod.yaml
  2. pod/security-context-pod created
  3. [root@master ctx]# kubectl get pods
  4. NAME                     READY   STATUS    RESTARTS       AGE
  5. nginx-679bdbcc5b-6hv5j   1/1     Running   1 (2d7h ago)   2d19h
  6. security-context-pod     1/1     Running   0              27s
复制代码
运行完成后,我们可以验证下容器中的进程运行的 ownership:
  1. [root@master ctx]#  kubectl exec security-context-pod top     
  2. kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
  3. Mem: 1585524K used, 277516K free, 12216K shrd, 2104K buff, 870696K cached
  4. CPU:  0.0% usr  0.0% sys  0.0% nic  100% idle  0.0% io  0.0% irq  0.0% sirq
  5. Load average: 0.00 0.01 0.05 1/420 12
  6.   PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
  7.     7     0 1000     R     1312  0.0   0  0.0 top
  8.     1     0 1000     S     1300  0.0   1  0.0 sleep 60m
  9. Mem: 1585632K used, 277408K free, 12220K shrd, 2104K buff, 870700K cached
  10. CPU:  0.2% usr  0.5% sys  0.0% nic 99.2% idle  0.0% io  0.0% irq  0.0% sirq
  11. Load average: 0.00 0.01 0.05 1/420 12
复制代码
我们直接运行一个 top 进程,检察容器中的所有正在执行的进程,我们可以看到 USER ID 都为 1000(runAsUser 指定的),然后检察下挂载的数据卷的 ownership:
  1. [root@master ctx]# kubectl exec security-context-pod -- ls -la /pod     
  2. total 0
  3. drwxr-xr-x    3 root     root            18 Aug 16 11:47 .
  4. drwxr-xr-x    1 root     root            28 Aug 16 11:47 ..
  5. drwxrwsrwx    2 root     2000             6 Aug 16 11:47 demo
复制代码
由于上面我们指定了 fsGroup=2000,所以声明挂载的数据卷 /pod/demo 的 GID 也酿成了 2000。直接调用容器中的 id 命令:
  1. [root@master ctx]# kubectl exec security-context-pod -- id
  2. uid=1000 gid=3000 groups=2000
复制代码
我们可以看到 gid 为 3000,与 runAsGroup 字段所指定的同等,假如 runAsGroup 字段被省略,则 gid 取值为 0(即 root),此时容器中的进程将可以操作 root Group 的文件。
比如我们现在想要去删除容器中的 /tmp 目次就没有权限了,由于该目次的用户和组都是 root,而我们当前要去删除使用的进程的 ID 号就酿成了 1000:3000,所以没有权限操作:
  1. [root@master ctx]# kubectl exec security-context-pod -- ls -la /tmp     
  2. total 0
  3. drwxrwxrwt    2 root     root             6 Dec 29  2021 .
  4. drwxr-xr-x    1 root     root            28 Aug 16 11:47 ..
复制代码
  1. [root@master ctx]# kubectl exec security-context-pod -- rm -rf /tmp     
  2. rm: can't remove '/tmp': Permission denied
  3. command terminated with exit code 1
复制代码
3.2 为容器设置 Security Context

除了在 Pod 中可以设置安全上下文之外,我们还可以单独为某个容器设置安全上下文,同样也是通过 securityContext 字段设置,当该字段的设置与 Pod 级别的 securityContext 设置相冲突时,容器级别的设置将覆盖 Pod 级别的设置。容器级别的 securityContext 不影响 Pod 中的数据卷。如下资源清单所示:
security-context-container.yaml
  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4.   name: security-context-container
  5.   namespace: dev
  6. spec:
  7.   securityContext:
  8.     runAsUser: 1000
  9.   containers:
  10.   - name: sec-ctx-demo
  11.     image: busybox
  12.     command: [ "sh", "-c", "sleep 60m" ]
  13.     securityContext:
  14.       runAsUser: 2000
  15.       allowPrivilegeEscalation: false
复制代码
直接创建上面的 Pod 对象:
  1. [root@master ctx]# kubectl apply -f security-context-container.yaml
  2. pod/security-context-container created
复制代码
同样我们直接执行容器中的 top 命令:
  1. [root@master ctx]# kubectl exec security-context-container top
  2. kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
  3. Mem: 1533072K used, 329968K free, 12312K shrd, 2104K buff, 866108K cached
  4. CPU:  0.0% usr  0.0% sys  0.0% nic  100% idle  0.0% io  0.0% irq  0.0% sirq
  5. Load average: 0.00 0.04 0.05 1/421 13
  6.   PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
  7.     8     0 2000     R     1312  0.0   0  0.0 top
  8.     1     0 2000     S     1300  0.0   0  0.0 sleep 60m
复制代码
容器的进程以 UID 2000 的身份运行,该取值由 spec.containers
  • .securityContext.runAsUser 容器组中的字段界说。Pod 中界说的 spec.securityContext.runAsUser 取值 1000 被覆盖。
    3.3 设置 Linux Capabilities

    要相识 Linux Capabilities,这就得从 Linux 的权限控制发展来阐明。在 Linux 2.2 版本之前,当内查对进程进行权限验证的时候,Linux 将进程划分为两类:特权进程(UID=0,也就是超等用户)和非特权进程(UID!=0),特权进程拥有所有的内核权限,而非特权进程则根据进程根据(effective UID, effective GID,supplementary group 等)进行权限查抄。
    比如我们以常用的 passwd 命令为例,修改用户暗码必要具有 root 权限,而平凡用户是没有这个权限的。但是实际上平凡用户又可以修改自己的暗码,这是怎么回事呢?在 Linux 的权限控制机制中,有一类比较特别的权限设置,比如 SUID(Set User ID on execution),允许用户以可执行文件的 owner 的权限来运行可执行文件。由于程序文件 /bin/passwd 被设置了 SUID 标识,所以平凡用户在执行 passwd 命令时,进程是以 passwd 的所有者,也就是 root 用户的身份运行,从而就可以修改暗码了。
    但是使用 SUID 却带来了新的安全隐患,当我们运行设置了 SUID 的命令时,通常只是必要很小一部分的特权,但是 SUID 却给了它 root 具有的全部权限,一旦被设置了 SUID 的命令出现毛病,是不是就很容易被使用了。
    为此 Linux 引入了 Capabilities 机制来对 root 权限进行了更加细粒度的控制,实现按需进行授权,如许就大大减小了系统的安全隐患。
    3.3.1 什么是 Capabilities

    从内核 2.2 开始,Linux 将传统上与超等用户 root 关联的特权划分为不同的单位,称为 capabilites。Capabilites 每个单位都可以独立启用和禁用。如许当系统在作权限查抄的时候就酿成了:在执行特权操作时,假如进程的有效身份不是 root,就去查抄是否具有该特权操作所对应的 capabilites,并以此决定是否可以进行该特权操作。比如假如我们要设置系统时间,就得具有 CAP_SYS_TIME 这个 capabilites。下面是从 capabilities man page 中摘取的 capabilites 列表:

    3.3.2 如何使用 Capabilities

    我们可以通过 getcap 和 setcap 两条命令来分别检察和设置程序文件的 capabilities 属性。比如当前我们是root 这个用户,使用 getcap 命令检察 ping 命令现在具有的 capabilities:
    1. [root@master ~]# useradd mssc
    2. [root@master ~]# passwd mssc
    3. 更改用户 mssc 的密码 。
    4. 新的 密码:
    5. 重新输入新的 密码:
    6. passwd:所有的身份验证令牌已经成功更新。
    7. [root@master ~]# su - mssc
    8. [mssc@master ~]$ ll /bin/ping
    9. -rwxr-xr-x. 1 root root 66176 8月   4 2017 /bin/ping
    10. [mssc@master ~]$ getcap /bin/ping
    11. /bin/ping = cap_net_admin,cap_net_raw+p
    复制代码
    我们可以看到具有 cap_net_admin 这个属性,所以我们现在可以执行 ping 命令:
    1. [mssc@master ~]$ ping www.baidu.com
    2. PING www.wshifen.com (183.232.231.173) 56(84) bytes of data.
    3. 64 bytes from 183.232.231.173 (183.232.231.173): icmp_seq=1 ttl=128 time=42.3 ms
    复制代码
    但是假如我们把命令的 capabilities 属性移除掉:
    1. [root@master ~]#  cd /etc
    2. [root@master etc]# ls
    3. [root@master etc]# chmod 777 sudoers
    4. [root@master etc]# vim sudoers
    5. mssc    ALL=(ALL)       ALL
    6. [root@master etc]# chmod 440 sudoers
    7. # -是移除
    8. [mssc@master ~]$ sudo setcap cap_net_admin,cap_net_raw-p /bin/ping
    9. [sudo] mssc 的密码:
    10. [mssc@master ~]$ getcap /bin/ping
    11. /bin/ping =
    12. [mssc@master ~]$ ping www.baidu.com
    13. ping: socket: 不允许的操作
    复制代码
    由于 ping 命令在执行时必要访问网络,所需的 capabilities 为 cap_net_admin 和 cap_net_raw,所以我们可以通过 setcap 命令可来添加它们:
    1. [mssc@master ~]$ sudo setcap cap_net_admin,cap_net_raw+p /bin/ping
    2. [mssc@master ~]$ getcap /bin/ping
    3. /bin/ping = cap_net_admin,cap_net_raw+p
    4. [mssc@master ~]$ ping www.baidu.com
    5. PING www.wshifen.com (183.232.231.172) 56(84) bytes of data.
    6. 64 bytes from 183.232.231.172 (183.232.231.172): icmp_seq=1 ttl=128 time=40.8 ms
    7. 64 bytes from 183.232.231.172 (183.232.231.172): icmp_seq=2 ttl=128 time=40.8 ms
    复制代码
    命令中的 p 表现 Permitted 集合,+ 号表现把指定的capabilities 添加到这些集合中,- 号表现从集合中移除。
    对于可执行文件的属性中有三个集合来保存三类 capabilities,它们分别是:


    • Permitted:在进程执行时,Permitted 集合中的 capabilites 主动被加入到进程的 Permitted 集合中。
    • Inheritable:Inheritable 集合中的 capabilites 会与进程的 Inheritable 集合执行与操作,以确定进程在执行 execve 函数后哪些 capabilites 被继承。
    • Effective:Effective 只是一个 bit。假如设置为开启,那么在执行 execve 函数后,Permitted 集合中新增的 capabilities 会主动出现在进程的 Effective 集合中。
    对于进程中有五种 capabilities 集合范例,相比文件的 capabilites,进程的 capabilities 多了两个集合,分别是 Bounding 和 Ambient。
    我们可以通过下面的命名来检察当前进程的 capabilities 信息:
    1. # 用ps -ef 查看所有进程 随便选一个pip即可
    2. [mssc@master ~]$ cat /proc/51771/status | grep 'Cap'   
    3. CapInh: 0000000000000000
    4. CapPrm: 0000000000000000
    5. CapEff: 0000000000000000
    6. CapBnd: 0000001fffffffff
    7. CapAmb: 0000000000000000
    复制代码
    然后我们可以使用 capsh 命令把它们转义为可读的格式,如许基本可以看出进程具有的 capabilities 了:
    1. [mssc@master ~]$  capsh --decode=0000001fffffffff
    2. 0x0000001fffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,35,36
    复制代码
    3.3.3 Docker Container Capabilities

    Docker 容器本质上就是一个进程,所以理论上容器就会和进程一样会有一些默认的开放权限,默认情况下 Docker 会删除必须的 capabilities 之外的所有 capabilities,由于在容器中我们常常会以 root 用户来运行,使用 capabilities 后,容器中的使用的 root 用户权限就比我们平时在宿主机上使用的 root 用户权限要少很多了,如许即使出现了安全毛病,也很难粉碎或者获取宿主机的 root 权限,所以 Docker 支持 Capabilities 对于容器的安全性来说黑白常有须要的。
    不外我们在运行容器的时候可以通过指定 --privileded 参数来开启容器的超等权限,这个参数一定要慎用,由于他会获取系统 root 用户所有能力赋值给容器,并且会扫描宿主机的所有设备文件挂载到容器内部,所以黑白常伤害的操作。
    但是假如你确实必要一些特别的权限,我们可以通过 --cap-add 和 --cap-drop 这两个参数来动态调整,可以最大限度地包管容器的使用安全。下面表格中列出的 Capabilities 是 Docker 默认给容器添加的,我们可以通过 --cap-drop 去除其中一个或者多个:

    下面表格中列出的 Capabilities 是 Docker 默认删除的,我们可以通过--cap-add添加其中一个或者多个:

       --cap-add和--cap-drop 这两参数都支持ALL值,比如假如你想让某个容器拥有除了MKNOD之外的所有内核权限,那么可以执行下面的命令: $ sudo docker run --cap-add=ALL --cap-drop=MKNOD ...
      比如现在我们必要修改网络接口数据,默认情况下是没有权限的,由于必要的 NET_ADMIN 这个 Capabilities 默认被移除了:
    1. [root@master ctx]# docker run -it --rm busybox /bin/sh
    2. / # ip link add dummy0 type dummy
    3. ip: RTNETLINK answers: Operation not permitted
    复制代码
    所以在不使用 --privileged 的情况下(不发起)我们可以使用 --cap-add=NET_ADMIN 将这个 Capabilities 添加回来:
    1. [root@master ctx]# docker run -it --rm --cap-add=NET_ADMIN busybox /bin/sh
    2. / # ip link add dummy0 type dummy
    3. #创建网卡后,就可以本地 ping 通了。
    4. / # ip addr add 169.254.20.10 dev dummy0
    5. / # ping 169.254.20.10
    6. PING 169.254.20.10 (169.254.20.10): 56 data bytes
    7. 64 bytes from 169.254.20.10: seq=0 ttl=64 time=0.042 ms
    8. 64 bytes from 169.254.20.10: seq=1 ttl=64 time=0.032 ms
    9. / # ip link delete dummy0
    复制代码
    3.4 Kubernetes 设置 Capabilities

    上面我介绍了在 Docker 容器下如何来设置 Capabilities,在 Kubernetes 中也可以很方便的来界说,我们只必要添加到 Pod 界说的 spec.containers.sercurityContext.capabilities中即可,也可以进行 add 和 drop 设置,同样上面的示例,我们要给 busybox 容器添加 NET_ADMIN 这个 Capabilities,对应的 YAML 文件可以如许界说:(cpb-demo.yaml)
    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4.   name: cpb-demo
    5. spec:
    6.   containers:
    7.   - name: cpb
    8.     image: busybox
    9.     args:
    10.     - sleep
    11.     - "3600"
    12.     securityContext:
    13.       capabilities:
    14.         add: # 添加
    15.         - NET_ADMIN
    16.         drop:  # 删除
    17.         - KILL
    复制代码
    我们在 securityContext 下面添加了 capabilities 字段,其中添加了 NET_ADMIN 并且删除了 KILL 这个默认的容器 Capabilities,如许我们就可以在 Pod 中修改网络接口数据了:
    1. [root@master ctx]# kubectl apply -f cpb-demo.yaml
    2. pod/cpb-demo created
    3. [root@master ctx]# kubectl get pods
    4. NAME                         READY   STATUS    RESTARTS       AGE
    5. cpb-demo                     1/1     Running   0              19s
    6. nginx-679bdbcc5b-6hv5j       1/1     Running   1 (2d8h ago)   2d20h
    7. security-context-container   1/1     Running   0              48m
    8. security-context-pod         1/1     Running   0              54m
    9. [root@master ctx]# kubectl exec -it cpb-demo -- /bin/sh
    10. / # ip link add dummy0 type dummy
    11. / # ip link delete dummy0
    复制代码
    在 Kubernetes 中通过 sercurityContext.capabilities 进行设置容器的 Capabilities,固然终极还是通过 Docker 的 libcontainer 去借助 Linux kernel capabilities 实现的权限管理。


    • sleep
      - “3600”
      securityContext:
      capabilities:
      add: # 添加

      • NET_ADMIN
        drop: # 删除
      • KILL

    1. 我们在 `securityContext` 下面添加了 `capabilities` 字段,其中添加了 `NET_ADMIN` 并且删除了 `KILL` 这个默认的容器 `Capabilities`,如许我们就可以在 Pod 中修改网络接口数据了:~~~shell[root@master ctx]# kubectl apply -f cpb-demo.yaml
    2. pod/cpb-demo created
    3. [root@master ctx]# kubectl get pods
    4. NAME                         READY   STATUS    RESTARTS       AGE
    5. cpb-demo                     1/1     Running   0              19s
    6. nginx-679bdbcc5b-6hv5j       1/1     Running   1 (2d8h ago)   2d20h
    7. security-context-container   1/1     Running   0              48m
    8. security-context-pod         1/1     Running   0              54m
    9. [root@master ctx]# kubectl exec -it cpb-demo -- /bin/sh
    10. / # ip link add dummy0 type dummy
    11. / # ip link delete dummy0
    复制代码
    在 Kubernetes 中通过 sercurityContext.capabilities 进行设置容器的 Capabilities,固然终极还是通过 Docker 的 libcontainer 去借助 Linux kernel capabilities 实现的权限管理。

    免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
  • 本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    x
    回复

    使用道具 举报

    0 个回复

    正序浏览

    快速回复

    您需要登录后才可以回帖 登录 or 立即注册

    本版积分规则

    种地

    金牌会员
    这个人很懒什么都没写!

    标签云

    快速回复 返回顶部 返回列表