赞
踩
开启 TLS时,所有的请求都需要首先认证。Kubernetes支持多种认证机制,并支持同时开启多个认证插件(只要有一个认证通过即可)。
如果认证成功,则用户的 username 会传入授权模块做进一步授权验证,而对于认证失败的请求则返回 HTTP 401。
当apiserver启动的时候,其实有两个和安全相关的配置,一个叫insecure-port,一个叫secure-port,早期大家很习惯的将insecure-port打开,经过insecure-port端口所有的请求其实是没有做任何的安全校验的,也就是认证,鉴权这些逻辑是不走的,这样就面临着一个危险,所有的request是没有认证的,不管是谁发的,它有没有权限,它都会被接受,这很可能就会有一些恶意的请求。
所以现在在非生产环境也会将insecure端口关掉。
另外一个是secure port,secure-port设置之后所有的认证,鉴权这些逻辑都要走。
- [root@k8s-master cfg]# vim kube-apiserver.conf
- --secure-port=6443 \
针对开放式的框架,它一定会支持很多很多的认证方式。
X509 证书
证书一般会有key和cert,cert在签发的时候是发给什么机构,哪个人的。这样你带着一个证书来访问apiserver的时候,它有签发你证书的ca文件,它就能够解析出来你的certificates,它就能够知道你是谁。
CN 是请求用户的用户名 O:是请求用户的组名
- cat > ca-csr.json <<EOF
- {
- "CN": "Kubernetes",
- "key": {
- "algo": "rsa",
- "size": 2048
- },
- "names": [
- {
- "C": "CN",
- "L": "China",
- "O": "Kubernetes",
- "OU": "CA",
- "ST": "Zhejiang"
- }
- ]
- }
- EOF
静态Token 文件
apiserver启动的时候要配置一个token-auth-file,在这个csv文件里面配置用户名,用户id,以及对应的token,和用户属于哪些组配置在这个scv文件里面,它有点像简化的数据库,其实也即是将用户名和对应的token发到这里面,然后在apiserver启动的时候加载这个文件,那apiserver就知道我这个集群可以接受哪些用户请求,你带着用户token过来,它就能够判断这个token是不是合法的,如果合法就知道对应的user是谁,它就可以将这个请求接受掉了。
在k8s启动的时候有bootstrap token,它也是可以做认证的。
静态密码文件
OpenID
OAuth 2.0的认证机制
ServiceAccount
ServiceAccount是 Kubernetes 自动生成的,并会自动挂载到容器的/run/secrets/kubernetes.io/serviceaccount 目录中。
当你去建立任何的namespace的时候,k8s就有一个控制器,它看见namespace创建了,它就会去建立sa,它会生成token,这个token签发的内容其实就是代表了这个token签发给哪个namespace的,哪个serviceaccount的,这个token是apiserver签发的,所以你带着token去访问apiserver的时候,它就知道这个token合法还是非法,代表的是哪个namespace,哪个serviceaccount。
https://github.com/cncamp/101/tree/master/module6/basic-auth
- [root@master ~]# mkdir -p /etc/kubernetes/auth
-
- [root@master auth]# cat static-token
- cncamp-token,cncamp,1000,"group1,group2,group3"
在这个scv文件里面创建了用户,token叫做cncamp-token,这个是用户的token。用户名是cncamp,它的uid是1000,然后它放到3个group里面,这就是简单的token文件。
如果我们要去启用静态的token,那么我要去修改apiserver的配置文件,这个就是告诉apiserver说,这个文件里面的内容我是承认的。也即是将主机的文件mount到apiserver的pod里面。
在这个pod的volumes里面定义了一个hostpath的volume
更新完apiserver的yaml文件会去做个重启,如果get pod成功那么说明api-server重启成功。
这里面加了header,这个header加了token,这个token代表了cncamp这个用户,直接发rest
api调用通过curl命令。
- [root@master manifests]# curl https://192.168.111.8:6443/api/v1/namespaces/default -H "Authorization: Bearer cncamp-token" -k
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {
-
- },
- "status": "Failure",
- "message": "namespaces \"default\" is forbidden: User \"cncamp\" cannot get resource \"namespaces\" in API group \"\" in the namespace \"default\"",
- "reason": "Forbidden",
- "details": {
- "name": "default",
- "kind": "namespaces"
- },
- "code": 403
- volumes:
- - hostPath:
- path: /etc/kubernetes/auth
- type: DirectoryOrCreate
- name: auth-files
-
- - mountPath: /etc/kubernetes/auth
- name: auth-files
- readOnly: true
-
- - --token-auth-file=/etc/kubernetes/auth/static-token
可以看到由于权限的问题,它的code是403是鉴权不过的,其实认证是通过的,因为它知道你的token对应的用户是cncamp。
- [root@master manifests]# curl https://192.168.111.8:6443/api/v1/namespaces/default -H "Authorization: Bearer cncamp-token" -k
- {
- "kind": "Status",
- "apiVersion": "v1",
- "metadata": {
-
- },
- "status": "Failure",
- "message": "namespaces \"default\" is forbidden: User \"cncamp\" cannot get resource \"namespaces\" in API group \"\" in the namespace \"default\"",
- "reason": "Forbidden",
- "details": {
- "name": "default",
- "kind": "namespaces"
- },
- "code": 403
也就是说带着cncamp的token去访问apiserver,它已经去本地的static token file里面去校验token代表哪个用户了,它查找到了这个用户并且说这个用户没有权限,其实整个的认证就已经过了。
如果能够使用kubernetes自己的ca去签发X509证书,那么它是直接可以认的。
- --client-ca-file=/etc/kubernetes/pki/ca.crt
kubeadm搭建的集群,本身就使用了x509证书
当创建任何的serviceaccount的时候,在这个namespace里面,其实k8s会自动的在这个namspace里面创建一个叫default的serviceaccount,所谓的serviceaccount就是系统账号。
每个系统账号会有对应的secret,可以看到有ca文件,还有namespace,这个是base64加密了的,还有一个token,这个其实就是apiserver签发的jwt token,和之前静态token是类似的。
可以看到只要带着这个token去访问apiserver,apiserver就能够认出我是谁,配合权限控制那么就可以根据这个token去访问apiserver里面的任何对象。
如果基于内置的认证方式还不能满足你需求,公司有自己的认证系统,认证方式都在集群之外,那么怎么使得k8s集群和这些认证平台去集成,那么就需要通过webhook,k8s认证也支持webhook。
你可以基于webhook来配置来指向外部的认证服务器,有了这种认证集成的方式之后,那么k8s就可以和任何平台去做集成。
匿名请求
创建一个NS名称空间, 专用于运行Pod;
kubectl create ns jenkins
创建一个secret关联serviceaccount和role,操作K8s API
- # 创建role
- kubectl -n jenkins create role jenkinsadmin \
- --verb=create,delete,update,list,get,patch \
- --resource=pods
-
- # 创建服务账户
- kubectl -n jenkins create serviceaccount jenkinsadmin
-
- # 创建角色绑定
- kubectl -n jenkins create rolebinding jenkinsadmin --role=jenkinsadmin --serviceaccount=jenkins:jenkinsadmin
-
- # 创建secret
- kubectl apply -f - <<EOF
- apiVersion: v1
- kind: Secret
- metadata:
- name: jenkinsadmin-token
- namespace: jenkins
- annotations:
- kubernetes.io/service-account.name: jenkinsadmin
- type: kubernetes.io/service-account-token
- EOF
-
-
- while ! kubectl -n jenkins describe secret jenkinsadmin-token | grep -E '^token' >/dev/null; do
- echo "waiting for token..." >&2
- sleep 1
- done
-
-
- # 获取令牌
- TOKEN=$(kubectl -n jenkins get secret jenkinsadmin-token -o jsonpath='{.data.token}' | base64 --decode)
-
- echo $TOKEN
-
- # 获取API
- kubectl config view -o jsonpath='{"Cluster name\tServer\n"}{range .clusters[*]}{.name}{"\t"}{.cluster.server}{"\n"}{end}'
-
- # 使用令牌玩转 API
- curl -X GET https://127.0.0.1:35659/api --header "Authorization: Bearer $TOKEN" --insecure
- [root@192 ~]# curl -X GET https://127.0.0.1:6443/api --header "Authorization: Bearer $TOKEN" --insecure
- {
- "kind": "APIVersions",
- "versions": [
- "v1"
- ],
- "serverAddressByClientCIDRs": [
- {
- "clientCIDR": "0.0.0.0/0",
- "serverAddress": "192.168.11.134:6443"
- }
- ]
- }
将token 以secret text类型存储到Jenkins
POD API
- //删除POD
- def DeletePod(namespace, podName){
- withCredentials([string(credentialsId: 'f66733bf-ef35-402d-87d1-a79510387d2b', variable: 'CICDTOKEN')]) {
- sh """
- curl --location --request DELETE "https://192.168.1.200:6443/api/v1/namespaces/${namespace}/pods/${podName}" \
- --header "Authorization: Bearer ${CICDTOKEN}" \
- --insecure >/dev/null
- """
- }
- }
-
- // 创建POD
- def CreatePod(namespace, podYaml){
- withCredentials([string(credentialsId: 'f66733bf-ef35-402d-87d1-a79510387d2b', variable: 'CICDTOKEN')]) {
- sh """
- curl --location --request POST "https://192.168.1.200:6443/api/v1/namespaces/${namespace}/pods" \
- --header 'Content-Type: application/yaml' \
- --header "Authorization: Bearer ${CICDTOKEN}" \
- --data "${podYaml}" --insecure >/dev/null
- """
- }
- }
- curl --location --request POST "https://192.168.11.134:6443/api/v1/namespaces/jenkins/pods" \
- --header 'Content-Type: application/yaml' \
- --header "Authorization: Bearer ${TOKEN}" \
- --data "${podYaml}" --insecure >/dev/null
-
- curl --location --request DELETE "https://192.168.11.134:6443/api/v1/namespaces/jenkins/pods/nginx" \
- --header "Authorization: Bearer ${TOKEN}" \
- --insecure >/dev/null
- curl --location --request GET 'https://192.168.11.134:6443/api/v1/namespaces/jenkins/pods' \
- --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjBqSWxfOExtSW1pVmpKVkFUVGFQbHp1ZE5TcFo0SjlmOUtjMWFveWtrZGMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJqZW5raW5zIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImplbmtpbnNhZG1pbi10b2tlbi1jbTRsNyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJqZW5raW5zYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJjMDAwZTVhMC00Yzg0LTQyZWEtYmJiNy1mZmM5MDBhYzUyMjIiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6amVua2luczpqZW5raW5zYWRtaW4ifQ.A-InywzLZZfwx_4-Na9iDDRGsIH0Bjm9Xk92VxKsnP7hflEbOU631EU0eHnewgg0UqAD1kkhW39XupN13oTXrOjHrzWdm_UUMe2cBIYCZD19VIpNnRZ6bBLZ3LFHA2F0gXO14HaVZiUvSYBXgIfyHydetIFQFBPWFtU7091u5iB4pcw_gE-VzGjX6NDHj-81j6Ap2Qr0gIrNvrPVAOpPO9uCSg3PNCgvQMq2ZNrY2te1w7QxmeFPEpOIPiK6VbUkRjhQlHmawULZFol2k5Wwv9z0m1hPQcc2Nten1f1__GR39hUjryWXfltJ8OLpbKWK-AtfBkHx8VqbiKH1vQOrRg' \
- --header 'Content-Type: text/plain' \
- --data-raw 'abc'
这里请求方法由get换成了delete
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。