当前位置: 首页 > news >正文

【云原生】kubernetes中的认证、权限设置--RBAC授权原理分析与应用实战

在这里插入图片描述

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生k8s,linux,shell脚本等实操经验,网站搭建,数据库等分享。

所属的专栏:云原生K8S,零基础到进阶实战
景天的主页:景天科技苑

文章目录

  • 1、k8s安全管理:认证、授权、准入控制概述
    • 1.1 认证
      • 1、认证支持多种插件
      • 2、kubernetes上的账号
      • 3.kubeconfig文件
    • 1.2 授权
    • 1.3 准入控制
  • 2、Useraccount和ServiceAccount介绍
    • ServiceAccount使用案例介绍
  • 3、对sa做授权
  • 4、RBAC认证授权策略
    • 4.1 Role:角色
    • 4.2 ClusterRole:集群角色
    • 4.3 RoleBinding:角色绑定、ClusterRolebinding:集群角色绑定
  • 5、资源的引用方式
  • 6、常见角色(role)授权的案例
  • 7、常见的角色绑定示例
  • 8、对Service Account的授权管理
  • 9、使用kubectl命令行工具创建资源对象
    • (1)在命名空间rbac中为用户es授权admin ClusterRole:
    • (2)在命名空间rbac中为名为myapp的Service Account授予view ClusterRole:
    • (3)在全集群范围内为用户root授予cluster-admin ClusterRole:
    • (4)在全集群范围内为名为myapp的Service Account授予view ClusterRole:
  • 10、限制不同的用户操作k8s集群
    • ssl认证
  • 11、准入控制
    • 11.1  ResourceQuota准入控制器
      • 1.限制cpu、内存、pod、deployment数量
      • 2.限制存储空间大小
    • 11.2 LimitRanger准入控制器
      • 1)在limit名称空间创建pod,不指定资源,看看是否会被limitrange规则自动附加其资源限制?
      • 2)创建pod,指定cpu请求是100m,看看是否允许创建

1、k8s安全管理:认证、授权、准入控制概述

k8s对我们整个系统的认证,授权,访问控制做了精密的设置;对于k8s集群来说,
apiserver是整个集群访问控制的唯一入口,我们在k8s集群之上部署应用程序的时候,
也可以通过宿主机的NodePort暴露的端口访问里面的程序,
用户访问kubernetes集群需要经历如下认证过程:认证->授权->准入控制(adminationcontroller)

  • 1.认证(Authenticating)是对客户端的认证,通俗点就是用户名密码验证

  • 2.授权(Authorization)是对资源的授权,k8s中的资源无非是容器,
    最终其实就是容器的计算,网络,存储资源,当一个请求经过认证后,需要访问某一个资源(比如创建一个pod),
    授权检查会根据授权规则判定该资源(比如某namespace下的pod)是否是该客户可访问的。

  • 3.准入(Admission Control)机制:
    准入控制器(Admission Controller)位于 API Server 中,在对象被持久化之前,
    准入控制器拦截对 API Server 的请求,一般用来做身份验证和授权。其中包含两个特殊的控制器:

MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook。分别作为配置的变异和验证准入控制 webhook。
变更(Mutating)准入控制:修改请求的对象
验证(Validating)准入控制:验证请求的对象

准入控制器是在 API Server 的启动参数配置的。一个准入控制器可能属于以上两者中的一种,也可能两者都属于。
当请求到达 API Server 的时候首先执行变更准入控制,然后再执行验证准入控制。

我们在部署 Kubernetes 集群的时候都会默认开启一系列准入控制器,
如果没有设置这些准入控制器的话可以说你的 Kubernetes 集群就是在裸奔,应该只有集群管理员可以修改集群的准入控制器。
例如我会默认开启如下的准入控制器。

--admission-control=ServiceAccount,NamespaceLifecycle,NamespaceExists,LimitRanger,ResourceQuota,MutatingAdmissionWebhook,
ValidatingAdmissionWebhook

k8s的整体架构也是一个微服务的架构,所有的请求都是通过一个GateWay,
也就是kube-apiserver这个组件(对外提供REST服务),k8s中客户端有两类,
一种是普通用户,一种是集群内的Pod,这两种客户端的认证机制略有不同,但无论是哪一种,
都需要依次经过认证,授权,准入这三个机制。

1.1 认证

1、认证支持多种插件

(1)令牌(token)认证:
双方有一个共享密钥,服务器上先创建一个密码下来,客户端登陆的时候拿这个密码登陆即可,
这个就是对称密钥认证方式;k8s提供了一个restful风格的接口,它的所有服务都是通过http协议提供的,
因此认证信息只能经由http协议的认证首部进行传递,这种认证首部进行传递通常叫做令牌;
(2)ssl认证:
对于k8s访问来讲,ssl认证能让客户端确认服务器的认证身份,我们在跟服务器通信的时候,
需要服务器发过来一个证书,我们需要确认这个证书是不是ca签署的,如果是我们认可的ca签署的,
里面的subjects信息与我们访问的目标主机信息保持一致,没有问题,那么我们就认为服务器的身份得到认证了,
k8s中最重要的是服务器还需要认证客户端的信息,kubectl也应该有一个证书,这个证书也是server所认可的ca签署的证书,
双方需要互相认证,实现加密通信,这就是ssl认证。

2、kubernetes上的账号

客户端对apiserver发起请求,apiserver要识别这个用户是否有请求的权限,
要识别用户本身能否通过apiserver执行相应的操作,
那么需要哪些信息才能识别用户信息来完成对用户的相关的访问控制呢?

kubectl explain pods.spec可以看到有一个字段serviceAccountName(服务账号名称),
这个就是我们pod连接apiserver时使用的账号,
在这里插入图片描述

因此整个kubernetes集群中的账号有两类,
ServiceAccount(服务账号),User account(用户账号)

User account:实实在在现实中的人,人可以登陆的账号,客户端想要对apiserver发起请求,
apiserver要识别这个客户端是否有请求的权限,那么不同的用户就会有不同的权限,靠用户账号表示,叫做username,是kubectl调用的账号

我们执行kubectl时,使用的用户时经过RBAC授权的

[root@master01 ~ ]#cat .kube/config 
apiVersion: v1
clusters:
- cluster:certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLvdsffsfvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeU1Ea3hOREF5TURjek5Wb1hEVE15TURreE1UQXlNRGN6TlZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTVB0CmJNNHg3STgvK01FQ29nY3lTNFRxK0ZzVHVtZi9JeFNXMXY4Q3NHVHVodEgrVElia21oYmlvenI4U0JtSGR2L1YKYTRjSjdzNGhxcE1LTnRiNk1IK1VZN0JqT25OT0J6TWYwbTg2cS9rRVFGRmZEdlRIU0kzYzBXK3BaRHZ5Y1EregphdXRGOHRjTWFtWk9KQU95U2xBN3NOelFCYlgrQW9lVFE0a29aVURGQm1oZjNIamdkanVtV3NERnZwVHMvd0wxCmlaV2p5dFd3c3J4RDIxK1lwa0ZkVUhRYnlxR2VuT0JscUYxbWhoTjkyY2VDcW80TDJSQlRYQXlKNVMxdG5EZ2gKR1B6WFNzN2cwNmhaaTlycEhPZ0RjdjByenBvdEdLc21LQm9DZ2RmcXovYlJ0UDk3UlA5ampXUHdDdUllR3Vwcwp6WGI4a1RINThleFp1cXNiS2dzQ0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZMUFRZRWppaWUrU3RYbENVK1REaWVRT3BjdWZNQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSDF6OHZjazBDaVZPT1J5QXZRYQpXV0s3WSt0WWZNSXhzcVBkU3A5My9yeXl2MkE0dWhTQjRiMDRGTmlLNWp4b2cvaDhoWmxIbFJoNDZzaUdMWlRjCmgwUHhmSlZ5L3UvdzNXZ2N0bXJMVTJ1VHVkcERkNm10YlhJRGhNempGWlh1VjFQa01oQk5ZVDUxS1hqY0dmTkMKY1JxMm5Vc1dCM0U5SjZJakNhWi80ME9wcjZBYUNoNWlWRUpmUzR6M3hHcm1uQ0lBeG5UaHBVUHEybjJ1NjZXOApQc2FvS0ZmTmZkUlEvSk5CUHVDUUs2RzRZM0syVEFYRkFMQzFXNEVmRmhKWUQ5RkxzQVk0TjUwQ1p2OVFNOXFuCmhrcW5SSGJqSGI4ZWdITThSRFU0UWNybm9IZzMycnB2MUtWcnZtVExQVVZ5dm85eUZpSm53ZzBJVVF3Rlc1R1UKelQwPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==server: https://10.10.0.10:6443name: kubernetes
contexts:
- context:cluster: kubernetesuser: kubernetes-adminname: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes

使用的是kubernetes-admin这个用户,这个是user account

ServiceAccount:方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的,是kubernetes中的一种资源

sa账号:登陆dashboard使用的账号
user account:这个是登陆k8s物理机器的用户

1.ServiceAccount
Service account是为了方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的。
它与User account不同,User account是为人设计的,而service account则是为Pod中的进程调用Kubernetes API而设计;
User account是跨namespace的,而service account则是仅局限它所在的namespace;
每个namespace都会自动创建一个default service account;
开启ServiceAccount Admission Controller后

1)每个Pod在创建后都会自动设置spec.serviceAccount为default(除非指定了其他ServiceAccout)
2)验证Pod引用的service account已经存在,否则拒绝创建;

当创建 pod 的时候,如果没有指定一个 serviceaccount,
系统会自动在与该pod 相同的 namespace 下为其指派一个default service account。
这是pod和apiserver之间进行通信的账号,如下:

kubectl get pods siweb-866d9955bd-pjg8r  -n h5-web -oyaml|grep -i "serviceaccountname"

在这里插入图片描述

查看某命名空间下有哪些sa

kubectl get sa -n h5-web

在这里插入图片描述

查看密钥

kubectl get secret -n h5-web

在这里插入图片描述

默认有一个default-token-h5fdg

创建sa时,会自动创建一个secret

[root@master01 ~ ]#kubectl create sa test
serviceaccount/test created
[root@master01 ~ ]#
[root@master01 ~ ]#
[root@master01 ~ ]#kubectl get sa
NAME              SECRETS   AGE
default           1         12d
nfs-provisioner   1         5d2h
test              1         4s
[root@master01 ~ ]#kubectl describe sa test
Name:                test
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   test-token-h9tkr
Tokens:              test-token-h9tkr
Events:              <none>
[root@master01 ~ ]#kubectl get secret
NAME                          TYPE                                  DATA   AGE
default-token-xc8dr           kubernetes.io/service-account-token   3      12d
mysecret                      Opaque                                2      3h12m
mysql-password                Opaque                                1      3h27m
nfs-provisioner-token-8mxt9   kubernetes.io/service-account-token   3      5d2h
test-token-h9tkr              kubernetes.io/service-account-token   3      20s   这个就是新创建的secret
[root@master01 ~ ]#kubectl describe secret test-token-h9tkr
Name:         test-token-h9tkr
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: testkubernetes.io/service-account.uid: edd4d5c7-403c-4bc3-8a7b-4912def671e7Type:  kubernetes.io/service-account-tokenData
====
ca.crt:     1099 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6InFpN2JVd1VkbllDM3dvSk1INkdRUVhqUExMejNEeVJWQnlHM0dUR052VWcifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InRlc3QtdG9rZW4taDl0a3IiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoidGVzdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImVkZDRkNWM3LTQwM2MtNGJjMy04YTdiLTQ5MTJkZWY2NzFlNyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OnRlc3QifQ.N9R_IoTJrrKLINaKw_A-xT1FfVTyHGYpIshcpZrQ_40o6gEEnaye4KY4HRrIQG-tXbVERMQcsHEJBFu7W2nmWHlN-Ar-1BgSYGWYKbemqXhht7zQwK6RWMxF9cV-mu-66m4IPTA7Hxl2XrH8R4c7bcmsPN4nSCBGwJsE2c2pItXpckuCaeHoXQOQ7PSMAdLjiZaZO4gVnYuIH-01uJauss0ofh7uXk5O8WrDM-EM-QuQLFrgzSwmFrWzqiPWIC11XnF1p5RyRXhyje5F0UZfhZ92rtLr4k-uzWs0VwjCpMoMremW_3UEnLN1nDa7anU9gFOBIW8UlWi_94NcIdv4LA

这个token就是创建sa时创建的token

从上面可以看到每个Pod无论定义与否都会有个存储卷,这个存储卷为default-token-***。
pod和apiserver的认证信息通过secret进行定义,由于认证信息属于敏感信息,所以需要保存在secret资源当中,
并以存储卷的方式挂载到Pod当中。从而让Pod内运行的应用通过对应的secret中的信息来连接apiserver,并完成认证。
每个 namespace 中都有一个默认的叫做 default 的 serviceaccount 资源。
查看名称空间内的secret,也可以看到对应的default-token。
让当前名称空间中所有的pod在连接apiserver时可以使用的预制认证信息,从而保证pod之间的通信。

默认的service account 仅仅只能获取当前Pod自身的相关属性,
无法观察到其他名称空间Pod的相关属性信息。
如果想要扩展Pod,假设有一个Pod需要用于管理其他Pod或者是其他资源对象,
是无法通过自身的名称空间的serviceaccount进行获取其他Pod的相关属性信息的,
此时就需要进行手动创建一个serviceaccount,并在创建Pod时进行定义。
那么serviceaccount该如何进行定义呢?实际上,service accout也属于一个k8s资源,
serviceAccount也属于标准的k8s资源,可以创建一个serviceAccount,
创建之后由我们创建的pod使用serviceAccountName去加载自己定义的serviceAccount就可以了,如下:

(1)创建一个serviceaccount:

kubectl create serviceaccount test
[root@master01 RBAC ]#kubectl get sa
NAME              SECRETS   AGE
default           1         12d
nfs-provisioner   1         5d15h
test              1         13h

可以看到已经创建了test的serviceacount
kubectl describe sa test 查看test这个账号的详细信息

[root@master01 RBAC ]#kubectl describe sa test
Name:                test
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   test-token-h9tkr
Tokens:              test-token-h9tkr
Events:              <none>

上面可以看到生成了一个test-token-h9tkr的secret和test-token-h9tkr的token

kubectl get secret 显示如下:

[root@master01 RBAC ]#kubectl get secret
NAME                          TYPE                                  DATA   AGE
default-token-xc8dr           kubernetes.io/service-account-token   3      12d
mysecret                      Opaque                                2      16h
mysql-password                Opaque                                1      16h
nfs-provisioner-token-8mxt9   kubernetes.io/service-account-token   3      5d15h
test-token-h9tkr              kubernetes.io/service-account-token   3      13h

kubectl describe secret test-token-h9tkr 显示如下:

[root@master01 RBAC ]#kubectl describe secret test-token-h9tkr
Name:         test-token-h9tkr
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: testkubernetes.io/service-account.uid: edd4d5c7-403c-4bc3-8a7b-4912def671e7Type:  kubernetes.io/service-account-tokenData
====
ca.crt:     1099 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6InFpN2JVd1VkbllDM3dvSk1INkdRUVhqUExMejNEeVJWQnlHM0dUR052VWcifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InRlc3QtdG9rZW4taDl0a3IiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoidGVzdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImVkZDRkNWM3LTQwM2MtNGJjMy04YTdiLTQ5MTJkZWY2NzFlNyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OnRlc3QifQ.N9R_IoTJrrKLINaKw_A-xT1FfVTyHGYpIshcpZrQ_40o6gEEnaye4KY4HRrIQG-tXbVERMQcsHEJBFu7W2nmWHlN-Ar-1BgSYGWYKbemqXhht7zQwK6RWMxF9cV-mu-66m4IPTA7Hxl2XrH8R4c7bcmsPN4nSCBGwJsE2c2pItXpckuCaeHoXQOQ7PSMAdLjiZaZO4gVnYuIH-01uJauss0ofh7uXk5O8WrDM-EM-QuQLFrgzSwmFrWzqiPWIC11XnF1p5RyRXhyje5F0UZfhZ92rtLr4k-uzWs0VwjCpMoMremW_3UEnLN1nDa7anU9gFOBIW8UlWi_94NcIdv4LA

上面可以看到生成了test-token-h9tkr的token详细信息,
这个token就是sa连接apiserver的认证信息,这个token也是登陆k8s dashboard的token,
这些是一个认证信息,能够登陆k8s,能认证到k8s,但是不能做别的事情,不代表权限,想要做其他事情,需要授权

3.kubeconfig文件

在K8S集群当中,每一个用户对资源的访问都是需要通过apiserver进行通信认证才能进行访问的,
那么在此机制当中,对资源的访问可以是token,也可以是通过配置文件的方式进行保存和使用认证信息,
可以通过kubectl config进行查看配置,如下:

[root@master01 RBAC ]#kubectl config view
apiVersion: v1
clusters:
- cluster:certificate-authority-data: DATA+OMITTEDserver: https://10.10.0.10:6443          #apiserver的地址name: kubernetes                           #集群的名字
contexts:
- context:cluster: kubernetesuser: kubernetes-adminname: kubernetes-admin@kubernetes            #上下文的名字
current-context: kubernetes-admin@kubernetes    #当前上下文的名字
kind: Config
preferences: {}
users:
- name: kubernetes-adminuser:client-certificate-data: REDACTEDclient-key-data: REDACTED

在上面的配置文件当中,定义了集群、上下文以及用户。其中Config也是K8S的标准资源之一,
在该配置文件当中定义了一个集群列表,指定的集群可以有多个;用户列表也可以有多个,
指明集群中的用户;而在上下文列表当中,是进行定义可以使用哪个用户对哪个集群进行访问,以及当前使用的上下文是什么。

认证就是被人信任
指定认证文件

kubectl get pods --kubeconfig=./config

1.2 授权

如果用户通过认证,什么权限都没有,需要一些后续的授权操作,如对资源的增删该查等,
kubernetes1.6之后开始有RBAC(基于角色的访问控制机制)授权检查机制。
Kubernetes的授权是基于插件形成的,其常用的授权插件有以下几种:
1)Node(节点认证)
2)ABAC(基于属性的访问控制)
3)RBAC(基于角色的访问控制)***
4)Webhook(基于http回调机制的访问控制)

什么是RBAC(基于角色的访问控制)?
让一个用户(Users)扮演一个角色(Role),角色拥有权限,从而让用户拥有这样的权限,
随后在授权机制当中,只需要将权限授予某个角色,此时用户将获取对应角色的权限,从而实现角色的访问控制。如图:
在这里插入图片描述

在k8s的授权机制当中,采用RBAC的方式进行授权,其工作逻辑是,把对对象的操作权限定义到一个角色当中,
再将用户绑定到该角色,从而使用户得到对应角色的权限。如果通过rolebinding绑定role,
只能对rolebingding所在的名称空间的资源有权限,上图user1这个用户绑定到role1上,
只对role1这个名称空间的资源有权限,对其他名称空间资源没有权限,属于名称空间级别的;

另外,k8s为此还有一种集群级别的授权机制,就是定义一个集群角色(ClusterRole),
对集群内的所有资源都有可操作的权限,
从而将User2通过ClusterRoleBinding到ClusterRole,从而使User2拥有集群的操作权限。
Role、RoleBinding、ClusterRole和ClusterRoleBinding的关系如下图:
在这里插入图片描述

通过上图可以看到,可以通过rolebinding绑定role,rolebinding绑定clusterrole,clusterrolebinding绑定clusterrole。
上面我们说了两个角色绑定:
(1)用户通过rolebinding绑定role, 限定在rolebinding所在的名称空间,有权限
(2)用户通过clusterrolebinding绑定clusterrole 集群内所有名称空间都有权限
clusterrolebinding绑定clusterrole的好处:
用户user1通过clusterrolebinding 绑定clusterrole ,然后这个user1对任何名称空间的资源都有了权限
(3)还有一种:rolebinding绑定clusterrole
cluserrole创建时不用指定名称空间,对clusterrole进行授权,让它具有操作K8S资源的权限,
然后用户只需要在不同的名称空间创建不同的rolebinding,绑定clusterrole即可

rolebinding绑定clusterrole的好处:
假如有6个名称空间,每个名称空间的用户都需要对自己的名称空间有管理员权限,
那么需要定义6个role和rolebinding,然后依次绑定,如果名称空间更多,我们需要定义更多的role,
这个是很麻烦的,所以我们引入clusterrole,定义一个clusterrole,对clusterrole授予所有权限,
然后用户通过rolebinding绑定到clusterrole,就会拥有自己名称空间的管理员权限了

注:RoleBinding仅仅对当前名称空间有对应的权限。

1.3 准入控制

一般而言,准入控制只是用来定义我们授权检查完成之后的后续的其他安全检查操作的,
进一步补充了授权机制,由多个插件组合实行,一般而言在创建,删除,修改或者做代理时做补充;

Kubernetes的Admission Control实际上是一个准入控制器(Admission Controller)插件列表,
发送到APIServer的请求都需要经过这个列表中的每个准入控制器插件的检查,如果某一个控制器插件准入失败,就准入失败。

控制器插件如下:

AlwaysAdmit:允许所有请求通过
AlwaysPullImages:在启动容器之前总是去下载镜像,相当于每当容器启动前做一次用于是否有权使用该容器镜像的检查
AlwaysDeny:禁止所有请求通过,用于测试
DenyEscalatingExec:拒绝exec和attach命令到有升级特权的Pod的终端用户访问。
如果集中包含升级特权的容器,而要限制终端用户在这些容器中执行命令的能力,推荐使用此插件
ImagePolicyWebhook
ServiceAccount:这个插件实现了serviceAccounts等等自动化,如果使用ServiceAccount对象,强烈推荐使用这个插件SecurityContextDeny:将Pod定义中定义了的SecurityContext选项全部失效。
SecurityContext包含在容器中定义了操作系统级别的安全选型如fsGroup,selinux等选项
ResourceQuota:用于namespace上的配额管理,它会观察进入的请求,
确保在namespace上的配额不超标。推荐将这个插件放到准入控制器列表的最后一个。
ResourceQuota准入控制器既可以限制某个namespace中创建资源的数量,
又可以限制某个namespace中被Pod请求的资源总量。ResourceQuota准入控制器和ResourceQuota资源对象一起可以实现资源配额管理。
LimitRanger:用于Pod和容器上的配额管理,它会观察进入的请求,
确保Pod和容器上的配额不会超标。准入控制器LimitRanger和资源对象LimitRange一起实现资源限制管理
NamespaceLifecycle:当一个请求是在一个不存在的namespace下创建资源对象时,
该请求会被拒绝。当删除一个namespace时,将会删除该namespace下的所有资源对象
DefaultStorageClass
DefaultTolerationSeconds
PodSecurityPolicy
当Kubernetes版本>=1.6.0,官方建议使用这些插件:admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,
PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds
当Kubernetes版本>=1.4.0,官方建议使用这些插件:
admission-control=NamespaceLifecycle,LimitRanger,
ServiceAccount,DefaultStorageClass,ResourceQuota
以上是标准的准入插件,如果是自己定制的话,
k8s1.7版 出了两个alpha features, Initializers 和 External Admission Webhooks

在k8s上准入控制器的模块有很多,
其中比较常用的有LimitRanger、ResourceQuota、ServiceAccount、这几种默认开启。PodSecurityPolicy(k8s1.25废弃了)等等,
对于前面三种准入控制器系统默认是启用的,我们只需要定义对应的规则即可;
对于PodSecurityPolicy(k8s1.25废弃了)这种准入控制器,系统默认没有启用,如果我们要使用,
就必需启用以后,对应规则才会正常生效;这里需要注意一点,对应psp准入控制器,一定要先写好对应的规则,
把规则和权限绑定好以后,在启用对应的准入控制器,否则先启用准入控制器,没有对应的规则,
默认情况它是拒绝操作,这可能导致现有的k8s系统跑的系统级pod无法正常工作;所以对于psp准入控制器要慎用,
如果规则和权限做的足够精细,它会给我们的k8s系统安全带来大幅度的提升,反之,可能导致整个k8s系统不可用。

查看apiserver启用的准入控制器有哪些?

[root@master01 containers ]#cat /etc/kubernetes/manifests/kube-apiserver.yaml
apiVersion: v1
kind: Pod
metadata:annotations:kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 10.10.0.10:6443creationTimestamp: nulllabels:component: kube-apiservertier: control-planename: kube-apiservernamespace: kube-system
spec:containers:- command:- kube-apiserver- --feature-gates=RemoveSelfLink=false- --advertise-address=10.10.0.10- --allow-privileged=true- --authorization-mode=Node,RBAC- --client-ca-file=/etc/kubernetes/pki/ca.crt- --enable-admission-plugins=NodeRestriction- --enable-bootstrap-token-auth=true- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt

提示:
apiserver启用准入控制插件需要使用–enable-admission-plugins选项来指定,
该选项可以使用多个值,用逗号隔开表示启用指定的准入控制插件;
这里配置文件中显式启用了NodeRestrication这个插件;
默认没有写在这上面的内置准入控制器,它也是启用了的,
比如LimitRanger、ResourceQuota、ServiceAccount等等;
对于不同的k8s版本,内置的准入控制器和启用与否请查看相关版本的官方文档;
对于那些没有启动的准入控制器,我们可以在上面选项中直接启用,分别用逗号隔开即可。

对应的官网地址:
https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/admission-controllers/

要修改准入控制,只需要修改kube-apiserver.yaml文件,然后重启kubelet就可以生效

2、Useraccount和ServiceAccount介绍

kubernetes中账户分为:UserAccounts(用户账户) 和 ServiceAccounts(服务账户) 两种:
UserAccount是给kubernetes集群外部用户使用的,如kubectl访问k8s集群要用useraccount用户,
kubeadm安装的k8s,默认的useraccount用户是kubernetes-admin;而且这个用户是被证书签发的用户

k8s客户端(一般用:kubectl) ------>API Server

APIServer需要对客户端做认证,使用kubeadm安装的K8s,
会在用户家目录下创建一个认证配置文件 .kube/config 这里面保存了客户端访问API Server的密钥相关信息,
这样当用kubectl访问k8s时,它就会自动读取该配置文件,向API Server发起认证,然后完成操作请求。

用户名称可以在kubeconfig中查看

[root@master01 ~ ]#cd .kube/
[root@master01 .kube ]#ll
total 8
drwxr-x--- 4 root root   35 Sep 14 10:11 cache
-rw------- 1 root root 5634 Sep 14 10:09 config
[root@master01 .kube ]#cat config 
apiVersion: v1
clusters:
- cluster:certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeU1Ea3hOREF5TURjek5Wb1hEVE15TURreE1UQXlNRGN6TlZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTVB0CmJNNHg3STgvK01FQ29nY3lTNFRxK0ZzVHVtZi9JeFNXMXY4Q3NHVHVodEgrVElia21oYmlvenI4U0JtSGR2L1YKYTRjSjdzNGhxcE1LTnRiNk1IK1VZN0JqT25OT0J6TWYwbTg2cS9rRVFGRmZEdlRIU0kzYzBXK3BaRHZ5Y1EregphdXRGOHRjTWFtWk9KQU95U2xBN3NOelFCYlgrQW9lVFE0a29aVURGQm1oZjNIamdkanVtV3NERnZwVHMvd0wxCmlaV2p5dFd3c3J4RDIxK1lwa0ZkVUhRYnlxR2VuT0JscUYxbWhoTjkyY2VDcW80TDJSQlRYQXlKNVMxdG5EZ2gKR1B6WFNzN2cwNmhaaTlycEhPZ0RjdjByenBvdEdLc21LQm9DZ2RmcXovYlJ0UDk3UlA5ampXUHdDdUllR3Vwcwp6WGI4a1RINThleFp1cXNiS2dzQ0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZMUFRZRWppaWUrU3RYbENVK1REaWVRT3BjdWZNQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSDF6OHZjazBDaVZPT1J5QXZRYQpXV0s3WSt0WWZNSXhzcVBkU3A5My9yeXl2MkE0dWhTQjRiMDRGTmlLNWp4b2cvaDhoWmxIbFJoNDZzaUdMWlRjCmgwUHhmSlZ5L3UvdzNXZ2N0bXJMVTJ1VHVkcERkNm10YlhJRGhNempGWlh1VjFQa01oQk5ZVDUxS1hqY0dmTkMKY1JxMm5Vc1dCM0U5SjZJakNhWi80ME9wcjZBYUNoNWlWRUpmUzR6M3hHcm1uQ0lBeG5UaHBVUHEybjJ1NjZXOApQc2FvS0ZmTmZkUlEvSk5CUHVDUUs2RzRZM0syVEFYRkFMQzFXNEVmRmhKWUQ5RkxzQVk0TjUwQ1p2OVFNOXFuCmhrcW5SSGJqSGI4ZWdITThSRFU0UWNybm9IZzMycnB2MUtWcnZtVExQVVZ5dm85eUZpSm53ZzBJVVF3Rlc1R1UKelQwPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==server: https://10.10.0.10:6443

ServiceAccount是Pod使用的账号,Pod容器的进程需要访问API Server时用的就是ServiceAccount账户;
ServiceAccount仅局限它所在的namespace,每个namespace创建时都会自动创建一个default service account;
创建Pod时,如果没有指定Service Account,Pod则会使用default Service Account。

[root@master01 RBAC ]#kubectl get pods mysql-pod -oyaml
apiVersion: v1serviceAccount: defaultserviceAccountName: default

ServiceAccount使用案例介绍

创建sa,并绑定到pod

1、创建sa

[root@master01 RBAC ]#kubectl create sa sa-test
serviceaccount/sa-test created

2、创建pod

[root@master01 RBAC ]#vim pod.yaml
apiVersion: v1
kind: Pod
metadata:name: sa-testnamespace: defaultlabels:app: sa
spec:serviceAccountName: sa-test   指定sacontainers:- name:  sa-nginxports:- containerPort: 80image: nginximagePullPolicy: IfNotPresent
[root@master01 RBAC ]#kubectl get pods
NAME                               READY   STATUS      RESTARTS        AGE
sa-test                            1/1     Running     0               33s

创建pod时,会在pod里面创建一个目录 /var/run/secrets/kubernetes.io/serviceaccount ,里面有sa等相关文件信息

进入pod里面,

[root@master01 RBAC ]#kubectl exec -it sa-test -- /bin/bash
root@sa-test:/# cd /var/run/secrets/kubernetes.io/serviceaccount/root@sa-test:/var/run/secrets/kubernetes.io/serviceaccount# ls
ca.crt	namespace  token

请求K8S资源:

基于ca.crt 这个证书,找到token,访问kubernetes资源,访问的是kube-system名称空间

root@sa-test:/var/run/secrets/kubernetes.io/serviceaccount# curl --cacert ./ca.crt  -H "Authorization: Bearer $(cat ./token)"  https://kubernetes/api/v1/namespaces/kube-system
{"kind": "Status","apiVersion": "v1","metadata": {},"status": "Failure","message": "namespaces \"kube-system\" is forbidden: User \"system:serviceaccount:default:sa-test\" cannot get resource \"namespaces\" in API group \"\" in the namespace \"kube-system\"","reason": "Forbidden","details": {"name": "kube-system","kind": "namespaces"},"code": 403

上面结果能看到sa能通过https方式成功认证API,能够访问,但是没有权限访问k8s资源,所以code状态码是403,表示没有权限操作k8s资源

3、对sa做授权

[root@master01 ~ ]#kubectl create clusterrolebinding sa-test-admin-clusterrolebinding --clusterrole=cluster-admin --serviceaccount=default:sa-test
clusterrolebinding.rbac.authorization.k8s.io/sa-test-admin-clusterrolebinding created

解读:

kubectl create clusterrolebinding sa-test-admin-clusterrolebinding 创建clusterrolebinding ,对集群内所有名称空间都有权限

sa-test-admin-clusterrolebinding 这个是clusterrolebinding 的名字,自己随意取,跟已经存在的不冲突就行

–clusterrole=cluster-admin 表示与cluster-admin绑定 ,cluster-admin默认就存在的管理员,拥有集群内所有资源的所有权限,与它绑定后,
该clusterrolebinding也就有了所有集群资源权限

–serviceaccount=default:sa-test 指定sa的名称空间和名字 default是名称空间,sa-test是sa名字

再次请求:

root@sa-test:/var/run/secrets/kubernetes.io/serviceaccount# curl --cacert ./ca.crt  -H "Authorization: Bearer $(cat ./token)"  https://kubernetes/api/v1/namespaces/kube-system
{"kind": "Namespace","apiVersion": "v1","metadata": {"name": "kube-system","selfLink": "/api/v1/namespaces/kube-system","uid": "cb69328a-4655-4bdc-b105-1561b4a133fb","resourceVersion": "20","creationTimestamp": "2022-09-14T02:07:47Z","labels": {"kubernetes.io/metadata.name": "kube-system"},"managedFields": [{

可见已有权限

4、RBAC认证授权策略

RBAC介绍
在Kubernetes中,所有资源对象都是通过API进行操作,他们保存在etcd里。
而对etcd的操作我们需要通过访问 kube-apiserver 来实现,上面的Service Account其实就是APIServer的认证过程,
而授权的机制是通过RBAC:基于角色的访问控制实现。

RBAC有四个资源对象,分别是Role、ClusterRole、RoleBinding、ClusterRoleBinding

4.1 Role:角色

一组权限的集合,在一个命名空间中,可以用其来定义一个角色,
只能对命名空间内的资源进行授权。
如果是集群级别的资源,则需要使用ClusterRole。
例如:定义一个角色用来读取Pod的权限

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:namespace: rbacname: pod-read
rules:
- apiGroups: [""]resources: ["pods"]resourceNames: []
verbs: ["get","watch","list"]

rules中的参数说明:

1、apiGroups:支持的API组列表,例如:"apiVersion: apps/v1"等,不写的话支持所有api
2、resources:支持的资源对象列表,例如pods、deployments、jobs等
3、resourceNames: 指定resource的名称,不写指对所有的pod授权
4、verbs:对资源对象的操作方法列表。API 请求动词 - API 
动词 get、list、create、update、patch、watch、 proxy、redirect、delete 和 deletecollection 用于资源请求

HTTP 请求动词 - HTTP 动词 get、post、put 和 delete 用于非资源请求。
Resource - 正在访问的资源的 ID 或名称(仅限资源请求)-
对于使用 get、update、patch 和 delete 动词的资源请求,你必须提供资源名称。

4.2 ClusterRole:集群角色

具有和角色一致的命名空间资源的管理能力,还可用于以下特殊元素的授权,对名称空间没有限制
1、集群范围的资源,例如Node
2、非资源型的路径,例如:/healthz
3、包含全部命名空间的资源,例如Pods

例如:定义一个集群角色可让用户访问任意secrets

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:name: secrets-clusterrole
rules:
- apiGroups: [""]resources: ["secrets"]
verbs: ["get","watch","list"]

如果创建的用户通过rolebinding方式绑定了这个clusterrole,那么该sa只能对其所在名称空间下的secrets有查看权限
通过clusterrolebinding绑定该clusterrole,该用户对任何名称空间下的secrets有访问权限

4.3 RoleBinding:角色绑定、ClusterRolebinding:集群角色绑定

角色绑定和集群角色绑定用于把一个角色绑定在一个目标上,
可以是User,Group,Service Account,使用RoleBinding为某个命名空间授权,使用ClusterRoleBinding为集群范围内授权。
例如:将在rbac命名空间中把pod-read角色授予用户es

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: pod-read-bindnamespace: rbac
subjects:
- kind: Username: esapiGroup: rbac.authorization.k8s.io
roleRef:   绑定哪个rolekind: Rolename: pod-readapiGroup: rbac.authorizatioin.k8s.io

Useraccount用户,一般给kubectl使用

这样es用户只能对rbac名称空间下的 pod有查看权限,通过rolebinding绑定的,只能对特定的名称空间有权限

RoleBinding也可以引用ClusterRole,对属于同一命名空间内的ClusterRole定义的资源主体进行授权,
例如:es能获取到集群中所有的资源信息

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: es-allresourcenamespace: rbac
subjects:
- kind: Username: esapiGroup: rbac.authorization.k8s.io
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: cluster-admin

这样es绑定了cluster-admin,es用户就有了rbac名称空间下的所有资源有增删改查等任何权限

[root@master01 RBAC ]#kubectl explain rolebinding.subjects
KIND:     RoleBinding
VERSION:  rbac.authorization.k8s.io/v1RESOURCE: subjects <[]Object>DESCRIPTION:Subjects holds references to the objects the role applies to.Subject contains a reference to the object or user identities a rolebinding applies to. This can either hold a direct API object reference, ora value for non-objects such as user and group names.FIELDS:apiGroup	<string>APIGroup holds the API group of the referenced subject. Defaults to "" forServiceAccount subjects. Defaults to "rbac.authorization.k8s.io" for Userand Group subjects.kind	<string> -required-Kind of object being referenced. Values defined by this API group are"User", "Group", and "ServiceAccount". If the Authorizer does notrecognized the kind value, the Authorizer should report an error.
默认 ClusterRole      默认 ClusterRoleBindingcluster-admin:      system:masters 组  	允许超级用户在平台上的任何资源上执行所有操作。 
当在 ClusterRoleBinding 中使用时,可以授权对集群中以及所有名字空间中的全部资源进行完全控制。当在 RoleBinding 中使用时,可以授权控制角色绑定所在名字空间中的所有资源,包括名字空间本身。admin             无         允许管理员访问权限,旨在使用 RoleBinding 在名字空间内执行授权。
如果在 RoleBinding 中使用,则可授予对名字空间中的大多数资源的读/写权限, 
包括创建角色和角色绑定的能力。 此角色不允许对资源配额或者名字空间本身进行写操作。此角色也不允许对 Kubernetes v1.22+ 创建的 Endpoints 进行写操作。 更多信息参阅 “Endpoints 写权限”小节。    edit           允许对名字空间的大多数对象进行读/写操作。
此角色不允许查看或者修改角色或者角色绑定。 不过,此角色可以访问 Secret,
以名字空间中任何 ServiceAccount 的身份运行 Pod,所以可以用来了解名字空间内所有服务账户的 API 访问级别。 此角色也不允许对 Kubernetes v1.22+ 创建的 Endpoints 进行写操作。 更多信息参阅 “Endpoints 写操作”小节。view      允许对名字空间的大多数对象有只读权限。 它不允许查看角色或角色绑定。
此角色不允许查看 Secrets,因为读取 Secret 的内容意味着可以访问名字空间中 ServiceAccount 的凭据信息,
进而允许利用名字空间中任何 ServiceAccount 的身份访问 API(这是一种特权提升)。

5、资源的引用方式

多数资源可以用其名称的字符串表示,也就是Endpoint中的URL相对路径,
例如pod中的日志是GET /api/v1/namaspaces/{namespace}/pods/{podname}/log
如果需要在一个RBAC对象中体现上下级资源,就需要使用“/”分割资源和下级资源。
例如:若想授权让某个主体同时能够读取Pod和Pod log,则可以配置 resources为一个数组

创建test名称空间:

[root@master01 RBAC ]#kubectl create ns test
namespace/test created

创建一个在test名称空间下的角色logs-reader,对pod和pod的日志有访问权限

[root@master01 RBAC ]#vim role-test.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:name: logs-readernamespace: test
rules:
- apiGroups: [""]resources: ["pods","pods/log"]verbs: ["get","list","watch"]
[root@master01 RBAC ]#kubectl apply -f role-test.yaml 
role.rbac.authorization.k8s.io/logs-reader created
[root@master01 RBAC ]#kubectl get role -n test
NAME          CREATED AT
logs-reader   2022-09-28T07:41:55Z
[root@master01 ~ ]#kubectl describe role logs-reader -n test
Name:         logs-reader
Labels:       <none>
Annotations:  <none>
PolicyRule:Resources  Non-Resource URLs  Resource Names  Verbs---------  -----------------  --------------  -----pods/log   []                 []              [get list watch]pods       []                 []              [get list watch]

创建一个sa账号:

[root@master01 RBAC ]#kubectl create sa sa-test -n test
serviceaccount/sa-test created
[root@master01 RBAC ]#kubectl get sa -n test
NAME      SECRETS   AGE
default   1         4m17s  创建名称空间时,会自动创建一个默认的sa  default
sa-test   1         21s

通过rolebinding将sa-test绑定logs-reader这个role

[root@master01 RBAC ]#cat rolebinding-test.yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: sa-test-rolebindingnamespace: test
subjects:
- kind: ServiceAccountname: sa-testnamespace: test
roleRef:kind: Rolename: logs-readerapiGroup: rbac.authorization.k8s.io

也可以用命令行方式:

kubectl create rolebinding sa-test-rolebinding -n test  --role=logs-reader --serviceaccount=test:sa-test

创建个pod

[root@master01 RBAC ]#vim pod-test.yaml
apiVersion: v1
kind: Pod
metadata:name: sa-test-podnamespace: testlabels:app: sa
spec:serviceAccountName: sa-testcontainers:- name:  sa-nginxports:- containerPort: 80image: nginximagePullPolicy: IfNotPresent
[root@master01 RBAC ]#kubectl get pods -n test -owide
NAME          READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
sa-test-pod   1/1     Running   0          9s    172.29.55.29   node01   <none>           <none>

进入容器:

[root@master01 RBAC ]#kubectl exec -it sa-test-pod -n test -- /bin/bash

访问pod日志:
由于kubernetes这个svc是在default名称空间下,所以访问的请求需要加default https://kubernetes.default

查看默认名称空间下的pod

root@sa-test-pod:/var/run/secrets/kubernetes.io/serviceaccount# curl --cacert ./ca.crt  -H "Authorization: Bearer $(cat ./token)"  https://kubernetes.default/api/v1/namespaces/defaults/pods                
{"kind": "Status","apiVersion": "v1","metadata": {},"status": "Failure","message": "pods is forbidden: User \"system:serviceaccount:test:sa-test\" cannot list resource \"pods\" in API group \"\" in the namespace \"defaults\"","reason": "Forbidden","details": {"kind": "pods"},"code": 403

由此可见,访问默认名称空间下的pod是没有权限的

查看test名称空间下test-pod的日志:

root@sa-test-pod:/var/run/secrets/kubernetes.io/serviceaccount# curl --cacert ./ca.crt  -H "Authorization: Bearer $(cat ./token)"  https://kubernetes.default/api/v1/namespaces/test/pods/sa-test-pod/log 
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2022/09/29 00:51:20 [notice] 1#1: using the "epoll" event method
2022/09/29 00:51:20 [notice] 1#1: nginx/1.23.1
2022/09/29 00:51:20 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6) 
2022/09/29 00:51:20 [notice] 1#1: OS: Linux 4.19.12-1.el7.elrepo.x86_64
2022/09/29 00:51:20 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2022/09/29 00:51:20 [notice] 1#1: start worker processes
2022/09/29 00:51:20 [notice] 1#1: start worker process 31
2022/09/29 00:51:20 [notice] 1#1: start worker process 32
2022/09/29 00:51:20 [notice] 1#1: start worker process 33

由于对sa-test在test名称空间下做了授权,所有有权限查看test名称空间下的资源

资源还可以通过名称(ResourceName)进行引用,在指定ResourceName后,
使用get、delete、update、patch请求,就会被限制在这个资源实例范围内

例如,下面的声明让一个主体只能对名为my-configmap的Configmap进行get和update操作:

apiVersion: rabc.authorization.k8s.io/v1
kind: Role
metadata:namaspace: defaultname: configmap-update
rules:
- apiGroups: [""]resources: ["configmaps"]resourceNames: ["my-configmap"]verbs: ["get","update"]

6、常见角色(role)授权的案例

常见的角色和用户绑定模式:

(1)允许读取核心API组的Pod资源

rules:
- apiGroups: [""]resources: ["pods"]verbs: ["get","list","watch"]

(2)允许读写apps API组中的deployment资源

rules:
- apiGroups: ["apps"] 想对任意组资源有权限,就填空resources: ["deployments"]verbs: ["get","list","watch","create","update","patch","delete"]

(3)允许读取Pod以及读写job信息

rules:
- apiGroups: [""]resources: ["pods"]verbs: ["get","list","watch"]
- apiGroups: [""]resources: ["jobs"]verbs: ["get","list","watch","create","update","patch","delete"]

(4)允许读取一个名为my-config的ConfigMap(必须绑定到一个RoleBinding来限制到一个Namespace下的ConfigMap):

rules:
- apiGroups: [""]resources: ["configmaps"]resourceNames: ["my-configmap"]verbs: ["get"]

(5)读取核心组的Node资源(Node属于集群级的资源,所以必须存在于ClusterRole中,并使用ClusterRoleBinding进行绑定):

rules:
- apiGroups: [""]resources: ["nodes"]verbs: ["get","list","watch"]

(6)允许对非资源端点“/healthz”及其所有子路径进行GET和POST操作(必须使用ClusterRole和ClusterRoleBinding):

rules:
- nonResourceURLs: ["/healthz","/healthz/*"]verbs: ["get","post"]

7、常见的角色绑定示例

(1)用户名alice

subjects:
- kind: Username: aliceapiGroup: rbac.authorization.k8s.io

(2)组名alice

subjects:
- kind: Groupname: aliceapiGroup: rbac.authorization.k8s.io

(3)kube-system命名空间中默认Service Account

subjects:
- kind: ServiceAccountname: defaultnamespace: kube-system

8、对Service Account的授权管理

Service Account也是一种账号,是给运行在Pod里的进程提供了必要的身份证明。
需要在Pod定义中指明引用的Service Account,这样就可以对Pod的进行赋权操作。
例如:pod内可获取rbac命名空间的所有Pod资源,pod-reader-sc的Service Account是绑定了名为pod-read的Role

创建名称空间rbac

[root@master01 RBAC ]#vim rbac-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:name: rbac
[root@master01 RBAC ]#kubectl apply -f rbac-namespace.yaml 
namespace/rbac created

也可以命令行创建:

创建sa:

[root@master01 RBAC ]#vim sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:name: pod-reader-scnamespace: rbac

创建pod:

[root@master01 RBAC ]#vim pod-rbac.yaml
apiVersion: v1
kind: Pod
metadata:name: nginxnamespace: rbac
spec:serviceAccountName: pod-reader-sccontainers:- name: nginximage: nginximagePullPolicy: IfNotPresentports:- containerPort: 80
[root@master01 RBAC ]#kubectl get pods -n rbac -owide
NAME    READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          19s   172.29.55.32   node01   <none>           <none>

进入容器:

[root@master01 RBAC ]#kubectl exec -it nginx -n rbac -- /bin/bashcd /var/run/secrets/kubernetes.io/serviceaccountcurl --cacert ./ca.crt  -H "Authorization: Bearer $(cat ./token)"  https://kubernetes.default/api/v1/namespaces/rbac/pods
root@nginx:/var/run/secrets/kubernetes.io/serviceaccount# curl --cacert ./ca.crt  -H "Authorization: Bearer $(cat ./token)"  https://kubernetes.default/api/v1/namespaces/rbac/pods
{"kind": "Status","apiVersion": "v1","metadata": {},"status": "Failure","message": "pods is forbidden: User \"system:serviceaccount:rbac:pod-reader-sc\" cannot list resource \"pods\" in API group \"\" in the namespace \"rbac\"","reason": "Forbidden","details": {"kind": "pods"},"code": 403

发现没有权限,给sa授予查看权限:

[root@master01 RBAC ]#kubectl create rolebinding rbac-rolebinding --clusterrole=view --serviceaccount=rbac:pod-reader-sc -n rbac
rolebinding.rbac.authorization.k8s.io/rbac-rolebinding created

创建rolebinding时,必须指定命名空间。否在是创建在默认命名空间下,这样对指定的命名空间就没有权限

再次访问

root@nginx:/var/run/secrets/kubernetes.io/serviceaccount# curl --cacert ./ca.crt  -H "Authorization: Bearer $(cat ./token)"  https://kubernetes.default/api/v1/namespaces/rbac/pods
{"kind": "PodList","apiVersion": "v1","metadata": {"selfLink": "/api/v1/namespaces/rbac/pods","resourceVersion": "1395069"},"items": [{"metadata": {"name": "nginx","namespace": "rbac","selfLink": "/api/v1/namespaces/rbac/pods/nginx","uid": "ea47146a-0b17-47fc-a018-7f4d6b77e7c4",

有权限了

(1)my-namespace中的my-sa Service Account授予只读权限

kubectl create rolebinding my-sa-view --clusterrole=view --serviceaccount=my-namespace:my-sa --namespace=my-namespace

(2)为一个命名空间中名为default的Service Account授权
如果一个应用没有指定 serviceAccountName,则会使用名为default的Service Account。
注意,赋予Service Account “default”的权限会让所有没有指定serviceAccountName的Pod都具有这些权限

例如,在my-namespace命名空间中为Service Account“default”授予只读权限:

kubectl create rolebinding default-view --clusterrole=view --serviceaccount=my-namespace:default --namespace=my-namespace

(3)为命名空间中所有Service Account都授予一个角色
如果希望在一个命名空间中,任何Service Account应用都具有一个角色,则可以为这一命名空间的Service Account群组进行授权

kubectl create rolebinding serviceaccounts-view --clusterrole=view --group=system:serviceaccounts:my-namespace --namespace=my-namespace

这样,就算在那个名称空间下创建的sa没有做授权,那该sa还是有对该名称空间下资源查看的权限

(4)为集群范围内所有Service Account都授予一个低权限角色
如果不想为每个命名空间管理授权,则可以把一个集群级别的角色赋给所有Service Account。

kubectl create clusterrolebinding serviceaccounts-view --clusterrole=view --group=system:serviceaccounts

(5)为所有Service Account授予超级用户权限

kubectl create clusterrolebinding serviceaccounts-view --clusterrole=cluster-admin --group=system:serviceaccounts

这样,在任何名称空间下创建的sa都具有超级管理员权限

服务账户(ServiceAccount) 的用户名前缀为 system:serviceaccount:,属于前缀为 system:serviceaccounts: 的用户组。

说明:
system:serviceaccount: (单数)是用于服务账户用户名的前缀;
system:serviceaccounts: (复数)是用于服务账户组名的前缀。

9、使用kubectl命令行工具创建资源对象

(1)在命名空间rbac中为用户es授权admin ClusterRole:

kubectl create rolebinding bob-admin-binding --clusterrole=admin --user=es --namespace=rbac

admin不能对资源配额和名称空间本身进行修改,此角色不允许对资源配额或者名字空间本身进行写操作

(2)在命名空间rbac中为名为myapp的Service Account授予view ClusterRole:

kubctl create rolebinding myapp-role-binding --clusterrole=view --serviceaccount=rbac:myapp --namespace=rbac

myapp仅能查看rbac名称空间下的资源

(3)在全集群范围内为用户root授予cluster-admin ClusterRole:

kubectl create clusterrolebinding cluster-binding --clusterrole=cluster-admin --user=root

root用户对K8S资源进行任何操作

(4)在全集群范围内为名为myapp的Service Account授予view ClusterRole:

kubectl create clusterrolebinding service-account-binding --clusterrole=view --serviceaccount=myapp

yaml文件进行rbac授权:https://kubernetes.io/zh/docs/reference/access-authn-authz/rbac/

当命令记不住可以 --help查看帮助:

Usage:
kubectl create rolebinding NAME --clusterrole=NAME|–role=NAME [–user=username] [–group=groupname]
[–serviceaccount=namespace:serviceaccountname] [–dry-run=server|client|none] [options]

kubectl create clusterrolebinding NAME --clusterrole=NAME [–user=username] [–group=groupname]
[–serviceaccount=namespace:serviceaccountname] [–dry-run=server|client|none] [options]

10、限制不同的用户操作k8s集群

限制不同的用户只能访问哪些名称空间,哪些资源,不能全部访问所有

操作K8S集群需要用户,用户要被K8S信任,

ssl认证

生成一个证书
(1)生成一个私钥

cd /etc/kubernetes/pki/
umask 077; openssl genrsa -out lucky.key 2048

(2)生成一个证书请求

openssl req -new -key lucky.key -out lucky.csr -subj "/CN=lucky"

(3)生成一个证书,基于ca证书生成的

openssl x509 -req -in lucky.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out lucky.crt -days 3650

在kubeconfig下新增加一个lucky这个用户
(1)把lucky这个用户添加到kubernetes集群中,可以用来认证apiserver的连接 集群有CA认证,并且将证书的输入嵌入到配置文件中

[root@xianchaomaster1 pki]# kubectl config --kubeconfig=config-demo set-credentials lucky --client-certificate=./lucky.crt --client-key=./lucky.key --embed-certs=true  

指定–kubeconfig参数后,所有的配置都会写到对应的文件中,1.23.6版本默认保存在当前目录

注意:

[root@master01 pki ]#echo $KUBECONFIG 
/etc/kubernetes/admin.conf

不去掉的话修改的是/etc/kubernetes/admin.conf
去掉这个环境变量,之后不用添加 --kubeconfig=config-demo 也能修改默认的/root/.kube/config文件

[root@master01 pki ]#cat config-demo 
apiVersion: v1
clusters: null
contexts: null
current-context: ""
kind: Config
preferences: {}
users:
- name: luckyuser:client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNvVENDQVlrQ0NRQ1ZrOWJRek9FeXpEQU5CZ2txaGtpRzl3MEJBUXNGQURBVk1STXdFUVlEVlFRREV3cHIKZFdKbGNtNWxkR1Z6TUI0WERUSXlNRGt5T1RBMU16TXhNRm9YRFRNeU1Ea3lOakExTXpNeE1Gb3dFREVPTUF3RwpBMVVFQXd3RmJIVmphM2t3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ3A0d3QxCnFKMTVwTXBuR0JtdjNBdFhxOE5DVERvaldES01CaTEyaW5jNDhLYTdGa3J1RG9CSzNSNUNPRHZlRERaNStWWkkKWlY4S2xNdnRCRVhHQkN5clZvNC9PRjMwMmttRkZqWXhkNnNQYXBFdFNnZEdQdm9ONVBhMUl5d0x6VU9SUkZFNwpSNU5VZVA0NENGRnFPQ3dOU1B0MFJ3emtYSzdPbE03UlBrbHQ4RU1WNFAwOUozMVFmeWlpN0lMQ2J1TlNxeGJsCjA3QVpQWDFFY3Z3V1RvYmVyN0FHYnE0UjhZMFRTWmdFdGNIZ1NPcUtCcytmZFl2TFE0S2dmM2JsbmNxTjlNSVkKeFozV1kySTJBWWw0dlZpWXlsS3FEdXdXaGo1cjZMaUx4K29Rd0U3Z3oyUkswNFlQa2I2U1pNSG1JK1Y4SjVVYgpPRFk5NFpCb3d6ZmVOUmxsQWdNQkFBRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRmVPbkRxeWlISnVNZWdwCnNodnNzRkpyV25VbndUUlVRaG5va1QzYUd4LytiaUcwYXNTSGV2MkErUFBsb1k2SnA5VVUwMm84TWtnbHY4djkKNTRCWXowbDVjMGxORnZ5RjVFRWlRdlh3dnN4bWpFeFpyTHFSSVVJclFzUi9MaktxUnQ4S0lYZVU2bm9abGFUZAp2RTFrVXRhbXZLZnlsWlNkcDZicUxWalJsYlg2eC92ZWNid2ViVmxJL1Z0OXJ2ZmxpOEpFY2dMU2NJa3Uxalc5Cms0REhqZm5BaC9NN1p6aitoSFZvUU5iQXlSZlA2ckpocEVjZ29ETEF4QmlEdWpPSzg1cnFaYXRRckljUEtSeDMKdnhURUJJTy9LZ3djeG51STlnY0RnWUhWb2VCVUJ0WEZ2dG9wNlFaRk5PK2poTTJVaXppeVBhVWlkYndIQ1B5SgpuaStIYWlFPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBcWVNTGRhaWRlYVRLWnhnWnI5d0xWNnZEUWt3NkkxZ3lqQVl0ZG9wM09QQ211eFpLCjdnNkFTdDBlUWpnNzNndzJlZmxXU0dWZkNwVEw3UVJGeGdRc3ExYU9QemhkOU5wSmhSWTJNWGVyRDJxUkxVb0gKUmo3NkRlVDJ0U01zQzgxRGtVUlJPMGVUVkhqK09BaFJhamdzRFVqN2RFY001Rnl1enBUTzBUNUpiZkJERmVEOQpQU2Q5VUg4b291eUN3bTdqVXFzVzVkT3dHVDE5UkhMOEZrNkczcSt3Qm02dUVmR05FMG1ZQkxYQjRFanFpZ2JQCm4zV0x5ME9Db0g5MjVaM0tqZlRDR01XZDFtTmlOZ0dKZUwxWW1NcFNxZzdzRm9ZK2EraTRpOGZxRU1CTzRNOWsKU3RPR0Q1RytrbVRCNWlQbGZDZVZHemcyUGVHUWFNTTMzalVaWlFJREFRQUJBb0lCQUJ2Uk5IQW9rdGgzTmprWgpSaU40aVZicXBnYzJDaEw5ZnhGVWRaOUNYdkV3M213bDQxRUZpTlk1VEpvVk1TQlRxWnZoU3RLQjNzVVJ4aTVpCkU3YXZ1a3kzMklUYml1N3J5endDZmc4dGhCSDdKaGhmVmIrWDBrUHlLTDlTS2dVb3NCYWFOQjdid25FRGVzVGIKLzlDL3I5N2hBMk52dXRtdG4yWHVFY3RMUXFUQWZSUHl3a0FGTmhmV2c5L3lJWTd0STRYQWhkdlNOSkVHWFhQNwphaGRSM3JwaEdqdU5NcExkRlZYb24zSnA1TTZNM0hWTkdKK00wR05OOVdxM1BOMVp4R2JCR2MvU3YxMVBwd3BjCm1iNVBXSUxWS3QzWkI0bU9QcFJCbFN1V3ZhdU5QWlJORWQ3cVh0cUlRUGhmWU9ocGQ2bklYbXY5TlZwdDlyTS8KZjkxMUppVUNnWUVBMytPREg1T0Y0bE5PZ1VzQkE3QVVDNU8zY0F2ZTNZbFl4TGI3eHgxMmthNDZVZko5aTJRYQpUZjRZUkNSTEZoeEpOc3V3bFQwRlFmZXBlbnpRNVFGTFU1ZGFxU2RpMUhOSWI1VGZQNWpEbFhMbTNLRnVkb1RPCklsYmtkS1gxZ1J2S0pzdFgrbUZObTE1dGVaRkxZRkp6anZsRWltdzNmdFJubElIV1ZBc1l6K01DZ1lFQXdrREIKZS9vaWVUVWtXY3pRa3h3R0dGblRHUEp1WWxCRlU2Z2owL3E2cVV3S1NXRUkzb3RtbDlQbVJJOWtwMm5JYldOUQpBT0E0dElJZjhWMVRsN2o3L2dBVnJyYWpoeGJ1cVpUbmdTenU3NVp6Q012UjdYcmV4dm15a2xzK2JKK3RsVWpECjlzSlNYb1FHOWxYeWNQZ1hHN2xOU3NDcVJ3N3ZXbDRDcE42UHBCY0NnWUVBMVhQQmhZOU9hOUxrMjl1NFlkMnoKbnIzOGU3UzFqQnp3SnN3V0MyWUpyeWFlcjVZekgzd1dvQmtLNVp4OGdkNEI1MTRYUXBGa3U5bjFHTFI3TEhvcAphTTY2UHQ4d0dFQzQ1TGpZaDNlTHNLWlZlQy9vY3RKMi9NSS9HUDlJcXdqbG1FcngyK0o4N1EzLzdaRWFmZ0RkCjc0ZXpVdzJOY3p2cWJPbkVmMmY5QmVVQ2dZQm0wK2lZUER6cmRKb2RmeklaN1llOGREQXUwSVptUEorMlBSZGEKS3l1TVd0aEhKN3FPTTdUSFFrQnVvb2xocGJtWFRpOFhoNW44MDdVZEM0NG9qcCsyUVUwNUF5MWxZVnBOSXFtNQowNU5YK0loRWE4Qmd1ZDRiN2luOUY1ZmY0RmIrNDFuNDBielFrNHNyOHlzM2FkeXhyRkdoOUlNdXdsVXB2UUloClREODFXUUtCZ1FEV0d6dlBKU3IvWW5hMWE1cnU5TnZGWm42TDdFdHBiSU1wUUw1Y1c1YmtYQVpib0Exc1BQUjgKd1FDYW52OUdOSjEvT2JJajJpb0xrZHNGM2pKRlhSdnpGNWpjVGswb3UrdE1VWkNJR2F4TGxtbDdYZzdLank3RAphT0N1V1E2SWN2WlFSeW11N0ZKbXF1ektZYnVJZVVoL3Y0REFLSXc2MmFhTEFrWVVLOVRCNEE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=

(2)在kubeconfig下新增加一个lucky这个账号

kubectl config  set-context lucky@kubernetes --cluster=kubernetes --user=lucky

(3)切换账号到lucky,默认没有任何权限
kubectl config use-context lucky@kubernetes
kubectl config use-context kubernetes-admin@kubernetes 这个是集群用户,有任何权限
把user这个用户通过rolebinding绑定到clusterrole上,授予权限,权限只是在lucky这个名称空间有效
(1)把lucky这个用户通过rolebinding绑定到clusterrole上

kubectl create ns lucky-test
kubectl create rolebinding lucky -n lucky-test --clusterrole=cluster-admin --user=lucky

该角色只对lucky-test名称空间下的资源有管理员权限,对其他名称空间下没有权限

[root@master01 .kube ]#kubectl get pods -n lucky-test
No resources found in lucky-test namespace.
[root@master01 .kube ]#kubectl get pods
Error from server (Forbidden): pods is forbidden: User "lucky" cannot list resource "pods" in API group "" in the namespace "default"

设置集群,不然配置文件里面没有集群:

[root@master01 pki ]#kubectl config  set-cluster development --server=https://10.10.0.10

这里直接采用原来的集群就可以

(2)切换到lucky这个用户

kubectl config use-context lucky@kubernetes

(3)测试是否有权限

kubectl get pods -n lucky-test

有权限操作这个名称空间

[root@master01 .kube ]#kubectl config view
apiVersion: v1
clusters:
- cluster:certificate-authority-data: DATA+OMITTEDserver: https://10.10.0.10:6443name: kubernetes
contexts:
- context:cluster: kubernetesuser: kubernetes-adminname: kubernetes-admin@kubernetes
- context:cluster: kubernetesuser: luckyname: lucky@kubernetes
current-context: lucky@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-adminuser:client-certificate-data: REDACTEDclient-key-data: REDACTED
- name: luckyuser:client-certificate-data: REDACTEDclient-key-data: REDACTED

在lucky-test名称空间下有权限:

[root@master01 .kube ]#kubectl create sa jingtian -n lucky-test
serviceaccount/jingtian created

假如公司来了个K8S技术人员,只需要创建用户
/root/.kube/config
文件copy到root/下

将kubernetes-admin相关内容删掉,将刚才生成的config-daemon相关文件复制过来

[root@master01 ~ ]#cat config
apiVersion: v1
clusters:
- cluster:certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeU1Ea3hOREF5TURjek5Wb1hEVE15TURreE1UQXlNRGN6TlZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTVB0CmJNNHg3STgvK01FQ29nY3lTNFRxK0ZzVHVtZi9JeFNXMXY4Q3NHVHVodEgrVElia21oYmlvenI4U0JtSGR2L1YKYTRjSjdzNGhxcE1LTnRiNk1IK1VZN0JqT25OT0J6TWYwbTg2cS9rRVFGRmZEdlRIU0kzYzBXK3BaRHZ5Y1EregphdXRGOHRjTWFtWk9KQU95U2xBN3NOelFCYlgrQW9lVFE0a29aVURGQm1oZjNIamdkanVtV3NERnZwVHMvd0wxCmlaV2p5dFd3c3J4RDIxK1lwa0ZkVUhRYnlxR2VuT0JscUYxbWhoTjkyY2VDcW80TDJSQlRYQXlKNVMxdG5EZ2gKR1B6WFNzN2cwNmhaaTlycEhPZ0RjdjByenBvdEdLc21LQm9DZ2RmcXovYlJ0UDk3UlA5ampXUHdDdUllR3Vwcwp6WGI4a1RINThleFp1cXNiS2dzQ0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZMUFRZRWppaWUrU3RYbENVK1REaWVRT3BjdWZNQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSDF6OHZjazBDaVZPT1J5QXZRYQpXV0s3WSt0WWZNSXhzcVBkU3A5My9yeXl2MkE0dWhTQjRiMDRGTmlLNWp4b2cvaDhoWmxIbFJoNDZzaUdMWlRjCmgwUHhmSlZ5L3UvdzNXZ2N0bXJMVTJ1VHVkcERkNm10YlhJRGhNempGWlh1VjFQa01oQk5ZVDUxS1hqY0dmTkMKY1JxMm5Vc1dCM0U5SjZJakNhWi80ME9wcjZBYUNoNWlWRUpmUzR6M3hHcm1uQ0lBeG5UaHBVUHEybjJ1NjZXOApQc2FvS0ZmTmZkUlEvSk5CUHVDUUs2RzRZM0syVEFYRkFMQzFXNEVmRmhKWUQ5RkxzQVk0TjUwQ1p2OVFNOXFuCmhrcW5SSGJqSGI4ZWdITThSRFU0UWNybm9IZzMycnB2MUtWcnZtVExQVVZ5dm85eUZpSm53ZzBJVVF3Rlc1R1UKelQwPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==server: https://10.10.0.10:6443name: kubernetescontexts:
- context:cluster: kubernetesuser: luckyname: lucky@kubernetes
current-context: lucky@kubernetes
kind: Config
preferences: {}
users:
- name: luckyuser:client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNvVENDQVlrQ0NRQ1ZrOWJRek9FeXpEQU5CZ2txaGtpRzl3MEJBUXNGQURBVk1STXdFUVlEVlFRREV3cHIKZFdKbGNtNWxkR1Z6TUI0WERUSXlNRGt5T1RBMU16TXhNRm9YRFRNeU1Ea3lOakExTXpNeE1Gb3dFREVPTUF3RwpBMVVFQXd3RmJIVmphM2t3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ3A0d3QxCnFKMTVwTXBuR0JtdjNBdFhxOE5DVERvaldES01CaTEyaW5jNDhLYTdGa3J1RG9CSzNSNUNPRHZlRERaNStWWkkKWlY4S2xNdnRCRVhHQkN5clZvNC9PRjMwMmttRkZqWXhkNnNQYXBFdFNnZEdQdm9ONVBhMUl5d0x6VU9SUkZFNwpSNU5VZVA0NENGRnFPQ3dOU1B0MFJ3emtYSzdPbE03UlBrbHQ4RU1WNFAwOUozMVFmeWlpN0lMQ2J1TlNxeGJsCjA3QVpQWDFFY3Z3V1RvYmVyN0FHYnE0UjhZMFRTWmdFdGNIZ1NPcUtCcytmZFl2TFE0S2dmM2JsbmNxTjlNSVkKeFozV1kySTJBWWw0dlZpWXlsS3FEdXdXaGo1cjZMaUx4K29Rd0U3Z3oyUkswNFlQa2I2U1pNSG1JK1Y4SjVVYgpPRFk5NFpCb3d6ZmVOUmxsQWdNQkFBRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRmVPbkRxeWlISnVNZWdwCnNodnNzRkpyV25VbndUUlVRaG5va1QzYUd4LytiaUcwYXNTSGV2MkErUFBsb1k2SnA5VVUwMm84TWtnbHY4djkKNTRCWXowbDVjMGxORnZ5RjVFRWlRdlh3dnN4bWpFeFpyTHFSSVVJclFzUi9MaktxUnQ4S0lYZVU2bm9abGFUZAp2RTFrVXRhbXZLZnlsWlNkcDZicUxWalJsYlg2eC92ZWNid2ViVmxJL1Z0OXJ2ZmxpOEpFY2dMU2NJa3Uxalc5Cms0REhqZm5BaC9NN1p6aitoSFZvUU5iQXlSZlA2ckpocEVjZ29ETEF4QmlEdWpPSzg1cnFaYXRRckljUEtSeDMKdnhURUJJTy9LZ3djeG51STlnY0RnWUhWb2VCVUJ0WEZ2dG9wNlFaRk5PK2poTTJVaXppeVBhVWlkYndIQ1B5SgpuaStIYWlFPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBcWVNTGRhaWRlYVRLWnhnWnI5d0xWNnZEUWt3NkkxZ3lqQVl0ZG9wM09QQ211eFpLCjdnNkFTdDBlUWpnNzNndzJlZmxXU0dWZkNwVEw3UVJGeGdRc3ExYU9QemhkOU5wSmhSWTJNWGVyRDJxUkxVb0gKUmo3NkRlVDJ0U01zQzgxRGtVUlJPMGVUVkhqK09BaFJhamdzRFVqN2RFY001Rnl1enBUTzBUNUpiZkJERmVEOQpQU2Q5VUg4b291eUN3bTdqVXFzVzVkT3dHVDE5UkhMOEZrNkczcSt3Qm02dUVmR05FMG1ZQkxYQjRFanFpZ2JQCm4zV0x5ME9Db0g5MjVaM0tqZlRDR01XZDFtTmlOZ0dKZUwxWW1NcFNxZzdzRm9ZK2EraTRpOGZxRU1CTzRNOWsKU3RPR0Q1RytrbVRCNWlQbGZDZVZHemcyUGVHUWFNTTMzalVaWlFJREFRQUJBb0lCQUJ2Uk5IQW9rdGgzTmprWgpSaU40aVZicXBnYzJDaEw5ZnhGVWRaOUNYdkV3M213bDQxRUZpTlk1VEpvVk1TQlRxWnZoU3RLQjNzVVJ4aTVpCkU3YXZ1a3kzMklUYml1N3J5endDZmc4dGhCSDdKaGhmVmIrWDBrUHlLTDlTS2dVb3NCYWFOQjdid25FRGVzVGIKLzlDL3I5N2hBMk52dXRtdG4yWHVFY3RMUXFUQWZSUHl3a0FGTmhmV2c5L3lJWTd0STRYQWhkdlNOSkVHWFhQNwphaGRSM3JwaEdqdU5NcExkRlZYb24zSnA1TTZNM0hWTkdKK00wR05OOVdxM1BOMVp4R2JCR2MvU3YxMVBwd3BjCm1iNVBXSUxWS3QzWkI0bU9QcFJCbFN1V3ZhdU5QWlJORWQ3cVh0cUlRUGhmWU9ocGQ2bklYbXY5TlZwdDlyTS8KZjkxMUppVUNnWUVBMytPREg1T0Y0bE5PZ1VzQkE3QVVDNU8zY0F2ZTNZbFl4TGI3eHgxMmthNDZVZko5aTJRYQpUZjRZUkNSTEZoeEpOc3V3bFQwRlFmZXBlbnpRNVFGTFU1ZGFxU2RpMUhOSWI1VGZQNWpEbFhMbTNLRnVkb1RPCklsYmtkS1gxZ1J2S0pzdFgrbUZObTE1dGVaRkxZRkp6anZsRWltdzNmdFJubElIV1ZBc1l6K01DZ1lFQXdrREIKZS9vaWVUVWtXY3pRa3h3R0dGblRHUEp1WWxCRlU2Z2owL3E2cVV3S1NXRUkzb3RtbDlQbVJJOWtwMm5JYldOUQpBT0E0dElJZjhWMVRsN2o3L2dBVnJyYWpoeGJ1cVpUbmdTenU3NVp6Q012UjdYcmV4dm15a2xzK2JKK3RsVWpECjlzSlNYb1FHOWxYeWNQZ1hHN2xOU3NDcVJ3N3ZXbDRDcE42UHBCY0NnWUVBMVhQQmhZOU9hOUxrMjl1NFlkMnoKbnIzOGU3UzFqQnp3SnN3V0MyWUpyeWFlcjVZekgzd1dvQmtLNVp4OGdkNEI1MTRYUXBGa3U5bjFHTFI3TEhvcAphTTY2UHQ4d0dFQzQ1TGpZaDNlTHNLWlZlQy9vY3RKMi9NSS9HUDlJcXdqbG1FcngyK0o4N1EzLzdaRWFmZ0RkCjc0ZXpVdzJOY3p2cWJPbkVmMmY5QmVVQ2dZQm0wK2lZUER6cmRKb2RmeklaN1llOGREQXUwSVptUEorMlBSZGEKS3l1TVd0aEhKN3FPTTdUSFFrQnVvb2xocGJtWFRpOFhoNW44MDdVZEM0NG9qcCsyUVUwNUF5MWxZVnBOSXFtNQowNU5YK0loRWE4Qmd1ZDRiN2luOUY1ZmY0RmIrNDFuNDBielFrNHNyOHlzM2FkeXhyRkdoOUlNdXdsVXB2UUloClREODFXUUtCZ1FEV0d6dlBKU3IvWW5hMWE1cnU5TnZGWm42TDdFdHBiSU1wUUw1Y1c1YmtYQVpib0Exc1BQUjgKd1FDYW52OUdOSjEvT2JJajJpb0xrZHNGM2pKRlhSdnpGNWpjVGswb3UrdE1VWkNJR2F4TGxtbDdYZzdLank3RAphT0N1V1E2SWN2WlFSeW11N0ZKbXF1ektZYnVJZVVoL3Y0REFLSXc2MmFhTEFrWVVLOVRCNEE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=

添加一个test的普通用户

useradd test
cp -ar /root/config /home/test/.kube/

修改/tmp/.kube/config文件,把kubernetes-admin相关的删除,只留lucky用户

chown -R test.test /home/test/
su - test
kubectl get pods -n lucky
[test@master01 .kube ]$kubectl get pods
Error from server (Forbidden): pods is forbidden: User "lucky" cannot list resource "pods" in API group "" in the namespace "default"
[test@master01 .kube ]$kubectl get pods -n lucky-test
No resources found in lucky-test namespace.

可以了

[test@master01 ~ ]$kubectl create sa nihao -n lucky-test
serviceaccount/nihao created
[test@master01 ~ ]$
[test@master01 ~ ]$
[test@master01 ~ ]$kubectl get sa -n lucky-test
NAME      SECRETS   AGE
default   1         102m
jinghao   1         74m
nihao     1         16s

如果报这个错,可以把之前配置的环境变量去掉

[test@master01 ~ ]$kubectl create sa nihao -n lucky-test
error: error loading config file "/etc/kubernetes/admin.conf": open /etc/kubernetes/admin.conf: permission denied
[test@master01 ~ ]$unset KUBECONFIG 
[test@master01 ~ ]$kubectl create sa nihao -n lucky-test
serviceaccount/nihao created

退出test用户,需要在把集群环境切换成管理员权限

kubectl config use-context kubernetes-admin@kubernetes

创建具有集群所有pod的查看权限:
如上创建用户lucky66-read

其他类似
创建clusterrole:

[root@master01 RBAC ]#vim read-clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:name: lucky66
rules:
- apiGroups: [""]resources: ["pods"]verbs: ["get","list","watch"]

对所有pod有查看权限

[root@master01 RBAC ]#kubectl get clusterrole
NAME                                                                   CREATED AT
lucky66                                                                2022-09-29T08:06:05Z

然后将用户与该角色绑定:

[root@master01 RBAC ]#kubectl create clusterrolebinding lucky66-rolebinding --clusterrole=lucky66  --user=lucky66-read
clusterrolebinding.rbac.authorization.k8s.io/lucky66-rolebinding created

其他类似。

11、准入控制

11.1  ResourceQuota准入控制器

ResourceQuota准入控制器是k8s上内置的准入控制器,默认该控制器是启用的状态,
它主要作用是用来限制一个名称空间下的资源的使用,它能防止在一个名称空间下的pod被过多创建时,
导致过多占用k8s资源,简单讲它是用来在名称空间级别限制用户的资源使用。

当多个用户或团队共享具有固定节点数目的集群时,人们会担心有人使用超过其基于公平原则所分配到的资源量。

资源配额是帮助管理员解决这一问题的工具。

资源配额,通过 ResourceQuota 对象来定义,对每个命名空间的资源消耗总量提供限制。
它可以限制命名空间中某种类型的对象的总数目上限,也可以限制命名空间中的 Pod 可以使用的计算资源的总上限。

资源配额的工作方式如下:

不同的团队可以在不同的命名空间下工作。这可以通过 RBAC 强制执行。

集群管理员可以为每个命名空间创建一个或多个 ResourceQuota 对象。

当用户在命名空间下创建资源(如 Pod、Service 等)时,Kubernetes 的配额系统会跟踪集群的资源使用情况,
以确保使用的资源用量不超过 ResourceQuota 中定义的硬性资源限额。

如果资源创建或者更新请求违反了配额约束,那么该请求会报错(HTTP 403 FORBIDDEN),
并在消息中给出有可能违反的约束。

如果命名空间下的计算资源 (如 cpu 和 memory)的配额被启用,
则用户必须为这些资源设定请求值(request)和约束值(limit),
否则配额系统将拒绝 Pod 的创建。

提示: 可使用 LimitRanger 准入控制器来为没有设置计算资源需求的 Pod 设置默认值

1.限制cpu、内存、pod、deployment数量

创建resourcequota资源

[root@xianchaomaster1 ~]# kubectl create ns quota
[root@xianchaomaster1 ~]# cat resourcequota-1.yaml 
apiVersion: v1
kind: ResourceQuota
metadata:name: quota-testnamespace: quota
spec:hard:pods: "6"requests.cpu: "2"requests.memory: 2Gilimits.cpu: "4"limits.memory: 10Gicount/deployments.apps: "6"persistentvolumeclaims: "6"
[root@xianchaomaster1 ~]# kubectl apply -f resourcequota-1.yaml

创建pod进行测试

资源清单YAML文件解读:
spec.hard字段是用来定义对应名称空间下的资源限制规则;
pods用来限制在对应名称空间下的pod数量,
requests.cpu字段 所有非终止状态的 Pod,其 CPU 需求总量不能超过该值;
requests.memory所有非终止状态的 Pod,其内存需求总量不能超过该值;
limits.cpu用来限制对应名称空间下的podcpu资源的上限总和,
limits.memory用来限制对应名称空间下pod内存资源上限总和;
count/deployments.apps用来限制对应名称空间下apps群组下的deployments的个数;
以上配置清单表示,在quota名称空间下运行的pod数量不能超过6个,
所有pod的cpu资源下限总和不能大于2个核心,
内存资源下限总和不能大于2G,
cpu上限资源总和不能大于4个核心,
内存上限总和不能超过10G,
apps群组下的deployments控制器不能超过6个,
pvc个数不能超过6个;
以上条件中任意一个条目不满足,都将无法在对应名称空间创建对应的资源。

 [root@xianchaomaster1]# cat quota-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:name: quotanamespace: quota
spec:replicas: 7selector:matchLabels:app: quotatemplate:metadata:labels:app: quotaspec:containers:- name: myappimage: janakiramm/myapp:v1imagePullPolicy: IfNotPresentports:- containerPort: 80resources:requests:cpu: 10mmemory: 10Milimits:cpu: 10mmemory: 10Mi
[root@master01 RBAC ]#kubectl get pods -n quota
NAME                     READY   STATUS    RESTARTS      AGE
quota-549dbc5564-2d929   1/1     Running   0             76s
quota-549dbc5564-2q9sg   1/1     Running   1 (35s ago)   73s
quota-549dbc5564-bswfx   1/1     Running   0             76s
quota-549dbc5564-clk7f   1/1     Running   0             73s
quota-549dbc5564-hbhx2   1/1     Running   0             76s
quota-549dbc5564-xhc67   1/1     Running   2 (26s ago)   73s

由于做了空间级别的资源限额,虽然配置了7个副本,最终只能创建资源限制的6个

资源限额的pod创建:
如果对命名空间做了resourcequota资源限额,
那在该命名空间下创建的pod也要做资源限额resources字段必须填写,否则创建不出pod

[root@master01 RBAC ]#vim quota-deployment-2.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:name: quotanamespace: quota
spec:replicas: 7selector:matchLabels:app: quotatemplate:metadata:labels:app: quotaspec:containers:- name: myappimage: janakiramm/myapp:v1imagePullPolicy: IfNotPresentports:- containerPort: 80
[root@master01 RBAC ]#kubectl apply -f quota-deployment-2.yaml 
deployment.apps/quota created
[root@master01 RBAC ]#kubectl get pods -n quota
No resources found in quota namespace.
[root@master01 RBAC ]#kubectl get deploy -n quota
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
quota   0/7     0            0           57s

有控制器,pod创建不出

2.限制存储空间大小

[root@xianchaomaster1 ~]# vim resourcequota-2.yaml 
apiVersion: v1
kind: ResourceQuota
metadata:name: quota-storage-testnamespace: quota
spec:hard:requests.storage: "5Gi"persistentvolumeclaims: "5"requests.ephemeral-storage: "1Gi"limits.ephemeral-storage: "2Gi"
[root@xianchaomaster1 ~]# kubectl apply -f resourcequota-2.yaml

备注:requests.storage用来限制对应名称空间下的存储下限总和,
persistenvolumeclaims用来限制pvc总数量,
requests.ephemeral-storage用来现在使用本地临时存储的下限总容量;
limits.ephemeral-storage用来限制使用本地临时存储上限总容量;
以上配置表示在default名称空间下非停止状态的容器存储下限总容量不能超过5G,
pvc的数量不能超过5个,本地临时存储下限容量不能超过1G,上限不能超过2G。

可以与CPU,MEM写到一块

11.2 LimitRanger准入控制器

LimitRanger准入控制器是k8s上一个内置的准入控制器,LimitRange是k8s上的一个标准资源,
它主要用来定义在某个名称空间下限制pod或pod里的容器对k8s上的cpu和内存资源使用;
它能够定义我们在某个名称空间下创建pod时使用的cpu和内存的上限和下限以及默认cpu、内存的上下限。
如果我们创建pod时定义了资源上下限,但不满足LimitRange规则中定义的资源上下限,
此时LimitRanger就会拒绝我们创建此pod;
如果我们在LimitRange规则中定义了默认的资源上下限制,
我们创建资源没有指定其资源限制,
它默认会使用LimitRange规则中的默认资源限制;
同样的逻辑LimitRanger可以限制一个pod使用资源的上下限,
它还可以限制pod中的容器的资源上下限,比限制pod更加精准;
不管是针对pod还是pod里的容器,它始终只是限制单个pod资源使用。

[root@xianchaomaster1 ~]# cat limitrange.yaml 
apiVersion: v1
kind: Namespace
metadata:name: limit
---
apiVersion: v1
kind: LimitRange
metadata:name: cpu-memorynamespace: limit
spec:limits:- default:cpu: 1000mmemory: 1000MidefaultRequest:cpu: 500mmemory: 500Mimin:cpu: 500mmemory: 500Mimax:cpu: 2000mmemory: 2000MimaxLimitRequestRatio:cpu: 4memory: 4type: Container
[root@xianchaomaster1 ~]# kubectl apply -f limitrange.yaml

备注:以上清单主要定义了两个资源,一个创建limit名称空间,
一个是在对应limit名称空间下定义了LimitRange资源;
其中LimitRange资源的名称为cpu-memory,default字段用来指定默认容器资源上限值;
defaultRequest用来指定默认容器资源下限值;
min字段用来指定限制用户指定的资源下限不能小于对应资源的值;
max是用来限制用户指定资源上限值不能大于该值;
maxLimitRequestRatio字段用来指定资源的上限和下限的比值;即上限是下限的多少倍;
type是用来描述对应资源限制的级别,该字段有两个值pod和container。

上述资源清单表示在该名称空间下创建pod时,默认不指定其容器的资源限制,
就限制对应容器最少要有0.5个核心的cpu和500M的内存;
最大为1个核心cpu,1g内存;
如果我们手动定义了容器的资源限制,那么对应资源限制最小不能小于cpu为0.5个核心,
内存为500M,最大不能超过cpu为2个核心,内存为2000M;
如果我们在创建pod时,只指定了容器的资源上限或下限,
那么上限最大是下限的的4倍,如果指定cpu上限为2000m那么下限一定不会小于500m,
如果只指定了cpu下限为500m那么上限最大不会超过2000m,对于内存也是同样的逻辑。

1)在limit名称空间创建pod,不指定资源,看看是否会被limitrange规则自动附加其资源限制?

[root@xianchaomaster1 ~]# cat pod-limit.yaml 
apiVersion: v1
kind: Pod
metadata:name: nginx-pod-demonamespace: limit
spec:containers:- image: nginximagePullPolicy: IfNotPresentname: nginx
[root@master01 RBAC ]#kubectl describe pod nginx-pod-demo -n limitRestart Count:  0Limits:cpu:     1memory:  1000MiRequests:cpu:        500mmemory:     500MiEnvironment:  <none>

通过上面结果可以看到我们在limit名称空间下创建的pod没有指定其容器资源限制,创建pod后,
其内部容器自动就有了默认的资源限制;
其大小就是我们在定义LimitRange规则中的default和defaultRequest字段中指定的资源限制。

2)创建pod,指定cpu请求是100m,看看是否允许创建

[root@master01 RBAC ]#vim pod-request.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-requestnamespace: limit
spec:containers:- image: nginximagePullPolicy: IfNotPresentname: nginxresources:requests:cpu: 100mmemory: 400Mi
[root@master01 RBAC ]#kubectl apply -f pod-request.yaml 
Error from server (Forbidden): error when creating "pod-request.yaml": pods "pod-request" is forbidden: 
[minimum cpu usage per Container is 500m, but request is 100m, minimum memory usage per Container is 500Mi,but request is 400Mi, cpu max limit to request ratio per Container is 4, but provided ratio is 10.000000]

这里CPU用的是默认的大小1000 与配置的100计算的比值为10

相关文章:

  • 虚拟机Ubuntu 22.04上搭建GitLab操作步骤
  • 黑客团伙利用Python、Golang和Rust恶意软件袭击印国防部门;OpenAI揭秘,AI模型如何被用于全球虚假信息传播? | 安全周报0531
  • 《异常检测——从经典算法到深度学习》29 EasyTSAD: 用于时间序列异常检测模型的工业级基准
  • 深入分析 Android Activity (二)
  • 软考系统集成项目管理工程师第7章思维导图发布
  • 探索AI去衣技术中的反射应用
  • FreeRTOS基础(三):动态创建任务
  • 面试题:计算机网络中的七四五是什么?
  • pytorch学习笔记3
  • Vue:现代前端开发的首选框架-【高级特性篇】
  • JAVA:异步任务处理类CompletableFuture让性能提升一倍
  • 如何设置手机的DNS
  • 基于tensorflow和NasNet的皮肤癌分类项目
  • SQL—DQL(数据查询语言)之小结
  • 【TensorFlow深度学习】LeNet-5卷积神经网络实战分析
  • 【vuex入门系列02】mutation接收单个参数和多个参数
  • 2017 年终总结 —— 在路上
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • CODING 缺陷管理功能正式开始公测
  • Docker 1.12实践:Docker Service、Stack与分布式应用捆绑包
  • github从入门到放弃(1)
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • iOS小技巧之UIImagePickerController实现头像选择
  • Javascript 原型链
  • Java知识点总结(JavaIO-打印流)
  • Python语法速览与机器学习开发环境搭建
  • tensorflow学习笔记3——MNIST应用篇
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • 前端代码风格自动化系列(二)之Commitlint
  • 如何设计一个微型分布式架构?
  • 如何邀请好友注册您的网站(模拟百度网盘)
  • 深入浅出Node.js
  • 什么软件可以提取视频中的音频制作成手机铃声
  • 数组大概知多少
  • 微信小程序设置上一页数据
  • k8s使用glusterfs实现动态持久化存储
  • MyCAT水平分库
  • Spring第一个helloWorld
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结
  • #ifdef 的技巧用法
  • #QT(一种朴素的计算器实现方法)
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (2)STL算法之元素计数
  • (ZT)薛涌:谈贫说富
  • (二)windows配置JDK环境
  • (个人笔记质量不佳)SQL 左连接、右连接、内连接的区别
  • (转)使用VMware vSphere标准交换机设置网络连接
  • .bat批处理(三):变量声明、设置、拼接、截取
  • .Net 中Partitioner static与dynamic的性能对比
  • .Net(C#)自定义WinForm控件之小结篇
  • .NET简谈设计模式之(单件模式)
  • .pyc文件是什么?
  • /deep/和 >>>以及 ::v-deep 三者的区别