k8s API Server提供了k8s各类资源对象(pod,RC,Service等)的增删改查及watch等HTTP Rest接口,是整个系统的数据总线和数据中心。
kubernetes API Server的功能:
1. 提供了集群管理的REST API接口(包括认证授权、数据校验以及集群状态变更);
2. 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd);
3. 提供准入控制的功能;
4. 拥有完备的集群安全机制.
集群功能模块之间的通信
kubernetes API Server作为集群的核心,负责集群各功能模块之间的通信,集群内各个功能模块通过API Server将信息存入etcd,当需要获取和操作这些数据时,通过API Server提供的REST接口(GET\LIST\WATCH方法)来实现,从而实现各模块之间的信息交互
每个Node节点上的kubelet定期就会调用API Server的REST接口报告自身状态,API Server接收这些信息后,将节点状态信息更新到etcd中。kubelet也通过API Server的Watch接口监听Pod信息,从而对Node机器上的POD进行管理。
kube-controller-manager中的Node Controller模块通过API Server提供的Watch接口,实时监控Node的信息,并做相应处理。他们通过API Server提供的接口实时监控整个集群里的每一个资源对象的当前状态,当发生各种故障导致系统状态发生变化,这些controller会尝试将系统从“现有装态”修正到“期望状态”。
Scheduler通过API Server的Watch接口监听到新建Pod副本的信息后,它会检索所有符合该Pod要求的Node列表,开始执行Pod调度逻辑。调度成功后将Pod绑定到目标节点上。
k8s通过kube-apiserver这个进程提供服务,该进程运行在单个k8s-master节点上。默认有两个端口
1.2.1 本地端口
该端口用于接收HTTP请求;
该端口默认值为8080,可以通过API Server的启动参数“--insecure-port”的值来修改默认值;
默认的IP地址为“localhost”,可以通过启动参数“--insecure-bind-address”的值来修改该IP地址;
非认证或授权的HTTP请求通过该端口访问API Server。
1.2.2 安全端口
该端口默认值为6443,可通过启动参数“--secure-port”的值来修改默认值;
默认IP地址为非本地(Non-Localhost)网络端口,通过启动参数“--bind-address”设置该值;
该端口用于接收HTTPS请求;
用于基于Tocken文件或客户端证书及HTTP Base的认证;
用于基于策略的授权;
默认不启动HTTPS安全访问控制。
1.2.3 kubectl客户端
命令行工具kubectl客户端,通过命令行参数转换为对API Server的REST API调用,并将调用结果输出。
命令格式:kubectl [command] [options]
1.2.4 Kubectl Proxy
Kubectl Proxy代理程序既能作为API Server的反向代理,也能作为普通客户端访问API Server的代理。通过master节点的8080端口来启动该代理程序。
本质上kubectl proxy为访问kubernetes apiserver的REST api充当反向代理角色,这里反向代理的作用与通常意义上的反向代理作用相同,比如提供统一入口进行访问控制、监控、管理,在代理中管理后端,在代理中进行认证等。当然可以不经过kubectl proxy反向代理直接访问kubernetes apiserver的REST api,但是需要手动管理kubernetes apiserver的地址、手动获取token、手动将token加请到请求的头部,相对来说要繁琐而已。
实验一:
kubectl proxy --port=8080 &
1.2.5 编程方式调用
使用场景:
官方支持的 Kubernetes 客户端库:
语言 |
客户端库 |
Go |
github.com/kubernetes/client-go/ |
Python |
github.com/kubernetes-client/python/ |
Java |
github.com/kubernetes-client/java |
dotnet |
github.com/kubernetes-client/csharp |
JavaScript |
github.com/kubernetes-client/javascript |
为了消除字段或重组资源表示形式,Kubernetes 支持多个 API 版本,每个版本在不同的 API 路径下。例如:/api/v1或者/apis/extensions/v1beta1。
版本是在 API 级别而非资源或字段级别配置的:
Alpha:
Beta:
稳定版:
API 组使扩展Kubernetes API更容易。API组在REST路径和序列化对象的 apiVersion 字段中指定。
当前,有几个正在使用的 API 组:
有两种途径来使用自定义资源扩展 API,分别是:
kubernetes的 Aggregated API是什么呢?它是允许k8s的开发人员编写一个自己的服务,可以把这个服务注册到k8s的api里面,这样,就像k8s自己的api一样,你的服务只要运行在k8s集群里面,k8s 的Aggregate通过service名称就可以转发到你写的service里面去了。
默认情况下,某些资源和 API 组处于启用状态。您可以通过设置--runtime-config来启用或禁用它们。
--runtime-config接受逗号分隔的值。例如:要禁用batch/v1,请配置--runtime-config=batch/v1=false;要启用batch/2alpha1,请配置--runtime-config=batch/v2alpha1。该标志接受描述apiserver的运行时配置的以逗号分隔的key=value对集合。
启用或禁用组或资源时,需要重新启动 apiserver 和控制器管理器以刷新--runtime-config的更改。
可以使用kubectl、客户端库方式对REST API的访问,Kubernetes的普通账户和Service帐户都可以实现授权访问API。API的请求会经过多个阶段的访问控制才会被接受处理,其中包含认证、授权以及准入控制(Admission Control)等。如下图所示:
需要注意:认证授权过程只存在HTTPS形式的API中。也就是说,如果客户端使用HTTP连接到kube-apiserver,是不会进行认证授权的。所以说,可以这么设置,在集群内部组件间通信使用HTTP,集群外部就使用HTTPS,这样既增加了安全性,也不至于太复杂。
开启TLS时,所有的请求首先需要认证。Kubernetes支持多种认证机制,并支持同时开启多个认证插件(只要有一个认证通过即可)。如果认证成功,则用户的username会传入授权模块做进一步授权验证;对于认证失败的请求则返回HTTP 401。
当TLS建立时,HTTP请求会进行身份认证步骤,如图中步骤1,集群管理器将apiserver配置为运行一个或多个认证器模块。
认证模块包含客户端证书,密码、Plain Tokens、Bootstrap Tokens、JWT Tokens(used for service accounts)。
我们可以指定多个认证模块,每个认证模块都会按顺序进行,直到其中一个成功。
3.1.1. kubernetes账户
所有Kubernetes集群有两类用户:由Kubernetes管理的Service Accounts (服务账户)和(Users Accounts) 普通账户。
普通账户是假定被外部或独立服务管理的,由管理员分配keys,用户像使用Keystone或google账号一样,被存储在包含usernames和passwords的list的文件里。
需要注意:在Kubernetes中不能通过API调用将普通用户添加到集群中。
Kubernetes只专注于做应用编排,其他的功能则提供接口集成,除了认证和授权,我们发现网络、存储也都如此。
这样做的好处也显而易见,用户账户信息与Kubernetes集群松耦合,便于集成企业已有的身份认证系统,如AD、LADP、Keycloak等。
相比之下,Service Accounts是由Kubernetes API管理的帐户。它们被绑定到特定的命名空间,并由APIserver自动创建或通过API调用手动创建。Service Accounts与存储为Secrets的一组证书相关联,这些凭据被挂载到pod中,以便集群进程与Kubernetes API通信。
3.1.2 静态密码认证
静态密码是最简单的认证方式,只需要在api-server启动时指定使用的密码本路径即可,通过配置-Basic-authfile=file选项实现,Basic认证凭证一直有效,并且如果没有重新启动API Server,密码将无法更改。
Basic Authentication文件csv也是格式文件,且必须包含:password, user, uid。在Kubernetes 1.6+版本中,可以指定一个可选的第四列,使用逗号来分隔group名,如果有多个组,必须使用双引号(“)。参考以下示例:
password,user,uid,"group1,group2,group3"
当从http客户端使用Basic Authentication时,API Server需要在请求头加入Basic BASE64ENCODED(USER:PASSWORD)。
通过静态密码的唯一优势是简单,其缺点也是非常明显:
这种方式在实际场景中很少被使用,不建议生产环境使用。
3.1.3 x509证书认证
对称加密和非对称加密
1. 对称加密
对称加密指的就是加密和解密使用同一个秘钥,所以叫做对称加密。对称加密只有一个秘钥,作为私钥。
常见的对称加密算法:DES,AES,3DES等等。
2. 非对称加密
非对称加密指的是:加密和解密使用不同的秘钥,一把作为公开的公钥,另一把作为私钥。公钥加密的信息,只有私钥才能解密。私钥加密的信息,只有公钥才能解密。
常见的非对称加密算法:RSA,ECC
3. 区别
对称加密算法相比非对称加密算法来说,加解密的效率要高得多。但是缺陷在于对于秘钥的管理上,以及在非安全信道中通讯时,密钥交换的安全性不能保障。所以在实际的网络环境中,会将两者混合使用.
双向TLS认证
双向认证则是需要服务端与客户端提供身份认证,只能是服务端允许的客户能去访问,安全性相对于要高一些。SSL单向认证只要求站点部署了ssl证书就行,任何用户都可以去访问(IP被限制除外等),只是服务端提供了身份认证。
使用API Server启动时配置–client-ca-file = SOMEFILE选项来启用客户端证书认证。引用的文件必须包含,提交给API Server的客户端证书的证书颁发机构。如果客户端提交的证书通过,通用名称(common name)将被用作请求的用户名。
x509认证是默认开启的认证方式,api-server启动时会指定ca证书以及ca私钥,只要是通过ca签发的客户端x509证书,则可认为是可信的客户端。
kubectl 如何认证? 获取$HOME/config
在kubectl config中会有两个证书,分别为certificate-authority证书和client-certificate证书。client-certificate用于客户端认证,这显而易见。
在使用client-certificate客户端证书认证时,CN(commom Name)对应Kubernetes的User,O(organization)对应Kubernetes的Group。
签发客户端证书有两种方式,一种是基于CA根证书签发证书,另一个种是发起CSR(Certificate Signing Requests)请求。
1) 使用CA根证书签发客户端证书
实验二:
openssl genrsa -out cat.key 2048
openssl req -new -key cat.key -out cat.csr -subj "/CN= cat "
openssl x509 -req -in cat.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out cat.crt -days 365 #基于CSR文件签发x509证书
kubectl config set-credentials cat --client-certificate= cat.crt --client-key= cat.key --embed-certs=true
kubectl config view
kubectl config set-context [email protected] --cluster=cluster.local --user=cat
kubectl config use-context [email protected]
2)通过CSR签发证书
前面通过CA签发证书需要有CA的私钥,其实Kubernetes可以直接发起CSR请求。
首先创建一个CSR请求,CN为test-csr,O为int32bit,即User为test-csr,Group为int32bbit。
openssl req -new -newkey rsa:4096 \
-nodes -keyout test-csr.key \
-out test-csr.csr -subj "/CN=test-csr/O=int32bit"
声明一个CSR Resource:
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
name: test-csr
spec:
groups:
- int32bit
request: ... #
这里填test-csr.csr内容并转化为base64
usages:
- client auth
创建该资源:
# kubectl apply -f test-csr.yaml
certificatesigningrequest.certificates.k8s.io/test-csr created
# kubectl get csr
NAME AGE REQUESTOR CONDITION
test-csr 4s kubernetes-admin Pending
此时CSR的状态为Pending,通过kubectl certificate approve命令签发证书:
# kubectl certificate approve test-csr
certificatesigningrequest.certificates.k8s.io/test-csr approved
# kubectl get csr
NAME AGE REQUESTOR CONDITION
test-csr 2m kubernetes-admin Approved,Issued
此时CSR显示已经完成签发,可以读取证书内容:
# kubectl get csr test-csr -o jsonpath='{.status.certificate}' | base64 -d
-----BEGIN CERTIFICATE-----
MIIEDTCCAvWgAwIBAgIUB9dVsj34xnQ8m5KUQwpdblWapNcwDQYJKoZIhvcNAQEL
...
yvfz8hcwrhQc6APpmZcBnil7iyzia3tnztQjoyaZ0cjC
-----END CERTIFICATE-----
查看证书部分摘要信息:
# kubectl get csr test-csr -o jsonpath='{.status.certificate}' \
| base64 -d \
| openssl x509 -noout \
-subject -issuer
subject=O = int32bit, CN = test-csr
issuer=CN = kubernetes
使用x509证书认证的问题
使用x509证书相对静态密码来说显然会更安全,只要证书不泄露,可以认为是无懈可击的。但是虽然颁发证书容易,目前却没有很好的方案注销证书。想想如果某个管理员离职,该如何回收他的权限和证书。有人说,证书轮转不就解决了吗?但这也意味着需要重新颁发其他所有证书,非常麻烦。
所以使用x509证书认证适用于Kubernetes内部组件之间认证,普通用户认证并不推荐通过证书的形式进行认证。
3.1.4 令牌认证
通过一个不记名令牌 (Bear Token) 来识别用户是一种相对安全又被各种客户端广泛支持的认证策略。不记名令牌,代表着对某种资源,以某种身份访问的权利,无论是谁,任何获取该令牌的访问者,都被认为具有了相应的身份和访问权限。配合成熟的令牌授予机构,不记名令牌非常适于在生产环境中严肃使用。身份令牌(ID Token)就是一种形式的不记名令牌,它本身记录着一个权威认证机构对用户身份的认证声明,同时还可以包含对这个用户授予了哪些权限的声明,像极了古代官员佩戴的腰牌。Kubernetes 接受和识别的正是这种 ID Token。
1)静态令牌认证
静态token认证和静态密码原理几乎完全一样,唯一不同的是静态token通过token-auth-file指定token文件,认证时头部格式为Authorization: Bearer ${Token},而静态密码通过basic-auth-file指定密码文件,认证头部为Basic base64encode(${username}:${password}),本质都是一样的。
因此其优点和缺点也和静态密码完全一样,这里不再赘述。
2)Bootstrap Token认证
前面提到的静态token在运行时是固定不变的,并且不会在Kubernetes集群中存储,意味着除非修改静态文件并重启服务,token不会改变。
而bootstrap token则是由Kubernetes动态生成的,通过Secret形式存储,并且具有一定的生命周期,一旦过期就会失效。
启用参数:--enable-bootstrap-token-auth=true
为了简便我们使用kubeadm生成一个token:
Kubeadm token create
Kubeadm token list
kubectl get clusterrolebinding | grep boot
kubectl get secret bootstrap-token-${TOKEN_ID} –n kube-system
过期的token会自动删除secret
Token有两个部分组成,由.分割,前面部分为Token ID,后面部分为Token Secret。Token默认TTL为一天,对应的group system:bootstrappers:kubeadm:default-node-token,对应User为system:bootstrap:${Token ID}。
kubeadm创建一个Token会对应在Kubernetes的kube-system namespace创建一个secret,secret名为bootstrap-token-${TOKEN_ID}。
授权: ClusterRoleBinding kubeadm:get-nodes
这种token主要用于临时授权使用,比如kubeadm初始化集群时会生成一个bootstrap token,这个token具有创建certificatesigningrequests权限,从而新Node能够发起CSR请求,请求客户端证书。
3) service account token认证
service account是Kubernetes唯一由自己管理的账号实体,意味着service account可以通过Kubernetes创建,不过这里的service account并不是直接和User关联的,service account是namespace作用域,而User是全cluster唯一。service account会对应一个虚拟User,User名为system:serviceaccount:${namespace}:${sa_name},比如在default namespace的test service account,则对应的虚拟User为system:serviceaccount:default:test。
和前面的bootstrap一样,service account也是使用Bearer Token认证的,不过和前面的Token不一样的是service account是基于JWT(JSON Web Token)认证机制,JWT原理和x509证书认证其实有点类似,都是通过CA根证书进行签名和校验,只是格式不一样而已,JWT由三个部分组成,每个部分由.分割,三个部分依次如下:
为了便于HTTP传输,JWT Token在传递过程中会转成Base64URL编码,其中Base64URL相对我们常用的Base64编码不同的是=被省略、+替换成-,/替换成_,这么做的原因是因为这些字符在URL里面有特殊含义,更多关于JWT的介绍可参考阮一峰的JSON Web Token 入门教程。
JWT Token的颁发机构为kubernetes/serviceaccount,颁发对象为SA对应的虚拟用户system:serviceaccount:default:test,除此之外还存储着其他的SA信息,如SA name、namespace、uuid等。这里需要注意的是我们发现JWT Token中没有exp字段,即意味着只要这个SA存在,这个Token就是永久有效的。
kubectl create sa {SA_NAME}
通过如下方式配置kubeconfig:
TOKEN_NAME=$(kubectl get serviceaccounts ${SA_NAME} -o jsonpath={.secrets[0].name})
TOKEN=$(kubectl get secret "${TOKEN_NAME}" -o jsonpath={.data.token} | base64 -d)
kubectl config set-credentials "${USERNAME}" --token="$TOKEN"
为了验证test-sa,在刚刚创建的int32bit-rolebinding的subjects增加了ServiceAccount test-sa。
Service account除了可以用于集群外认证外,其还有一个最大的特点是可以通过Pod.spec.serviceAccountName把token attach到Pod中。
此时Kubernetes会自动把SA的Token通过volume的形式挂载到/run/secrets/kubernetes.io/serviceaccount目录上,从而Pod可以读取token调用Kubernetes API.
如何在Pod自动添加ServiceAccount:
通过 Admission Controller插件来实现对pod修改,它是apiserver的一部分。创建或更新pod时会同步进行修改pod。当插件处于激活状态(在大多数发行版中都默认情况)创建或修改pod时,会按以下操作执行:
1.如果pod没有设置ServiceAccount,则将ServiceAccount设置为default。
2.确保pod引用的ServiceAccount存在,否则将会拒绝请求。
3.如果pod不包含任何ImagePullSecrets,则将ServiceAccount的ImagePullSecrets会添加到pod中。
4.为包含API访问的Token的pod添加了一个volume。
5.把volumeSource添加到安装在pod的每个容器中,挂载在/var/run/secrets/kubernetes.io/serviceaccount。
service account token的管理:Token Controller
TokenController作为controller-manager的一部分运行。异步行为:
需要使用--service-account-private-key-file 参数选项将Service Account 密匙(key)文件传递给controller-manager中的Token controller。key用于 Service Account Token签名。同样,也需要使用--service-account-key-file 参数选项将相应的(public key)公匙传递给kube-apiserver ,公钥用于在认证期间验证Token。
针对一些需要和Kubernetes API交互的应用非常有用,比如coredns就需要监控endpoints、services的变化,因此关联了coredns SA,coredns又关联了system:coredns clusterrole。flannel需要监控pods以及nodes变化同样关联了flannel SA。
到这里为止,service account可能是Kubernetes目前最完美的认证方案了,既能支持集群外的客户端认证,又支持集群内的Pod关联授权。
但事实上,service account并不是设计用来给普通user认证的,而是给集群内部服务使用的。目前虽然token是永久有效的,但未来会改成使用动态token的方式,参考官方设计设计文档Bound Service Account Tokens,此时如果kubectl客户端认证则需要频繁更新token。
除此之外,SA虽然能够对应一个虚拟User,但不支持自定义Group,在授权体系中不够灵活。另外也不支持客户端高级认证功能,比如MFA、SSO等。
3.1.1.5 集成外部认证系统
前面已经介绍过Kubernetes集成简单的静态用户文件以及x509证书认证,Kubernetes最强大的功能是支持集成第三方Id Provider(IdP),主流的如AD、LADP以及OpenStack Keystone等,毕竟专业的人做专业的事。
Kubernetes 的认证策略有很多种(请参考 Kubernetes Authentication Strategy),其中,通过一个不记名令牌 (Bear Token) 来识别用户是一种相对安全又被各种客户端广泛支持的认证策略。不记名令牌,代表着对某种资源,以某种身份访问的权利,无论是谁,任何获取该令牌的访问者,都被认为具有了相应的身份和访问权限。配合成熟的令牌授予机构,不记名令牌非常适于在生产环境中严肃使用。身份令牌(ID Token)就是一种形式的不记名令牌,它本身记录着一个权威认证机构对用户身份的认证声明,同时还可以包含对这个用户授予了哪些权限的声明,像极了古代官员佩戴的腰牌。Kubernetes 接受和识别的正是这种 ID Token。
由上可知,想得到 ID Token,首先要经过某个权威机构的一套身份认证流程,OpenID Connect 简称 OIDC 就是这样一套认证、授予 ID Token 的协议。OIDC 是 OAuth2 协议的一种扩展,目前在各大主流厂牌的云服务中都被广泛支持和使用,例如 IBM IAM Service、Google Accounts、Azure Active Directory 等。
Kubernetes 使用 OIDC Token 的认证流程
Kubernetes 使用 OIDC 进行身份认证的流程,比上面介绍的 OAuth2 授权流程要简单不少。在整个过程中, Kubernetes 既作为资源(Resource)服务器,又作为用户代理 User-Agent 存在,但它并不提供引导用户到 Auth Server 进行认证的功能,相反,它要求用户先自行获取 ID Token,然后在访问 Kubernetes API Server 的时候直接提供 ID Token。因此,整个过程中,Kubernetes 其实不需要真正和 Authentication Server 发生任何交互。整个认证流程如下图 2 所示:
那么问题来了,如果 Kubernetes 不和 Auth Server 发生交互的话,它怎么鉴定这些 Token 是合法的用户 token 呢?这里我们可以参考一下 Kubernetes Authentication OIDC Tokens 官方文档,其中它分 9 个步骤更详细描述了从获取 token 到在 kubectl 中使用它们进行访问的流程。其中绝大部分都被上图抽象概括,这里我们重点关注一下步骤 5:
5.The API server will make sure the JWT signature is valid by checking against the certificate named in the configuration.
能够认证 token 的合法性的关键在于,所有 JWT token 都被其颁发 Auth Service 进行了数字签名,我们只需在 Kubernetes API Server 中配置上我们所信任的这个 Auth Server 的证书(Certificate),并用它来验证收到的 id_token 中的签名是否合法,就可以验证 token 的真实性。使用这种基于 PKI 的验证机制,在配置完成后,认证过程中 Kubernetes 就无需和 Auth Server 有任何交互。
Kubernetes使用API server授权API请求。它根据策略来评估所有请求属性,是否给于通过。
(Kubernetes使用API server,访问控制和依赖特定资源对象的策略由(Admission Controllers)准入控制器处理。)
当配置多个授权模块时,会按顺序检查每个模块,如果有任何模块授权通过,则继续执行下一步的请求。如果所有模块拒绝,则该请求授权失败(返回HTTP 403)。
Kubernetes只对以下的API请求属性进行检查:
策略中需要包含一个flag,来指定你的策略包含的哪种授权模块:
使用以下flags:
3.2.1 Node授权
Node授权是一种特殊授权模式,专门授权由kubelet访问的API请求。
Node授权器允许kubelet执行的API操作包括:
读:
写:
Auth-related:
在以后的版本中,Node授权器支持添加或删除的权限。
为获得Node授权器的授权,kubelet需要使用system:nodes组中的用户名system:node:
启用Node授权器方法:apiserver --authorization-mode=Node。
为了限制kubelets能够写入的API对象,可以启动--admission-control=...,NodeRestriction,...准入(admission)插件。
3.2.2 ABAC模式
基于属性的访问控制(ABAC)定义了访问控制范例,通过将属性组合在一起的策略来授予用户访问权限。ABAC策略可以使用任何类型的属性(用户属性,资源属性,对象,环境属性等)。
使用ABAC模式指定策略文件:--authorization-policy-file=SOME_FILENAME。
文件格式是JSON, one JSON object per line。
每一行都是一个“policy 对象”,policy对象具有以下属性:
/foo/*
matches all subpaths of /foo/
示例:
Alice对所有资源进行操作
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "alice", "namespace": "*", "resource": "*", "apiGroup": "*"}}
Kubelet可以读取任何pod:
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "kubelet", "namespace": "*", "resource": "pods", "readonly": true}}
Kubelet可以读/写事件:
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "kubelet", "namespace": "*", "resource": "events"}}
Bob可以在namespace“projectCaribou”中读取pod:
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "bob", "namespace": "projectCaribou", "resource": "pods", "readonly": true}}
3.2.3 RBAC模式
基于角色的访问控制(“RBAC”)使用“rbac.authorization.k8s.io”API 组来实现授权控制,允许管理员通过Kubernetes API动态配置策略。
启用RBAC:
apiserver --authorization-mode=RBAC。
RBAC API声明了四个最高级别的类型(本文介绍),RBAC 的授权策略可以利用 kubectl 或者 Kubernetes API 直接进行配置。RBAC 可以授权给用户,让用户有权进行授权管理,这样就无需接触节点,直接进行授权管理。RBAC 在 Kubernetes 中被映射为 API 资源和操作。
Role 和 ClusterRole
Role是一系列的权限的集合,例如一个Role可以包含读取 Pod 的权限和列出 Pod 的权限, ClusterRole 跟 Role 类似,但是可以在集群中全局使用。
Role只能授予单个namespace 中资源的访问权限。以下是Role“default”namespace 中的示例,用于授予对pod的访问权限:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
ClusterRole授权 >= Role授予(与Role类似),但ClusterRole属于集群级别对象:
ClusterRole示例:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
# "namespace" omitted since ClusterRoles are not namespaced
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"]
RoleBinding和ClusterRoleBinding
RoleBinding是将Role中定义的权限授予给用户或用户组。它包含一个subjects列表(users,groups ,service accounts),并引用该Role。RoleBinding在某个namespace 内授权,ClusterRoleBinding适用在集群范围内使用。
RoleBinding可以引用相同namespace下定义的Role。以下的RoleBinding在“default”namespace中将“pod-reader”Role授予用户“jane”。将允许“jane”在“default”namespace中读取pod权限。
# This role binding allows "jane" to read pods in the "default" namespace.
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
RoleBinding还可以引用ClusterRole。将允许管理员为整个集群定义一组通用Role,然后在不同namespace中使用RoleBinding引用。
# This role binding allows "dave" to read secrets in the "development" namespace.
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: read-secrets
namespace: development # This only grants permissions within the "development" namespace.
subjects:
- kind: User
name: dave
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
ClusterRoleBinding可以用于集群中所有命名空间中授予权限。以下ClusterRoleBinding允许组“manager”中的任何用户在任何命名空间中读取secrets。
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: read-secrets-global
subjects:
- kind: Group
name: manager
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
子资源的授权
大多数资源由name字符串的形式表示,例如“pod”。然而,一些Kubernetes API 涉及“子资源”,例如Pod的logs ,pod log endpoint 的URL:
GET /api/v1/namespaces/{namespace}/pods/{name}/log
在这种情况下,“pod”是namespace中资源,“log”是pod的子资源,这种情况要在RBAC角色中表示,可以使用斜杠来划分资源和子资源。如下例子:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list"]
资源也可以通过resourceNames列表的某些请求的资源名称来引用。如下例子:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: configmap-updater
rules:
- apiGroups: [""]
resources: ["configmap"]
resourceNames: ["my-configmap"]
verbs: ["update", "get"]
需要注意如果设置了resourceNames,那么verbs不能指定为list、watch、create或deletecollection。
Role 示例
允许在核心API Group中读取“pods”资源:
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
允许在“extensions”和“apps”API Group中读/写“deployments”:
rules:
- apiGroups: ["extensions", "apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
允许读取 “Pod” 和 读/写 “jobs”:
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: ["batch", "extensions"]
resources: ["jobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
允许读取名称为 “my-config” 的 ConfigMap:
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["my-config"]
verbs: ["get"]
允许读取核心 Group中资源“Node”(Node属于集群范围,则必须将ClusterRole绑定ClusterRoleBinding):
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
允许非资源型“/ healthz”和所有子路径进行 “GET”和“POST”请求:(必须将ClusterRole绑定ClusterRoleBinding):
rules:
- nonResourceURLs: ["/healthz", "/healthz/*"] # '*' in a nonResourceURL is a suffix glob match
verbs: ["get", "post"]
Referring to Subjects
RoleBinding或ClusterRoleBinding可以将Role绑定到主体subjects。Subjects 可以是groups、users和service accounts。
Role Binding 示例
适合一个名为“[email protected]”的用户:
subjects:
- kind: User
name: "[email protected]"
apiGroup: rbac.authorization.k8s.io
适合一个名为“frontend-admins”的Group:
subjects:
- kind: Group
name: "frontend-admins"
apiGroup: rbac.authorization.k8s.io
适合kube-system Namespace中的默认ServiceAccount:
subjects:
- kind: ServiceAccount
name: default
namespace: kube-system
适合“qa”Namespace中的所有ServiceAccount:
subjects:
- kind: Group
name: system:serviceaccounts:qa
apiGroup: rbac.authorization.k8s.io
适合集群中所有ServiceAccount:
subjects:
- kind: Group
name: system:serviceaccounts
apiGroup: rbac.authorization.k8s.io
适合所有经过认证的用户(1.5版本以上):
subjects:
- kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
适合所有未经认证的用户(1.5版本以上):
subjects:
- kind: Group
name: system:unauthenticated
apiGroup: rbac.authorization.k8s.io
适合所有用户(1.5版本以上):
subjects:
- kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: system:unauthenticated
apiGroup: rbac.authorization.k8s.io
默认Role和 Role Bindings
API Server会创建一组默认的ClusterRole和ClusterRoleBinding对象。其中许多都是system:前缀,表示这些资源属于系统基础组件。修改这些资源对象可能会引起一些未知错误。例如:是system:nodeClusterRole,此角色定义了kubelet的权限,如果角色被修改,将会引起kubelet无法工作。
Auto-reconciliation
在每次启动时,API Server会更新默认的cluster roles ,并更新默认ClusterRoleBinding各个角色绑定主体,这使集群能够修复某些意外修改情况。
User-facing Roles
一些不以system:为前缀的角色是面向用户的Role 。它们包括超级用户Role (cluster-admin),ClusterRoleBindings (cluster-status),以及特定namespaces中授权的 RoleBinding( admin,edit,view )
cluster-admin:
Allows super-user access to perform any action on any resource. When used in a ClusterRoleBinding, it gives full control over every resource in the cluster and in all namespaces. When used in a RoleBinding, it gives full control over every resource in the rolebinding's namespace, including the namespace itself.
Admin:
Allows admin access, intended to be granted within a namespace using a RoleBinding. If used in a RoleBinding, allows read/write access to most resources in a namespace, including the ability to create roles and rolebindings within the namespace. It does not allow write access to resource quota or to the namespace itself.
Edit:
Allows read/write access to most objects in a namespace. It does not allow viewing or modifying roles or rolebindings
View:
Allows read-only access to see most objects in a namespace. It does not allow viewing roles or rolebindings. It does not allow viewing secrets, since those are escalating
Default ClusterRole |
Default ClusterRoleBinding |
Description |
cluster-admin |
system:masters group |
Allows super-user access to perform any action on any resource. When used in a ClusterRoleBinding, it gives full control over every resource in the cluster and in all namespaces. When used in a RoleBinding, it gives full control over every resource in the rolebinding's namespace, including the namespace itself. |
admin |
None |
Allows admin access, intended to be granted within a namespace using a RoleBinding. If used in a RoleBinding, allows read/write access to most resources in a namespace, including the ability to create roles and rolebindings within the namespace. It does not allow write access to resource quota or to the namespace itself. |
edit |
None |
Allows read/write access to most objects in a namespace. It does not allow viewing or modifying roles or rolebindings |
view |
None |
Allows read-only access to see most objects in a namespace. It does not allow viewing roles or rolebindings. It does not allow viewing secrets, since those are escalating |
Default ClusterRole |
Default ClusterRoleBinding |
Description |
cluster-admin |
system:masters group |
Allows super-user access to perform any action on any resource. When used in a ClusterRoleBinding, it gives full control over every resource in the cluster and in all namespaces. When used in a RoleBinding, it gives full control over every resource in the rolebinding's namespace, including the namespace itself. |
Core Component Roles
Default ClusterRole |
Default ClusterRoleBinding |
Description |
system:kube-scheduler |
system:kube-scheduler user |
Allows access to the resources required by the kube-scheduler component. |
system:kube-controller-manager |
system:kube-controller-manager user |
Allows access to the resources required by the kube-controller-manager component. The permissions required by individual control loops are contained in the controller roles. |
system:node |
system:nodes group (deprecated in 1.7) |
Allows access to resources required by the kubelet component, including read access to all secrets, and write access to all pods. As of 1.7, use of the [Node authorizer](/docs/admin/authorization/node/) and [NodeRestriction admission plugin](/docs/admin/admission-controllers#NodeRestriction) is recommended instead of this role, and allow granting API access to kubelets based on the pods scheduled to run on them. As of 1.7, when the `Node` authorization mode is enabled, the automatic binding to the `system:nodes` group is not created. |
system:node-proxier |
system:kube-proxy user |
Allows access to the resources required by the kube-proxy component |
Default ClusterRole |
Default ClusterRoleBinding |
Description |
system:kube-scheduler |
system:kube-scheduler user |
Allows access to the resources required by the kube-scheduler component. |
准入控制(Admission Control)在授权后对请求做进一步的验证或添加默认参数,在对kubernetes api服务器的请求过程中,先经过认证、授权后,执行准入操作,在对目标对象进行操作。这个准入插件代码在apiserver中,而且必须被编译到二进制文件中才能被执行。
在对集群进行请求时,每个准入控制插件都按顺序运行,只有全部插件都通过的请求才会进入系统,如果序列中的任何插件拒绝请求,则整个请求将被拒绝,并返回错误信息。
在某些情况下,为了适用于应用系统的配置,准入逻辑可能会改变目标对象。此外,准入逻辑也会改变请求操作的一部分相关资源。
运行准入控制插件
旧版本:在kubernetes apiserver中有一个flag:admission_control,他的值为一串用逗号连接起、有序的准入模块列表,设置后,就可在对象操作前执行一定顺序的准入模块调用。
Kubernetes 1.10之后的版本, --admission-control 已经废弃,建议使用 --enable-admission-plugins --disable-admission-plugins 指定需要打开或者关闭的 Admission Controller。 同时用户指定的顺序并不影响实际 Admission Controllers 的执行顺序,对用户来讲非常友好。
在1.18版本中默认启动的插件:
NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota
AlwaysAdmit
结束所有的请求。
AlwaysPullImages
该插件修改每个新的Pod,强制pull最新镜像,这在多租户群集中非常有用,以便私有镜像只能由拥有授权凭据的用户使用。
AlwaysDeny
拒绝所有请求,一般用于测试。
DenyExecOnPrivileged(已弃用)
该插件将拦截所有请求。如果pod有一个privileged container,将只执行这个pod中的命令。
如果自己的集群支持privileged container,自己又希望限制用户在这些privileged container上执行命令,那么强烈推荐使用它。
此功能已合并到DenyEscalatingExec中。
DenyEscalatingExec
禁止privileged container的exec和attach操作。
ImagePolicyWebhook
通过webhook决定image策略,需要同时配置--admission-control=ImagePolicyWebhook,配置文件格式如下。
ServiceAccount
该插件将serviceAccounts 实现了自动化。如果打算使用Kubernetes ServiceAccount对象,那么强烈建议使用此插件。
SecurityContextDeny
该插件会将使用了 SecurityContext的pod中定义的选项全部失效 。
ResourceQuota
该插件将会观察传入的所有请求,并确保它不会违反ResourceQuota对象中枚举的任何限制Namespace。如果在Kubernetes Deployment中使用了ResourceQuota对象,则必须使用此插件来约束Container。
更多详细信息,请参阅resourceQuota design doc和example of Resource Quota。
推荐在Admission Control参数列表中,这个插件排最后一个。
LimitRanger
该插件将会观察传入的所有请求,并确保它不会违反LimitRanger对象中枚举的任何限制Namespace,如果在Kubernetes Deployment中使用了LimitRanger对象,则必须使用此插件。LimitRanger还可使用Apply将default资源请求不指定任何的Pods; 目前LimitRanger对Default Namespace中的所有pod应用要求0.1 CPU
更多详细信息,请参阅limitRange design doc和example of Limit Range 。
InitialResources(试验)
根据镜像的历史使用记录,为容器设置默认资源请求和limits。
更多详细信息,参考 InitialResouces proposal。
NamespaceLifecycle
该插件确保处于Termination状态的Namespace不再接收新的对象创建请求,并拒绝请求不存在的Namespace。该插件还可以防止删除系统保留的Namespace:default,kube-system,kube-public。
DefaultStorageClass
该插件将观察PersistentVolumeClaim,并自动设置默认的Storage Class。
当没有配置默认Storage Class时,此插件不会执行任何操作。当有多个Storage Class被标记为默认值时,它也将拒绝任何创建,管理员必须重新访问StorageClass对象,并且只标记一个作为默认值。此插件不用于PersistentVolumeClaim的更新,仅用于创建。
更多详细信息,参考persistent volume。
DefaultTolerationSeconds
该插件设置Pod的默认forgiveness toleration为5分钟。
PodSecurityPolicy
该插件用于创建和修改pod,使用Pod Security Policies时需要开启。
当 Kubernetes <1.6.0版本时,API服务器需要启用扩展名/ v1beta1 / podsecuritypolicy API扩展组(--runtime-config=extensions/v1beta1/podsecuritypolicy=true)。
更多信息,请参考Pod Security Policy documentation。
NodeRestriction
此插件限制kubelet修改Node和Pod对象,这样的kubelets只允许修改绑定到Node的Pod API对象,以后版本可能会增加额外的限制。
限制kubelet仅可访问node、endpoint、pod、service以及secret、configmap、PV和PVC等相关的资源(仅适用于v1.7+)
1.Kubernetes API Server官方文档
http://docs.kubernetes.org.cn/27.html
2. SSL双向认证和SSL单向认证的流程和区别
https://www.cnblogs.com/bluestorm/p/10571989.html
3. 浅聊Kubernetes的各种认证策略以及适用场景
https://zhuanlan.zhihu.com/p/97797321
4. openssl 证书请求和自签名命令req详解
https://www.cnblogs.com/gordon0918/p/5409286.html
5. Https原理及流程
https://www.jianshu.com/p/14cd2c9d2cd2
6. Kubernetes 必须掌握技能之 RBAC
https://zhuanlan.zhihu.com/p/97793056
7. 使用kubectl访问Kubernetes集群时的身份验证和授权
https://blog.csdn.net/luanpeng825485697/article/details/83955721
8. kubernetes中kubeconfig的用法
https://www.cnblogs.com/charlieroro/p/8489515.html
9.为 Kubernetes 搭建支持 OpenId Connect 的身份认证系统
https://developer.ibm.com/zh/articles/cl-lo-openid-connect-kubernetes-authentication/
10. kubernetes新建自定义用户(新cluster 用户名)
https://blog.csdn.net/wt334502157/article/details/102822348
11.kubernetes proxy简介
https://blog.csdn.net/dkfajsldfsdfsd/article/details/80981780
12.accessing-the-rest-api
https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#directly-
13. Kubernetes 准入控制 Admission Controller 介绍
https://www.codercto.com/a/27364.html