一、k8s安全管理:认证、授权、准入控制概述
k8s对我们整个系统的认证,授权,访问控制做了精密的设置;对于k8s集群来说,apiserver是整个集群访问控制的唯一入口,我们在k8s集群之上部署应用程序的时候,也可以通过宿主机的NodePort暴露的端口访问里面的程序,用户访问kubernetes集群需要经历如下认证过程:
认证->授权->准入控制(admination controller)
1.认证(Authenticating)是对客户端的认证,通俗点就是用户名密码验证
2.授权(Authorization)是对资源的授权,k8s中的资源无非是容器,最终其实就是容器的计算,网络,存储资源,当一个请求经过认证后,需要访问某一个资源(比如创建一个pod),授权检查会根据授权规则判定该资源(比如某namespace下的pod)是否是该客户可访问的。
3.准入(Admission Control)机制:
准入控制器(Admission Controller)位于 API Server中,在对象被持久化之前,准入控制器拦截对 API Server 的请求,一般用来做身份验证和授权。其中包含两个特殊的控制器:
Mutating Admission Webhook 和 Validating Admission Webhook。分别作为配置的变更和验证准入控制 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认证(TLS):
对于k8s访问来讲,ssl认证能让客户端确认服务器的认证身份,我们在跟服务器通信的时候,需要服务器发过来一个证书,我们需要确认这个证书是不是ca签署的,如果是我们认可的ca签署的,里面的subj信息与我们访问的目标主机信息保持一致,没有问题,那么我们就认为服务器的身份得到认证了,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
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之间进行通信的账号,如下:
root@k8s-master01 \~\]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-pod-volume 1/1 Running 0 43m
nfs-provisioner-cd5589cfc-c8vc5 1/1 Running 0 13h
pod-secret 1/1 Running 0 18m
web-0 1/1 Running 0 13h
web-1 1/1 Running 0 13h
\[root@k8s-master01 \~\]# kubectl get pods web-0 -o yaml \| grep "serviceAccountName"
serviceAccountName: default
\[root@k8s-master01 \~\]# kubectl get sa
NAME SECRETS AGE
default 0 12d
默认的service account 仅仅只能获取当前Pod自身的相关属性,无法观察到其他名称空间Pod的相关属性信息。
创建一个serviceaccount:
\[root@k8s-master \~\]# kubectl create serviceaccount test
\[root@k8s-master \~\]# kubectl describe sa test #查看test这个账号的详细信息
\[root@k8s-master \~\]# kubectl describe sa test
Name: test
Namespace: default
Labels: \
resources: ["pods"]
resourceNames: []
verbs: ["get","watch","list"]
rules中的参数说明:
* apiGroups:支持的API组列表,例如:"apiVersion: batch/v1"等
* resources:支持的资源对象列表,例如pods、deplayments、jobs等
* resourceNames: 指定resource的名称
* verbs:对资源对象的操作方法列表。
3.2 ClusterRole:集群角色
具有和角色一致的命名空间资源的管理能力,还可用于以下特殊元素的授权
* 集群范围的资源,例如Node
* 非资源型的路径,例如:/healthz
* 包含全部命名空间的资源,例如Pods
例如:定义一个集群角色可让用户访问任意secrets
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secrets-clusterrole
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get","watch","list"]
3.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-bind
namespace: rbac
subjects:
- kind: User
name: es
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-read
apiGroup: rbac.authorization.k8s.io
RoleBinding也可以引用ClusterRole,对属于同一命名空间内的ClusterRole定义的资源主体进行授权, 例如:es能获取到集群中所有的资源信息
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: es-allresource
namespace: rbac
subjects:
- kind: User
name: es
apiGroup: rbac.authorization.k8s.io
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
集群角色绑定的角色只能是集群角色,用于进行集群级别或对所有命名空间都生效的授权
例如:允许manager组的用户读取所有namaspace的secrets
apiVersion: rabc.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-secret-global
subjects:
- kind: Group
name: manager
apiGroup: rabc.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-read
apiGroup: rabc.authorization.k8s.io
四、资源的引用方式
多数资源可以用其名称的字符串表示,也就是Endpoint中的URL相对路径,例如pod中的日志是GET /api/v1/namaspaces/{namespace}/pods/{podname}/log
如果需要在一个RBAC对象中体现上下级资源,就需要使用"/"分割资源和下级资源。
例如:若想授权让某个主体同时能够读取Pod和Pod log,则可以配置 resources为一个数组
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: logs-reader
namespace: default
rules:
- apiGroups: [""]
resources: ["pods","pods/log"]
verbs: ["get","list"]
资源还可以通过名称(ResourceName)进行引用,在指定ResourceName后,使用get、delete、update、patch请求,就会被限制在这个资源实例范围内。
例如,下面的声明让一个主体只能对名为my-configmap的Configmap进行get和update操作:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: configmap-update
rules:
- apiGroups: [""]
resources: ["configmap"]
resourceNames: ["my-configmap"]
verbs: ["get","update"]
查看资源信息的命令:
root@k8s-master01 \~\]# kubectl api-resources 五、常见角色示例 (1)允许读取核心API组的Pod资源 rules: - apiGroups: \[""
resources: ["pods"]
verbs: ["get","list","watch"]
(2)允许读写extensions和apps两个API组中的deployment资源
rules:
- apiGroups: ["extensions","apps"]
resources: ["deployments"]
verbs: ["get","list","watch","create","update","patch","delete"]
(3)允许读取Pod以及读写job信息
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]、
- apiGroups: ["batch","extensions"]
resources: ["jobs"]
verbs: ["get","list","watch","create","update","patch","delete"]
(4)允许读取一个名为my-config的ConfigMap(必须绑定到一个RoleBinding来限制到一个Namespace下的ConfigMap):
rules:
apiGroups: [""]
resources: ["configmap"]
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"]
六、常见的角色绑定示例
(1)用户名alice
subjects:
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io
(2)组名alice
subjects:
- kind: Group
name: alice
apiGroup: rbac.authorization.k8s.io
(3)kube-system命名空间中默认Service Account
subjects:
kind: ServiceAccount
name: default
namespace: kube-system
(4)qa命名空间中的所有Service Account:
subjects:
kind: Group
name: system:serviceaccounts:qa
apiGroup: rbac.authorization.k8s.io
(5)所有Service Account
subjects:
kind: Group
name: system:serviceaccounts
apiGroup: rbac.authorization.k8s.io
(6)所有认证用户
subjects:
kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
(7)所有未认证用户
subjects:
kind: Group
name: system:unauthenticated
apiGroup: rbac.authorization.k8s.io
(8)全部用户
subjects:
kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:unauthenticated
apiGroup: rbac.authorization.k8s.io
七、对Service Account的授权管理
pod内可获取rbac命名空间的所有Pod资源,pod-reader-sc的Service Account是绑定了名为pod-read的Role。
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: rbac
spec:
serviceAccountName: pod-reader-sc
containers:
name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
containerPort: 80
默认的RBAC策略为控制平台组件、节点和控制器授予有限范围的权限,但是除kube-system外的Service Account是没有任何权限的。
(1)为一个应用专属的Service Account赋权
此应用需要在Pod的spec中指定一个serviceAccountName,用于API、Application Manifest、kubectl create serviceaccount等创建Service Account的命令。
例如为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
另外,许多系统级Add-Ons都需要在kube-system命名空间中运行,要让这些Add-Ons能够使用超级用户权限,则可以把cluster-admin权限赋予kube-system命名空间中名为default的Service Account,这一操作意味着kube-system命名空间包含了通向API超级用户的捷径。
kubectl create clusterrolebinding add-ons-add-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default
(3)为命名空间中所有Service Account都授予一个角色
如果希望在一个命名空间中,任何Service Account应用都具有一个角色,则可以为这一命名空间的Service Account群组进行授权
kubectl create rolebinding serviceaccounts-view --clusterrole=view --group=system:serviceaccounts:my-namespace --namespace=my-namespace
(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
八、使用kubectl命令行工具创建资源对象
(1)在命名空间rbac中为用户es授权admin ClusterRole:
kubectl create rolebinding bob-admin-binding --clusterrole=admin --user=es --namespace=rbac
(2)在命名空间rbac中为名为myapp的Service Account授予view ClusterRole:
kubctl create rolebinding myapp-role-binding --clusterrole=view --serviceaccount=rbac:myapp --namespace=rbac
(3)在全集群范围内为用户root授予cluster-admin ClusterRole:
kubectl create clusterrolebinding cluster-binding --clusterrole=cluster-admin --user=root
(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/
九、限制不同的用户操作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)生成一个证书
openssl x509 -req -in lucky.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out lucky.crt -days 3650
在kubeconfig下新增加一个lucky这个用户
(1)把lucky这个用户添加到kubernetes集群中,可以用来认证apiserver的连接
root@xianchaomaster1 pki\]# kubectl config set-credentials lucky --client-certificate=./lucky.crt --client-key=./lucky.key --embed-certs=true
(2)在kubeconfig下新增加一个lucky这个账号
kubectl config set-context lucky@kubernetes --cluster=kubernetes --user=lucky
(3)切换账号到lucky,默认没有任何权限
\[root@k8s-master01 pki\]# kubectl config use-context lucky@kubernetes
\[root@k8s-master01 pki\]# kubectl get pod
Error from server (Forbidden): pods is forbidden: User "lucky" cannot list resource "pods" in API group "" in the namespace "default"
###切换到有权限的管理账户
\[root@k8s-master01 pki\]# kubectl config use-context kubernetes-admin@kubernetes
这个是集群用户,有任何权限;把lucky这个用户通过rolebinding绑定到clusterrole上,授予权限,权限只是在lucky这个名称空间有效
(1)把lucky这个用户通过rolebinding绑定到clusterrole上
\[root@k8s-master01 pki\]# kubectl create ns lucky
\[root@k8s-master01 pki\]# kubectl create rolebinding lucky -n lucky --clusterrole=cluster-admin --user=lucky
(2)切换到lucky这个用户
\[root@k8s-master01 pki\]# kubectl config use-context lucky@kubernetes
(3)测试是否有权限
kubectl get pods -n lucky
\[root@k8s-master01 pki\]# kubectl get pod -n lucky
No resources found in lucky namespace.
\[root@k8s-master01 pki\]# kubectl get sa -n lucky
NAME SECRETS AGE
default 0 2m10s
#有权限操作这个名称空间
kubectl get pods
\[root@k8s-master01 pki\]# kubectl get pod
Error from server (Forbidden): pods is forbidden: User "lucky" cannot list resource "pods" in API group "" in the namespace "default"
#没有权限操作其他名称空间
添加一个lucky的普通用户
useradd lucky
cp -ar /root/.kube/ /home/lucky/
chown -R lucky:lucky /home/lucky/
su - lucky
vim .kube/config
.......
server: https://192.168.158.15:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: lucky
name: lucky@kubernetes
current-context: lucky@kubernetes
....
su - root
chattr +i /home/lucky/.kube/config
exit
cat \<\
verbs: ["get", "list", "watch"]