一、kubernetes安全机制
api server是k8s集群的入口,默认有两个端口:
本地端口8080: 用于接收HTTP请求, 不对外服务, 非认证或授权的HTTP请求通过该端口访问API Server
安全端口6443: 用于接收认证授权的HTTPS请求,对外服务。
用户通过安全端口访问k8s的api server需要过三关:认证、授权、准入控制
- Authentication认证: 用于识别用户身份, 方式有: SSL证书,token, 用户名+密码等
- Authorization授权: 确认是否对资源具有相关的权限
- Admission Control准入控制: 判断操作是否符合集群的要求
无论kubectl客户端命令或api或ui,在创建或访问资源时,一定要有apiServer所对应的资源版本,只要资源版本与kind能够正确匹配才能进行继续操作,否侧操作会被终止。
Authentication认证
Authentication认证: 用于识别用户身份, 验证方式有:
SSL证书
token
用户名+密码
用户分类
用户有两种:
用户账户(user) : 是在集群外部访问apiserver时使用的用户,如kubectl命令就是作为kubernetes的admin用户来执行的。
服务账户(ServiceAccount): 为了方便Pod里面的进程调用
Kubernetes API或其他外部服务而设计的。
User account是为人设计的,而service account则是为Pod中的进程调用Kubernetes API而设计;
User account是跨namespace的,而service account则是仅局限它所在的namespace;
每个namespace都会自动创建一个default service account
参考: https://www.kubernetes.org.cn/service-account
kubeconfig文件
- kubeconfig文件用于组织有关群集、用户、命名空间和身份验证机制的信息,用于对k8s集群的访问。
- 使用kubectl命令时默认使用
~/.kube/config
这个kubeconfig文件来访问k8s集群,也可以用--kubeconfig
指定其它文件
一个kubeconfig文件通常由以下几个配置段组成:
users: 用户账号及其认证信息列表
cluster: 目标集群列表
contexts: 以哪个user接入哪个cluster的连接组合。
current-context:当前使用的context
示例: 查看admin用户的kubeconfig文件
cat /root/.kube/config
Authorization授权
认证环节之后是授权, 确认是否对资源具有相关的权限
一个请求需要在其请求信息中包含用户名,请求的动作以及目标对象; 若存在某授权策略对于此请求给予了授权许可,即授权成功。
授权模块
Node: 根据Pod对象调度的结果为Node进行授权。
ABAC(Attribute-based access control): 基于属性的访问控制(ABAC)定义了一种访问控制模式,通过使用将属性组合在一起的策略,将访问权限授予用户。这些策略可以使用任何类型的属性(用户属性、资源属性、对象、环境属性等)。
RBAC(Role-based access control): 基于角色的访问控制(RBAC)是一种基于企业中各个用户的角色来管理对计算机或网络资源的访问的方法。使用"rbac.authorization.k8s.io" API驱动授权策略,并支持动态配置。
Webhook: WebHook其实就是一个HTTP回调:在发生某些事情时发生的HTTP POST;通过HTTP POST的简单事件通知。实现WebHooks的web应用程序将在发生某些事情时向URL发送消息。
RBAC
- 角色
- Role 授权特定命名空间的访问权限
- ClusterRole 授权所有命名空间的访问权限
- 角色绑定
- RoleBinding 将角色绑定到主机(即subject)
- ClusterRoleBinding 将集群角色绑定到主体
- 主体 (subject)
- User 用户
- Group 用户组
- ServiceAccount 服务帐号
Admission Control准入控制
通过认证和鉴权之后,客户端并不能得到API Server的真正响应,这个请求还需通过Admission Control所控制的一个准入控制插件列表的层层考验。
准入控制器
Admission Control配备有一个“准入控制器”的插件列表,发送给API Server的任何请求都需要通过列表中每一个准入控制器的检查,检查不通过API Server拒绝此调用请求。
此外,准入控制器还能够修改请求参数以完成一些自动化的任务,比如Service Account这个控制器。
当前可配置的Admission Control准入控制如下:
- AlwaysAdmit:允许所有请求;
- AlwaysPullmages:在启动容器之前总去下载镜像,相当于在每个容器的配置项imagePullPolicy=Always
- AlwaysDeny:禁止所有请求,一般用于测试;
- DenyExecOnPrivileged:它会拦截所有想在Privileged Container上执行命令的请求,如果你的集群支持Privileged Container,你又希望限制用户在这些Privileged Container上执行命令,强烈推荐你使用它,其功能已经合并到DenyEscalatingExec中。
- ImagePolicyWebhook:这个插件将允许后端的一个Webhook程序来完成admission controller的功能。ImagePolicyWebhook需要使用一个配置文件(通过kube-apiserver的启动参数--admission-control-config-file设置)定义后端Webhook的参数。目前该插件还处在Alpha版本。
- Service Account:这个plug-in将ServiceAccount实现了自动化,默认启用,如果你想使用ServiceAccount对象,那么强烈推荐使用它。
- SecurityContextDeny:这个插件将使用SecurityContext的Pod中的定义全部失效。SecurityContext在Container中定义了操作系统级别的安全设定(uid,gid,capabilityes,SELinux等)。在未启用PodSecurityPolicy的集群中建议启用该插件,以禁用容器设置的非安全访问权限。
- ResourceQuota:用于资源配额管理目的,作用于namespace上,它会观察所有请求,确保在namespace上的配额不会超标。推荐在Admission Control参数列表中将这个插件安排在最后一个,以免可能被其他插件拒绝的Pod被过早分配资源。
- LimitRanger:用于资源限制管理,作用于namespace上,确保对Pod进行资源限制。启用该插件还会为未设置资源限制的Pod进行默认设置,例如为namespace "default"中所有的Pod设置0.1CPU的资源请求。
- InitialResources:是一个实验特性,旨在为未设置资源请求与限制的Pod,根据其镜像的历史资源的使用情况进行初始化的资源请求、限制设置。
- NamespaceLifecycle:如果尝试在一个不存在的namespace中创建资源对象,则该创建请求将被拒绝。当删除一个namespace时,系统将会删除该namespace中所有对象,保存Pod,Service等。
- DefaultStorageClass:为了实现共享存储的动态供应,为未指定StorageClass或PV的PVC尝试匹配默认的StorageClass,尽可能减少用户在申请PVC时所需了解的后端存储细节。
- DefaultTolerationSeconds:这个插件为那些没有设置forgiveness tolerations并具有notready:NoExecute和unreachable:NoExecute两种taints的Pod设置默认的“容忍”时间,为5min。
- PodSecurityPolicy:这个插件用于在创建或修改Pod时决定是否根据Pod的security context和可用的PodSecurityPolicy对Pod的安全策略进行控制。
LimitRanger示例
kubectl create ns limitrange
kubectl describe ns limitrange
看到无LimitRange
vim limitrange.yml
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-limit-range
namespace: limitrange
spec:
limits:
- default:
cpu: 1000m
defaultRequest:
cpu: 1000m
min:
cpu: 500m
max:
cpu: 2000m
maxLimitRequestRatio:
cpu: 4
type: Container
kubectl apply -f limitrange.yml
kubectl describe ns limitrange
vim limitrange-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: limitrange
spec:
containers:
- name: c1
image: nginx:1.15-alpine
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: 200m # cpu请求200m,小于namespace的cpu最小限制(500m)
kubectl apply -f limitrange-pod.yml
说明: 可看到namespace的cpu最小限制是500m,创建此pod请求为200m,准入控制拒绝了。 改成限制范围内就可以创建
vim limitrange-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: limitrange
spec:
containers:
- name: c1
image: nginx:1.15-alpine
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: 600m # 改成大于500m
kubectl apply -f limitrange-pod.yml
kubectl get pods -n limitrange
可以成功创建pod
ResourceQuota示例
vim resourcequota.yml
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota
namespace: limitrange
spec:
hard: # 硬限制
pods: "1" # 限制此namespace里就不能超过1个pod
kubectl apply -f resourcequota.yml
kubectl describe ns limitrange
硬限制为1个pod,已经有1个pod了
vim resourcequota-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx2 # 改一个pod名
namespace: limitrange # 相同的namespace
spec:
containers:
- name: c1
image: nginx:1.15-alpine
imagePullPolicy: IfNotPresent
kubectl apply -f resourcequota-pod.yml
报错,pod数量超过了
二、User访问案例
参考资料 https://kubernetes.io/docs/reference/access-authn-authz/rbac/
创建k8s用户(User)
1, 准备工作
mkdir rbac
cd rbac/
cp /etc/kubernetes/ssl/ca-key.pem .
cp /etc/kubernetes/ssl/ca.pem .
2, 创建证书
openssl genrsa -out daniel.key 2048 #创建user私钥
3.创建证书签署请求
(subj中的CN为用户名,O为用户组)
openssl req -new -key daniel.key -out daniel.csr -subj "/O=k8s/CN=daniel"
签署证书
openssl x509 -req -in daniel.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out daniel.crt -days 365
[root@master1 rbac]# ls
3,创建用户配置文件
vim create-rbac-user.sh #过程复杂,直接用脚本
#设置集群连接
kubectl config set-cluster kubernetes \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://192.168.154.135:6443 \
--kubeconfig=daniel-kubeconfig
#颁发证书
kubectl config set-credentials daniel \
--client-key=daniel.key \
--client-certificate=daniel.crt \
--embed-certs=true \
--kubeconfig=daniel-kubeconfig
#设置安全上下文
kubectl config set-context daniel@kubernetes \
--cluster=kubernetes \
--user=daniel \
--kubeconfig=daniel-kubeconfig
#切换安全上下文
kubectl config use-context daniel@kubernetes --kubeconfig=daniel-kubeconfig
#查看安全上下文
kubectl config view --kubeconfig=daniel-kubeconfig
执行脚本
chmod +x create-rbac-user.sh
sh create-rbac-user.sh
查看kubeconfig文件
[root@master1 ~]# cat /root/rbac/daniel-kubeconfig
创建系统用户
useradd daniel
mkdir -p /home/daniel/.kube
cp /root/rbac/daniel-kubeconfig /home/daniel/.kube/config
chown daniel.daniel -R /home/daniel/
su - daniel
说明: 切换登录用户时, 就使用了/home/daniel/.kube/config文件。
验证用户访问k8s资源
可以看到daniel用户对pod,svc,ns等资源都没有权限
[daniel@master1 ~]$ kubectl get pod
[daniel@master1 ~]$ kubectl get svc
[daniel@master1 ~]$ kubectl get ns
创建role
vim role-pods-read.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role-pods-reader
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
说明: 此role是表示对pods资源有读的相关权限(get,list,watch)
kubectl apply -f role-pods-read.yaml
kubectl get role |grep role-pods-reader
创建rolebinding
vim rolebinding-pods-read.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: rolebinding-pods-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: role-pods-reader # 对应上一步的role名
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: daniel # 与前面创建的k8s用户一致
kubectl apply -f rolebinding-pods-read.yml
kubectl get rolebinding |grep rolebinding-pods-reader
说明: 这样系统用户daniel
与k8s用户daniel
通过这个rolebinding
将role
里定义的权限都联系起来了
再验证用户访问k8s资源
[root@master1 rbac]# su - daniel
[daniel@master1 ~]$ kubectl get pods
[daniel@master1 ~]$ kubectl get pods -n kube-system
[daniel@master1 ~]$ kubectl get svc
[daniel@master1 ~]$ kubectl get ns
说明: 由上可知,daniel 用户终于可以访问 default 命名空间里的pods资源了,但其它的还没有权限访问
创建ClusterRole
vim clusterrole-pods-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: clusterrole-pods-reader
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
kubectl apply -f clusterrole-pods-reader.yaml
kubectl get clusterrole |grep pods-reader
创建ClusterRoleBinding
vim clusterrolebinding-pods-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: clusterrolebinding-pods-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: clusterrole-pods-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: daniel
kubectl apply -f clusterrolebinding-pods-reader.yaml
kubectl get clusterrolebinding |grep pods-reader
再验证用户访问k8s资源
[root@master1 rbac]# su - daniel
[daniel@master1 ~]$ kubectl get pod --all-namespaces
现在所有命名空间的pods都可以访问了
问题: 访问svc等其它资源如何操作?
参考查看admin这个clusterrole
kubectl get clusterrole admin -o yaml
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.authorization.k8s.io/aggregate-to-admin: "true"
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
creationTimestamp: "2021-05-28T15:17:10Z"
labels:
kubernetes.io/bootstrapping: rbac-defaults
managedFields:
- apiVersion: rbac.authorization.k8s.io/v1
fieldsType: FieldsV1
fieldsV1:
f:aggregationRule:
.: {}
f:clusterRoleSelectors: {}
f:metadata:
f:annotations:
.: {}
f:rbac.authorization.kubernetes.io/autoupdate: {}
f:labels:
.: {}
f:kubernetes.io/bootstrapping: {}
manager: kube-apiserver
operation: Update
time: "2021-05-28T15:17:10Z"
- apiVersion: rbac.authorization.k8s.io/v1
fieldsType: FieldsV1
fieldsV1:
f:rules: {}
manager: kube-controller-manager
operation: Update
time: "2021-05-28T15:17:24Z"
name: admin
resourceVersion: "212"
selfLink: /apis/rbac.authorization.k8s.io/v1/clusterroles/admin
uid: 2068aaa4-36d6-4294-959a-63b9c6a8cc3c
rules:
- apiGroups:
- ""
resources:
- pods/attach
- pods/exec
- pods/portforward
- pods/proxy
- secrets
- services/proxy
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- impersonate
- apiGroups:
- ""
resources:
- pods
- pods/attach
- pods/exec
- pods/portforward
- pods/proxy
verbs:
- create
- delete
- deletecollection
- patch
- update
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- persistentvolumeclaims
- replicationcontrollers
- replicationcontrollers/scale
- secrets
- serviceaccounts
- services
- services/proxy
verbs:
- create
- delete
- deletecollection
- patch
- update
- apiGroups:
- apps
resources:
- daemonsets
- deployments
- deployments/rollback
- deployments/scale
- replicasets
- replicasets/scale
- statefulsets
- statefulsets/scale
verbs:
- create
- delete
- deletecollection
- patch
- update
- apiGroups:
- autoscaling
resources:
- horizontalpodautoscalers
verbs:
- create
- delete
- deletecollection
- patch
- update
- apiGroups:
- batch
resources:
- cronjobs
- jobs
verbs:
- create
- delete
- deletecollection
- patch
- update
- apiGroups:
- extensions
resources:
- daemonsets
- deployments
- deployments/rollback
- deployments/scale
- ingresses
- networkpolicies
- replicasets
- replicasets/scale
- replicationcontrollers/scale
verbs:
- create
- delete
- deletecollection
- patch
- update
- apiGroups:
- policy
resources:
- poddisruptionbudgets
verbs:
- create
- delete
- deletecollection
- patch
- update
- apiGroups:
- networking.k8s.io
resources:
- ingresses
- networkpolicies
verbs:
- create
- delete
- deletecollection
- patch
- update
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- persistentvolumeclaims
- persistentvolumeclaims/status
- pods
- replicationcontrollers
- replicationcontrollers/scale
- serviceaccounts
- services
- services/status
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- bindings
- events
- limitranges
- namespaces/status
- pods/log
- pods/status
- replicationcontrollers/status
- resourcequotas
- resourcequotas/status
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- list
- watch
- apiGroups:
- apps
resources:
- controllerrevisions
- daemonsets
- daemonsets/status
- deployments
- deployments/scale
- deployments/status
- replicasets
- replicasets/scale
- replicasets/status
- statefulsets
- statefulsets/scale
- statefulsets/status
verbs:
- get
- list
- watch
- apiGroups:
- autoscaling
resources:
- horizontalpodautoscalers
- horizontalpodautoscalers/status
verbs:
- get
- list
- watch
- apiGroups:
- batch
resources:
- cronjobs
- cronjobs/status
- jobs
- jobs/status
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- daemonsets
- daemonsets/status
- deployments
- deployments/scale
- deployments/status
- ingresses
- ingresses/status
- networkpolicies
- replicasets
- replicasets/scale
- replicasets/status
- replicationcontrollers/scale
verbs:
- get
- list
- watch
- apiGroups:
- policy
resources:
- poddisruptionbudgets
- poddisruptionbudgets/status
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
- ingresses/status
- networkpolicies
verbs:
- get
- list
- watch
- apiGroups:
- authorization.k8s.io
resources:
- localsubjectacce***eviews
verbs:
- create
- apiGroups:
- rbac.authorization.k8s.io
resources:
- rolebindings
- roles
verbs:
- create
- delete
- deletecollection
- get
- list
- patch
- update
- watch
三、ServiceAccount访问案例
创建namespace
kubectl create namespace sa
验证namespace的sa与secret
创建namespace默认会创建一个serviceaccount和一个secret
kubectl get sa -n sa
kubectl get secret -n sa
kubectl describe sa default -n sa
kubectl describe secret default-token-gcbbc -n sa
创建pod验证其sa与secret
kubectl run nginx --image=nginx:1.15-alpine -n sa
kubectl describe pod nginx -n sa
说明: 创建pod不指定serviceaccount则默认使用default.
创建一个sa
kubectl create sa daniel -n sa
kubectl get sa -n sa
kubectl get secret -n sa
创建pod并自定义sa
vim sa-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx2
namespace: sa
spec:
containers:
- name: c1
image: nginx:1.15-alpine
ports:
- name: httpd
containerPort: 80
serviceAccountName: daniel # 指定sa为daniel
验证pod使用的sa
kubectl apply -f sa-pod.yml
kubectl describe pod nginx2 -n sa