Kubernetes(k8s)集群安全机制之访问控制

Posted Tuki_a

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kubernetes(k8s)集群安全机制之访问控制相关的知识,希望对你有一定的参考价值。

访问控制流程

客户端如果想要访问和变更集群的资源,首先要识别客户端身份(Authentication),通过认证后对其进行授权(Authorization),最后根据准入控制对访问进行限制。

1、Authentication(认证):
认证方式现共有8种,可以启用一种或多种认证方式,只要有一种认证方式通过,就不再进行其它方式的认证。通常启用X509 Client Certs和Service Accout Tokens两种认证方式。

2、Authorization(授权):
必须经过认证阶段,才到授权请求,根据所有授权策略匹配请求资源属性,决定允许或拒绝请求。授权方式现共有6种,AlwaysDeny、AlwaysAllow、ABAC、RBAC、Webhook、Node。默认集群强制开启RBAC。

3、Admission Control(准入控制):
用于拦截请求的一种方式,运行在认证、授权之后,是权限认证链上的最后一环,对请求API资源对象进行修改和校验。

访问k8s的API Server的客户端

访问k8s的API Server的客户端主要分为两类:
1、kubectl:用户家目录中的 .kube/config 里面保存了客户端访问API Server的密钥相关信息,这样当用kubectl访问k8s时,它就会自动读取该配置文件,向API Server发起认证,然后完成操作请求。
2、pod:Pod中的进程需要访问API Server,如果是人去访问或编写的脚本去访问,这类访问使用的账号为:UserAccount;而Pod自身去连接API Server时,使用的账号是:ServiceAccount,生产中后者使用居多。

Kubernetes集群有两类用户:由Kubernetes管理的Service Accounts (服务账户)和(Users Accounts) 普通账户。k8s中账号的概念不是我们理解的账号,它并不真的存在,它只是形式上存在
如下图运行一个pod,看下他的用户是nginx,其实就是一个Service Accounts 服务账户。

UserAccount(用户账户)与serviceaccount(服务账户)区别:
用户账户是针对人而言的。 服务账户是针对运行在 pod 中的进程而言的
用户账户是全局性的。 其名称在集群各 namespace 中都是全局唯一的,未来的用户资源不会做 namespace 隔离, 服务账户是 namespace 隔离的
通常情况下,集群的用户账户可能会从企业数据库进行同步,其创建需要特殊权限,并且涉及到复杂的业务流程。 服务账户创建的目的是为了更轻量,允许集群用户为了具体的任务创建服务账户 ( 即权限最小化原则 )。

使用代理查看API信息

kubectl向apiserver发起的命令,采用的是http方式,其实就是对URL发起增删改查的操作
开启8888端口代理并打入后台,通过代理查看api群组下的相关信息

查看端口信息可以看到kube-proxy开放8888端口,也可以查看apis下的相关信息

fg调回前台关闭代理

以上两种api的区别是:
api它是一个特殊链接,只有在核心v1群组中的对象才能使用。
apis 它是一般API访问的入口固定格式名。

ServiceAccount

创建ServiceAccount账户

创建一个ServiceAccount账户admin,用下图命令可以查看详细信息,此时k8s为用户自动生成认证信息,但没有授权

给SA添加仓库认证

在我之前secret文章里写过一个仓库认证的文件,将给的认证那两行注释掉

vim registry.yaml

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: game2048
      image: reg.westos.org/test/game2048:latest	#镜像地址写那个不公开的项目下的镜像
  #imagePullSecrets:
    #- name: myregistrykey	#拉取镜像时用的secrets


重新应用文件,容器运行失败,因为指定的仓库项目不公开,没有拿到secrets无法拉取镜像

添加secrets到serviceaccount中:

kubectl patch serviceaccount admin -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'


在文件里加入下图内容,把serviceaccount和pod绑定起来

重新应用文件,镜像拉取成功。
将认证信息添加到serviceAccount中,要比直接在Pod指定imagePullSecrets要安全很多。

UserAccount

创建UserAccount账户

创建一个用户需要生成密钥并签名证书

cd /etc/kubernetes/pki/				#一定要进入这个目录创建
openssl genrsa -out test.key 2048	#生成2048位密钥
openssl req -new -key test.key -out test.csr -subj "/CN=test"	#生成证书签名请求文件
#CSR(Certificate Signing Request),即证书签名请求文件。
#CSR是证书申请者在申请数字证书时由CSP(加密服务提供者)在生成私钥的同时也生成证书请求文件,证书申请者只要把CSR文件提交给证书颁发机构后,证书颁发机构使用其根证书私钥签名就生成了证书公钥文件,也就是颁发给用户的证书。
openssl  x509 -req -in test.csr -CA ca.crt -CAkey ca.key  -CAcreateserial -out test.crt -days 365		#使用证书签名请求文件生成自签名证书,有效期为365天
openssl x509 -in test.crt -text -noout	#-in指定输入文件,-text以文本格式输出,-noout没证书输出,伪命令x509可以像openssl ca一样对证书或请求执行签名动作,这个命令就是查看证书信息。


可以看到已经生成了tast用户的证书、密钥等文件

往集群里导入test用户的相关信息,之后可以通过这些文件完成认证

kubectl config set-credentials test --client-certificate=/etc/kubernetes/pki/test.crt --client-key=/etc/kubernetes/pki/test.key --embed-certs=true


看下配置,可以看到k8s的管理员账户是属于kubernetes的

将test用户添加进用户列表

下图命令用户转换用户身份为test(默认是管理员账户)

如下图,因为我们没有对test用户进行授权,所以test用户什么都不能干,需要继续添加授权

RBAC(Role Based Access Control)授权

RBAC(Role Based Access Control):基于角色访问控制授权。
允许管理员通过Kubernetes API动态配置授权策略。RBAC就是用户通过角色与权限进行关联(即用户需要与角色进行绑定来得到权限)
RBAC只有授权,没有拒绝授权,所以只需要定义允许该用户做什么即可。
RBAC包括四种类型:Role、ClusterRole、RoleBinding、ClusterRoleBinding。

RBAC的三个基本概念

Subject:被作用者,它表示k8s中的三类主体, user, group, serviceAccount
Role:角色,它其实是一组规则,定义了一组对 Kubernetes API 对象的操作权限。
RoleBinding:定义了“被作用者”和“角色”的绑定关系。

Role 和 ClusterRole

Role是一系列的权限的集合,Role只能授予单个namespace 中资源的访问权限。

ClusterRole 跟 Role 类似,但是可以在集群中全局使用。
Kubernetes 还提供了四个预先定义好的 ClusterRole 来供用户直接使用:cluster-amdin、admin、edit、view

创建Role

先转换回管理员账户

创建一个目录,编写创建角色的定义文件

文件内容如下:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: myrole
rules:
- apiGroups: [""] 
  resources: ["pods"]		#权限作用对象
  verbs: ["get", "watch", "list", "create", "update", "patch", "delete"]		#具有的权限

应用文件,角色已被创建

RoleBinding

RoleBinding是将Role中定义的权限授予给用户或用户组。它包含一个subjects列表(users,groups ,service accounts),并引用该Role。

编写用户test与角色myrole绑定的定义文件,内容如下:

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: test-read-pods
  namespace: default
subjects:
- kind: User
  name: test
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: myrole
  apiGroup: rbac.authorization.k8s.io

应用文件,绑定成功

转换用户为test,查看pod成功(默认在default这个namespaces下),在其他namespaces查看失败

创建ClusterRole

先转换回管理员账户,再编写定义文件,内容如下:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: myclusterrole
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list", "delete", "create", "update"]
- apiGroups: ["extensions", "apps"]
  resources: ["deployments"]		#给了操作控制器的一些权限
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

应用文件,ClusterRole创建成功

ClusterRoleBinding

RoleBinding是对某个namespace 内授权,ClusterRoleBinding适用在集群范围内使用

在上面RoleBinding定义文件的基础上在最后加上如下内容:

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: rolebind-myclusterrole
  namespace:  default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: myclusterrole	#test与myclusterrole绑定
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: test	

应用文件绑定成功,换到test用户可以查看控制器

但因为没有给service的相关权限,不能对svc操作

切回admin用户重新修改文件,在最后加入如下内容

- apiGroups: [""]
  resources: ["services", "endpoints"]		#给了svc和后端节点的相关权限
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

重新应用文件

查看描述,是有service的相关权限的

切换到test用户查看svc成功

服务账户的自动化

1、服务账户准入控制器(Service account admission controller)
如果该 pod 没有 ServiceAccount 设置,将其 ServiceAccount 设为 default。
保证 pod 所关联的 ServiceAccount 存在,否则拒绝该 pod。
如果 pod 不包含 ImagePullSecrets 设置,那么 将 ServiceAccount 中的 ImagePullSecrets 信息添加到 pod 中。
将一个包含用于 API 访问的 token 的 volume 添加到 pod 中。
将挂载于 /var/run/secrets/kubernetes.io/serviceaccount 的 volumeSource 添加到 pod 下的每个容器中。

2、Token 控制器(Token controller)
检测服务账户的创建,并且创建相应的 Secret 以支持 API 访问。
检测服务账户的删除,并且删除所有相应的服务账户 Token Secret。
检测 Secret 的增加,保证相应的服务账户存在,如有需要,为 Secret 增加 token。
检测 Secret 的删除,如有需要,从相应的服务账户中移除引用。

3、服务账户控制器(Service account controller)
服务账户管理器管理各命名空间下的服务账户,并且保证每个活跃的命名空间下存在一个名为 “default” 的服务账户

用户组的概念

Kubernetes 还拥有“用户组”(Group)的概念:
ServiceAccount对应内置“用户”的名字是:system:serviceaccount:<ServiceAccount名字 >
而用户组所对应的内置名字是:system:serviceaccounts:<Namespace名字 >

示例1:表示mynamespace中的所有ServiceAccount

subjects:
- kind: Group
  name: system:serviceaccounts:mynamespace
  apiGroup: rbac.authorization.k8s.io

示例2:表示整个系统中的所有ServiceAccount

subjects:
- kind: Group
  name: system:serviceaccounts
  apiGroup: rbac.authorization.k8s.io

PSP(PodSecurityPolicy)

PodSecurityPolicy是集群级别的Pod安全策略,自动为集群中的Pod和Volume设置Security Context。
PodSecurityPolicy 自 Kubernetes v1.21 起已弃用,并将在 v1.25 中删除。
官方文档:https://kubernetes.io/docs/concepts/policy/pod-security-policy/

Pod 安全策略控制是作为可选的准入控制器实现的。PodSecurityPolicies 是通过启用准入控制器来强制执行的,但是在没有授权任何策略的情况下这样做会阻止在集群中创建任何 pod

由于 Pod 安全策略 API ( policy/v1beta1/podsecuritypolicy) 是独立于准入控制器启用的,对于现有集群,建议在启用准入控制器之前添加和授权策略。

开启PSP

先确保是管理员账户

管理员账户是有所有权限的

编辑文件开启psp

vim /etc/kubernetes/manifests/kube-apiserver.yaml

在下图位置加入PodSecurityPolicy,保存退出稍等一会即自动开启(想关闭psp也是在文件里删掉即可)

现在开启了psp,运行一个pod,会发现失败,因为我们没有定义任何授权策略,不允许创建任何pod

授权策略

使用官方的一个授权策略(RBAC是一种标准的 Kubernetes 授权模式,可以很容易地用于授权使用策略。一个Roleo或ClusterRole需要授予user对所需策略的访问权限。),内容如下:

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: example
spec:
  privileged: false  # Don't allow privileged pods!
  # The rest fills in some required fields.
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  runAsUser:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  volumes:
  - '*'

应用文件,因为策略允许所以现在可以创建pod!

以上是关于Kubernetes(k8s)集群安全机制之访问控制的主要内容,如果未能解决你的问题,请参考以下文章

第152天学习打卡(Kubernetes 集群安全机制)

十一,k8s集群访问控制之ServicAccount

干货 | K8S 1.6新增特性之RBAC

Kubernetes的安全机制

云原生之kubernetes实战在k8s集群下部署ingress对外访问服务

Kubernetes——对外服务之Ingress