API-Server作为Kubernetes网关,是访问和管理资源对象的唯一入口,其他各种集群组件访问资源都需要经过此网关才能进行正常访问和管理。每一次的访问请求都需要进行合法性的检验,其中包括身份验证、操作权限验证以及操作规范验证等,需要通过一系列验证通过之后才能使用api-server,api-server的数据全部存放在etcd当中。如下图:
认证Authentication
api-server有两个工作地址
-
一个用于K8S集群外的真实用户访问(宿主机网络)
K8S-master上的kube-apiserver服务(K8S-master的IP+6443端口) -
一个用于K8S集群内部pod中应用进行访问(pod网络,由service引入到pod网络中)
[root@k8s-master ~]# kubectl describe svc kubernetes Name: kubernetes Namespace: default Labels: component=apiserver provider=kubernetes Annotations: <none> Selector: <none> Type: ClusterIP IP: 10.96.0.1 Port: https 443/TCP TargetPort: 6443/TCP Endpoints: 192.168.80.146:6443 Session Affinity: None Events: <none>
用户认证 user account
用户访问api-server的方式:通常使用kubectl命令,或利用api-server的Request full接口。
kubectl命令的认证是使用~/.kube/config文件进行。
kubectl-proxy可以作为api-server的Request full接口的反向代理;向kubect-proxy访问无需认证,kubect-proxy向api-server的访问调用kubectl命令的文件进行认证。
config资源的定义格式
[root@k8s-master mainfests]# kubectl config view
apiVersion: v1
clusters: #集群列表
- cluster:
certificate-authority-data: REDACTED
server: https://192.168.56.11:6443
name: kubernetes
contexts: #上下文列表
- context: #定义哪个集群被哪个用户访问
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes #当前上下文
kind: Config
preferences: {}
users: #用户列表
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
config也是K8S的标准资源之一,在该配置文件当中定义了一个集群列表,指定的集群可以有多个;定义一个用户列表,用户也可以有多个,指明集群中的用户;而在上下文列表当中,是进行定义可以使用哪个用户对哪个集群进行访问,以及当前使用的上下文是什么。如图:定义了用户kubernetes-admin可以对kubernetes该集群的访问,用户kubernetes-user1对Clluster1集群的访问
修改config资源
增加新的用户认证
##第一步、生成一个新key文件magedu.key
[root@k8s-master ~]# cd /etc/kubernetes/pki
[root@k8s-master pki]# (umask 077;openssl genrsa -out magedu.key 2048)
Generating RSA private key, 2048 bit long modulus
............................................................................................+++
...................................................................................+++
e is 65537 (0x10001)
##第二步、创建证书生成请求magedu.csr
[root@k8s-master pki]# openssl req -new -key magedu.key -out magedu.csr -subj "/CN=magedu"
##第三步、利用私有CA对证书进行签署
[root@k8s-master pki]# openssl x509 -req -in magedu.csr -CA ./ca.crt -CAkey ./ca.key -CAcreateserial -out magedu.crt -days 365 #证书签署
Signature ok
subject=/CN=magedu
Getting CA Private Key
##第四部、往config中注册新用户magedu并制定使用的key文件和证书crt文件
[root@k8s-master pki]# kubectl config set-credentials magedu --client-certificate=./magedu.crt --client-key=./magedu.key --embed-certs=true
User "magedu" set.
##第五步、往config中注册新的上下文context
[root@k8s-master pki]# kubectl config set-context magedu@kubernetes --cluster=kubernetes --user=magedu
Context "magedu@kubernetes" created.
##第六步、修改config现在使用的context
[root@k8s-master pki]# kubectl config use-context magedu@kubernetes
Switched to context "magedu@kubernetes".
查看修改后的config,因magedu能通过认证但还未授权,所以不能执行任何操作,如下图:
内部Pod认证service account
Service account是为了方便Pod里面的应用调用Kubernetes API或其他外部服务而设计的。service account有以下特性:
-
User account是跨namespace的,而service account则是仅局限它所在的namespace
-
每个namespace都会自动创建一个default service account
-
每创建一个service account,K8S系统会为它们创建相应的secret
-
开启ServiceAccount Admission Controller后:
每个Pod在创建后都会自动设置spec.serviceAccount为所处namespace的default service account(除非指定了其他ServiceAccout) 验证Pod引用的service account已经存在,否则拒绝创建 如果Pod没有指定ImagePullSecrets,则把service account的ImagePullSecrets加到Pod中 每个container启动后都会挂载该service account的token和ca.crt到/var/run/secrets/kubernetes.io/serviceaccount/
而pod和apiserver之间进行通信的账号,称为serviceAccountName。如下:
##每个Pod在创建后都会自动设置spec.serviceAccount为所处namespace的default service account(除非指定了其他ServiceAccout)
[root@k8s-master ~]# kubectl get pods myapp-0 -o yaml| grep serviceAccountName -A 5 -B 5
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
subdomain: myapp-svc
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
[root@k8s-master ~]# kubectl get -n default sa
NAME SECRETS AGE
default 1 14d
##验证Token controller检测service account的创建,并为它们创建secret
[root@k8s-master ~]# kubectl describe -n default sa default
Name: default
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: default-token-cfgsk
Tokens: default-token-cfgsk
Events: <none>
[root@k8s-master ~]# kubectl get -n default secrets
NAME TYPE DATA AGE
default-token-cfgsk kubernetes.io/service-account-token 3 14d
service account中的secret最终会以挂载卷的形式被Pod挂载,从而让Pod中的应用能引用secret
[root@k8s-master ~]# kubectl describe pods myapp-0 | grep "Volumes:" -A 5
Volumes:
default-token-cfgsk:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-cfgsk
Optional: false
默认的service account 的权限都很低,只能获取当前Pod自身的相关属性。如果要创建一个管理型的Pod(dashboard),需要新建一个service account,并为新service account授予更多权限。
##新建一个service account并被用于一个新Pod
[root@k8s-master ~]# kubectl get secret
NAME TYPE DATA AGE
default-token-cfgsk kubernetes.io/service-account-token 3 15d
[root@k8s-master ~]# kubectl create serviceaccount admin
serviceaccount/admin created
[root@k8s-master ~]# kubectl get sa
NAME SECRETS AGE
admin 1 5s
default 1 15d
[root@k8s-master ~]# kubectl get secret ##自动为新serviceaccount创建secret
NAME TYPE DATA AGE
`admin-token-trqdn` kubernetes.io/service-account-token 3 8s
default-token-cfgsk kubernetes.io/service-account-token 3 15d
[root@k8s-master ~]# kubectl describe sa admin
Name: admin
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: `admin-token-trqdn`
Tokens: admin-token-trqdn
Events: <none>
##新建一个Pod并引用名为admin的serviceaccount
[root@k8s-master k8s-yaml]# vim ngx-pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod1
labels:
tier: frontend
spec:
containers:
- name: hello1
image: 192.168.80.146:5000/my_ngx:v2
serviceAccountName: admin
[root@k8s-master k8s-yaml]# kubectl apply -f ngx-pod1.yaml
pod/pod1 created
[root@k8s-master k8s-yaml]# kubectl describe pods pod1 | grep "Volumes" -A 5
Volumes:
admin-token-trqdn:
Type: Secret (a volume populated by a Secret)
SecretName: admin-token-trqdn
Optional: false
授权authorization
K8S的常用授权插件 RBAC
RBAC全称:Role Based Access Control,实现基于角色进行访问控制。
- 许可权限:对某些资源对象能进行的某些操作
- 角色:用户(user account 或service
account)绑定(扮演)某个角色,而角色绑定许可权限A,那么该用户就有权限A
角色和角色绑定分为,分为名称空间级别集群级别
- 名称空间级别:角色称Role 角色绑定称RoleBinding
- 集群级别:角色称ClusterRole 角色绑定称ClusterRoleBinding
一般情况使用Rolebinding绑定Role、使用ClusterRoleBinding绑定ClusterRole。也有特殊情况使用RoleBinding绑定ClusterRole。
当用户使用Rolebinding绑定ClusterRole,那么用户能获取clusterRole的权限,但权限范围被限制在当前所处名称空间内
此类特殊的Rolebinding绑定ClusterRole的使用场景:
用户对自己所处的名称空间拥有相同的权限,则使用使用Rolebinding绑定clusterRole可以更便捷的授权。不用每个名称空间都创建Role,然后再绑定。
Kubernetes RBAC的演示
user --> RoleBinding --> Role
一个Role对象只能对某一个名称空间中资源的有访问权限
1、创建Role
[root@k8s-master ~]# kubectl create role -h #查看角色创建帮助
[root@k8s-master ~]# kubectl create role pods-reader --verb=get,list,watch --resource=pods --dry-run -o yaml #干跑模式查看role的定义
apiVersion: rbac.authorization.k8s.io/v1
kind: Role #资源类型
metadata:
creationTimestamp: null
name: pods-reader
rules:
- apiGroups: #对那些api组内的资源进行操作
- ""
resources: #对那些资源定义
- pods
verbs: #操作权限定义
- get
- list
- watch
[root@k8s-master mainfests]# vim role-demo.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pods-reader
namespace: default
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
[root@k8s-master mainfests]# kubectl apply -f role-demo.yaml #角色创建
role.rbac.authorization.k8s.io/pods-reader created
[root@k8s-master mainfests]# kubectl get role
NAME AGE
pods-reader 3s
[root@k8s-master mainfests]# kubectl describe role pods-reader
Name: pods-reader
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"rbac.authorization.k8s.io/v1","kind":"Role","metadata":{"annotations":{},"name":"pods-reader","namespace":"default"},"rules":[{"apiGroup...
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get list watch] #此处已经定义了pods-reader这个角色对pods资源拥有get、list、watch的权限
2、进行角色绑定RoleBinding
RoleBinding可以把用户绑定在同一命名空间内定义的Role对象
[root@k8s-master ~]# kubectl create rolebinding -h #角色绑定创建帮助
[root@k8s-master mainfests]# kubectl create rolebinding magedu-read-pods --role=pods-reader --user=magedu --dry-run -o yaml #干跑获得yaml定义格式
[root@k8s-master mainfests]# vim rolebinding-demo.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
creationTimestamp: null
name: magedu-read-pods
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pods-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: magedu
[root@k8s-master mainfests]# kubectl apply -f rolebinding-demo.yaml #创建角色绑定
rolebinding.rbac.authorization.k8s.io/magedu-read-pods created
[root@k8s-master mainfests]# kubectl describe rolebinding magedu-read-pods #查看角色绑定的信息,这里可以看到user:magedu绑定到了pods-reader这个角色上
[root@k8s-master ~]# kubectl config use-context magedu@kubernetes #切换magedu这个用户,并使用get获取pods资源信息
Switched to context "magedu@kubernetes".
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
filebeat-ds-hxgdx 1/1 Running 1 36d
filebeat-ds-s466l 1/1 Running 2 36d
[root@k8s-master ~]# kubectl get pods -n ingress-nginx #测试获取ingress-nginx这个名称空间的pods信息
No resources found.
Error from server (Forbidden): pods is forbidden: User "magedu" cannot list pods in the namespace "ingress-nginx"
user --> ClusterRoleBinding --> ClusterRole
创建一个linux的新用户ik8s,并为他配置kubectl config(使用k8s的用户magedu)
[root@k8s-master ~]# useradd ik8s
[root@k8s-master ~]# cp -rp .kube/ /home/ik8s/
[root@k8s-master ~]# chown -R ik8s.ik8s /home/ik8s/
[root@k8s-master ~]# su - ik8s
[ik8s@k8s-master ~]$ kubectl config use-context magedu@kubernetes
Switched to context "magedu@kubernetes".
[ik8s@k8s-master ~]$ kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: REDACTED
server: https://192.168.56.11:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
- context:
cluster: kubernetes
user: magedu
name: magedu@kubernetes
current-context: magedu@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
- name: magedu
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
1、创建ClusterRole
一个ClusterRole对象能整个K8S任何资源都有访问权限
[root@k8s-master mainfests]# kubectl create clusterrole cluster-read --verb=get,list,watch --resource=pods -o yaml > clusterrole-demo.yaml
[root@k8s-master mainfests]# vim clusterrole-demo.yaml #定义clusterrole和权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-read
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
[root@k8s-master mainfests]# kubectl apply -f clusterrole-demo.yaml #创建clusterrole
clusterrole.rbac.authorization.k8s.io/cluster-read configured
2、进行角色绑定ClusterRoleBinding
ClusterRoleBinding可以把用户绑定在一个ClusterRole对象
[root@k8s-master mainfests]# kubectl create clusterrolebinding magedu-read-all-pods --clusterrole=cluster-read --user=magedu --dry-run -o yaml > clusterrolebinding-demo.yaml
[root@k8s-master mainfests]# vim clusterrolebinding-demo.yaml #创建角色绑定,将magedu绑定到clusterrole:magedu-read-all-pods上
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: magedu-read-all-pods
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-read
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: magedu
[root@k8s-master mainfests]# kubectl apply -f clusterrolebinding-demo.yaml
clusterrolebinding.rbac.authorization.k8s.io/magedu-read-all-pods created
[root@k8s-master mainfests]# kubectl get clusterrolebinding
NAME AGE
......
magedu-read-all-pods 10s
##切换到ik8s进行验证
[ik8s@k8s-master ~]$ kubectl get pods #角色绑定后在ik8s终端上进行获取pods信息,已经不会出现forbidden了
NAME READY STATUS RESTARTS AGE
filebeat-ds-hxgdx 1/1 Running 1 36d
filebeat-ds-s466l 1/1 Running 2 36d
myapp-0 1/1 Running 0 2d
myapp-1 1/1 Running 0 2d
myapp-2 1/1 Running 0 2d
myapp-3 1/1 Running 0 2d
pod-sa-demo 1/1 Running 0 1d
pod-vol-demo 2/2 Running 0 4d
redis-5b5d6fbbbd-q8ppz 1/1 Running 1 4d
[ik8s@k8s-master ~]$ kubectl get pods -n ingress-nginx #更换名称空间进行查看也是可行的
NAME READY STATUS RESTARTS AGE
default-http-backend-7db7c45b69-nqxw9 1/1 Running 1 4d
nginx-ingress-controller-6bd7c597cb-9fzbw 1/1 Running 0 4d
[ik8s@k8s-master ~]$ kubectl delete pods pod-sa-demo #但是进行删除pod就无法进行,因为在授权时是没有delete权限的
Error from server (Forbidden): pods "pod-sa-demo" is forbidden: User "magedu" cannot delete pods in the namespace "default"
User --> Rolebinding --> Clusterrole
将maedu通过rolebinding到集群角色magedu-read-pods当中,此时,magedu仅作用于当前名称空间的所有pods资源的权限
[root@k8s-master mainfests]# kubectl create rolebinding magedu-read-pods --clusterrole=cluster-read --user=magedu --dry-run -o yaml > rolebinding-clusterrole-demo.yaml
[root@k8s-master mainfests]# vim rolebinding-clusterrole-demo.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: magedu-read-pods
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-read
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: magedu
[root@k8s-master mainfests]# kubectl apply -f rolebinding-clusterrole-demo.yaml
rolebinding.rbac.authorization.k8s.io/magedu-read-pods created
[ik8s@k8s-master ~]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
filebeat-ds-hxgdx 1/1 Running 1 36d
filebeat-ds-s466l 1/1 Running 2 36d
myapp-0 1/1 Running 0 2d
myapp-1 1/1 Running 0 2d
myapp-2 1/1 Running 0 2d
myapp-3 1/1 Running 0 2d
pod-sa-demo 1/1 Running 0 1d
pod-vol-demo 2/2 Running 0 4d
redis-5b5d6fbbbd-q8ppz 1/1 Running 1 4d
[ik8s@k8s-master ~]$ kubectl get pods -n ingress-nginx
No resources found.
Error from server (Forbidden): pods is forbidden: User "magedu" cannot list pods in the namespace "ingress-nginx"