内容简介:以前在基于k8s做应用开发的时候,都是使用admin来使用k8s,基本不用去关注授权的问题。但是,当我们将k8s作为PaaS平台的容器编排引擎,并引入多租户时,就涉及到权限管理相关的问题了。那么,如果你刚好是公司的系统管理员,当你部署完一套k8s,准备将其提供给多个部门使用的时候(他们希望彼此互不影响),接下来的内容就特别适合你了。K8s的安全问题越来越成为大家都在关注的重点,挑战一方面来自于运行时容器层面宿主机的安全,另一方面来自于k8s本身的安全。k8s的授权默认是基于RBAC的方式,这个比较好理解,但
以前在基于k8s做应用开发的时候,都是使用admin来使用k8s,基本不用去关注授权的问题。但是,当我们将k8s作为PaaS平台的容器编排引擎,并引入多租户时,就涉及到权限管理相关的问题了。那么,如果你刚好是公司的系统管理员,当你部署完一套k8s,准备将其提供给多个部门使用的时候(他们希望彼此互不影响),接下来的内容就特别适合你了。
概要介绍
K8s的安全问题越来越成为大家都在关注的重点,挑战一方面来自于运行时容器层面宿主机的安全,另一方面来自于k8s本身的安全。
认证方式
k8s的授权默认是基于RBAC的方式,这个比较好理解,但是认证却支持好几种方式:
- 客户端证书
-
Bearer Tokens
- Service Account Token
- BootStrap Token
- Static Token
- HTTP Basic Auth
- Authenticating Proxy
接下来我们重点分析前三种类型,至于Authenticating Proxy之类,这里暂不做分析。
权限控制原理
要解决文章开始时提到的问题,按照常规业务系统的设计,不外乎以下几步:
- 将系统中模块的子功能的操作权限赋予角色;
- 将用户与角色绑定,让用户拥有角色对应的操作权限;
- 认证用户的登录;
k8s系统中基于RBAC的授权刚好就是前面两步做的事情:
- 首先创建role,在role中指定该role所拥有的权限,能够允许执行的所有操作。
-
然后创建rolebinding,这一步binding的不止是用户;在k8s中,允许binding到role的可以是
user
,group
,service account
。其中user
就是用户,group
是用户组,service account
可以理解为系统为内部服务分配的一个账户。
如果希望role和rolebinding不止是局限于对应的namespace,可以使用clusterrole和clusterrolebinding,这将使role的操作权限扩大到集群层面,而不是在单独某一个namespace内。
那么,第三步又是如何实现的呢?下面就介绍几种方法。
客户端证书认证
客户端证书认证就是客户端向k8s提交带有用户名、用户组等信息的CSR,然后管理员在k8s上为该客户签发证书。以后,用户使用该证书去访问k8s,api-server就能够辨识出用户。结合RBAC的配置,如果该用户或者用户组通过rolebinding绑定了role,那么该用户就拥有该role对对应资源的操作权限。
下面便是操作流程,通过示例,可以再理解一遍上面的流程。
-
在本地主机上生成客户端的key和CSR文件
# 生成key文件 $ openssl genrsa -out ljchen.key 4096 # 创建csr配置文件 $ cat csr.cnf [ req ] default_bits = 2048 prompt = no default_md = sha256 distinguished_name = dn [ dn ] CN = ljchen O = dev [ v3_ext ] authorityKeyIdentifier=keyid,issuer:always basicConstraints=CA:FALSE keyUsage=keyEncipherment,dataEncipherment extendedKeyUsage=serverAuth,clientAuth # 生成csr文件 $ openssl req -config ./csr.cnf -new -key ljchen.key -nodes -out ljchen.csr
-
向k8s提交CSR,管理员签发后生成客户端证书
# 创建CSR的k8s yaml $ cat csr.yaml apiVersion: certificates.k8s.io/v1beta1 kind: CertificateSigningRequest metadata: name: mycsr spec: groups: - system:authenticated request: ${BASE64_CSR} usages: - digital signature - key encipherment - server auth - client auth # 下发CSR到k8s $ export BASE64_CSR=$(cat ./ljchen.csr | base64 | tr -d '\n') $ cat csr.yaml | envsubst | kubectl apply -f - # 在k8s上为CSR生成证书 $ kubectl get csr $ kubectl certificate approve mycsr $ kubectl get csr NAME AGE REQUESTOR CONDITION mycsr 9s 28b93...d73801ee46 Approved,Issued # 导出证书 $ kubectl get csr mycsr -o jsonpath=’{.status.certificate}’ \ | base64 --decode > ljchen.crt # 查看证书信息 $ openssl x509 -in ./ljchen.crt -noout -text Certificate: Data: Version: 3 (0x2) Serial Number: 01:27:cb:76:d1:72:cd:73:a5:be:06:b1:ae:f9:6c:99:11:5c:36:c8 Signature Algorithm: sha256WithRSAEncryption Issuer: CN=kubernetes Validity Not Before: Jun 13 02:04:00 2019 GMT Not After : Jun 12 02:04:00 2020 GMT Subject: O=dev, CN=ljchen Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (4096 bit) ...
-
配置RBAC, 在k8s端使用证书来控制用户认证
$ kubectl create ns development # 创建role $ cat role.yaml kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: development name: dev rules: - apiGroups: [""] resources: ["pods", "services"] verbs: ["create", "get", "update", "list", "delete"] - apiGroups: ["apps"] resources: ["deployments"] verbs: ["create", "get", "update", "list", "delete"] $ kubectl apply -f role.yaml # 创建role-binding, 分两种情况,可以绑定到user或者group,两者二选一 # 绑定到user上 $ cat role-binding-user.yaml kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: dev namespace: development subjects: - kind: User name: ljchen apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: dev apiGroup: rbac.authorization.k8s.io # 绑定到group上 $ cat role-binding-group.yaml kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: dev namespace: development subjects: - kind: Group name: dev apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: dev apiGroup: rbac.authorization.k8s.io $ kubectl apply -f role-binding-group.yaml
-
在客户端,配置kubeconfig文件
# 1. 先基于生成的ljchen.crt和已存在的ca来配置kubeconfig文件 # 2. 将ljchen.key应用到kubeconfig中 $ kubectl config set-credentials ljchen --client-key=~/.kube/ljchen.key --embed-certs=true
Service Account Token认证
service account本来是系统服务使用的账户,当我们创建service account时,它会自带一个secret,这个secret就是token。
前面谈到,rolebinding除了支持绑定user,group之外,还支持绑定到service account。所以,为了方便,我们有时候通过绑定role到某个service account的方式来直接使用sa的sercret来访问系统资源。比如部署dashboard的时候,就经常用这种方法来获取token登录UI。
下面的示例就是创建service account并取得token来登录系统的流程。
-
服务端获取token
#Create a new ServiceAccount kubectl create serviceaccount k8sadmin -n kube-system #Create a ClusterRoleBinding with Cluster Admin Privileges(系统管理员角色!!) kubectl create clusterrolebinding k8sadmin --clusterrole=cluster-admin --serviceaccount=kube-system:k8sadmin #serviceAccount 会自动生成secret,对应的token就是secret的值 kubectl get secret -n kube-system | grep k8sadmin | cut -d " " -f1 | xargs -n 1 | xargs kubectl get secret -n kube-system -o yaml apiVersion: v1 data: ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1EWXhNakV6TWpZd09Gb1hEVEk1TURZd09URXpNall3T0Zvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTktnCnRiSnQxSTZ6QlFVTmE2WHROK1pQN2xLeDdxbVk2aGJiaVByTXVGbmRhanBvd0RYdDhHVlJmNGFhbWVLS2Z0enEKWlJvSko5eHg5T3lnRkVINzRLY2tGRFhCbElUck9oY0t6TjJIWEI4SUlKM3BvN0Qzc0VScHZEYVZ6L0Z5TmRWagpBU0VhQzhlRWRSa2g2akhVeHJUTWlUMlJZemMrZGNaWC83MHcrTW90bjE5Skt4d0Y5N3h3U2EvYmd6NUdXK1V3CllBd0E0TWRwWG1YM1R1TUx5Rm9kSTVZOUt1VHBpVWd1OFp5Sm5ySzBpQ3g5MlpQMGRSVUlITXVRakxKWkhyY2QKOERsSmNnL0ZsOXlwaDh3UTZScDZSbzFlZ05tY2xGVFJBQm12OVhvMmNOdHJ4Mm1BTmp4aDBycjFkU21NWEJqUgpqS1Y0SFdqVWRzcERKbVpXRnJzQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFNZkxia016RzZ6aGpUSGxtaU93SFJqL05BSWEKM0ZOY2lvekhJcUU2VkE5UUlOZ0V4a1pzQnBRREdBWVZvYk1Ec3RSQXQxY2M4cW5qdVltSnoreFlDZTFYY0xLMgpWRlpWdkdOZzJCRmJrTFdtYlRPeXhNNmQ0S2VvZnh6VDQ4cmU3U1pmQWRLRnRrVXN5T3AvUndQWGlOMVFpcy8vCkV6NDA1RlczTFZRWGtpMjh2cG5KUG5WNUhoZy9FY0ZMOXoveXdSUEtldmFRZUE5NGFFVXNuOEJXTGtZcWs3NWgKalM4dlhlNi9KOGVvWDdybVdhOG9QZUdQYmpqZ2E0Q0UyK2N1L0RqMFNFWEduK2xzM2w1V3dGZVNVNXdwd21XUwptdUdPdDZXVTdaa3hJbkNSTERudGovZzlJOFVGai9JZFBvd3B2bU1oUW5DOXFtV2pCZ21RSkhsN29iUT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= namespace: a3ViZS1zeXN0ZW0= token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklpSjkuZXlKcGMzTWlPaUpyZFdKbGNtNWxkR1Z6TDNObGNuWnBZMlZoWTJOdmRXNTBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5dVlXMWxjM0JoWTJVaU9pSnJkV0psTFhONWMzUmxiU0lzSW10MVltVnlibVYwWlhNdWFXOHZjMlZ5ZG1salpXRmpZMjkxYm5RdmMyVmpjbVYwTG01aGJXVWlPaUpyT0hOaFpHMXBiaTEwYjJ0bGJpMXFiamQ0ZGlJc0ltdDFZbVZ5Ym1WMFpYTXVhVzh2YzJWeWRtbGpaV0ZqWTI5MWJuUXZjMlZ5ZG1salpTMWhZMk52ZFc1MExtNWhiV1VpT2lKck9ITmhaRzFwYmlJc0ltdDFZbVZ5Ym1WMFpYTXVhVzh2YzJWeWRtbGpaV0ZqWTI5MWJuUXZjMlZ5ZG1salpTMWhZMk52ZFc1MExuVnBaQ0k2SW1RMll6TmpPR1V5TFRoa01UVXRNVEZsT1MwNE0yVmtMVEF3TVRZelpURTBPV05tTWlJc0luTjFZaUk2SW5ONWMzUmxiVHB6WlhKMmFXTmxZV05qYjNWdWREcHJkV0psTFhONWMzUmxiVHByT0hOaFpHMXBiaUo5LnBlRGtqREp5UlliRDVfdFJQZDBKaDB5VEpSTDhNM3M1ZlJka1dYUWNDd2RGM0J3TE9mRVBPaWI0bEF3US1OcUptQS1sUlZ2dnQ4ZTVqU3h4UVVJSlRJYWp6S0RxaWYzQUpPVElYVEpmYy1vRGg1VUw2T01WdVJhdlhLNkZkbk1rd281RlhOSzVOYnl4WGx5RGdoaUJqWGc0ZUVXUWRLcXdKc05GYjBtcm15N2czb2NrZUsyQjZONzNDMWNwUGtIajRqTzY3bHl0OVFrQmtRRU1odGlNaURoZlJlTWFzLXF1ZFIzbGh3Z2xZUlNBbkdzelFOSnFKbFZxTzNUSkdEVjNmc0tUNVBlZFVHU1ZjM0JlQm1ZLXhyLUtyZFR5dE1rSk1rRUtoOHNOWEZ2UzN1MFowYjRRaVhwd296cjFkVlBkUnU4NDB2X2hkN1JPUkpOQkZ0UlV1dw== kind: Secret metadata: annotations: kubernetes.io/service-account.name: k8sadmin kubernetes.io/service-account.uid: d6c3c8e2-8d15-11e9-83ed-00163e149cf2 creationTimestamp: "2019-06-12T13:27:34Z" name: k8sadmin-token-jn7xv namespace: kube-system resourceVersion: "487" selfLink: /api/v1/namespaces/kube-system/secrets/k8sadmin-token-jn7xv uid: d6c522cd-8d15-11e9-83ed-00163e149cf2 type: kubernetes.io/service-account-token # 获取token值 kubectl get secret -n kube-system | grep k8sadmin | cut -d " " -f1 | xargs -n 1 | xargs kubectl get secret -o 'jsonpath={.data.token}' -n kube-system | base64 --decode
-
客户端使用token
kubectl -s https://10.x.x.x:6443 --token eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrOHNhZG1pbi10b2tlbi1iNG1xcCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJrOHNhZG1pbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjVjN2RlYTVkLTUzYWMtMTFlOS1iMmNmLTUyNTQwMGZmNzI5YSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTprOHNhZG1pbiJ9.bpyv4SuQ1P-LyGIs5udfx74qonM21ickQA60og47HT5MHQDCypPyrsjBwq73mEzVvDmw6A42WKtBq_Tv4V7cT4fB-pnmxtkuESkmDdIr0FH7LCSyd6MIvIkqxkVvawy74AiWB7YbgbA1bJq5_btNPl8kPfFNz9SSPpKSnv3wc6Ln8kfvZRSWM-K_6sE4QQOhlcoshwqzCPSH9hU3HjkcYTg-QAry-IThjSLAoFiq4sgSsl95MG51sxPYhvM5hl-FLVGAehnJtlPlwc29BU5zfeCv64_hhLHIwYT74pLgVNe6O_McuhnreG5W2YcqxngFOUHuHrdogLlwRe_KELRS-Q get nodes NAME STATUS ROLES AGE VERSION k8s-master Ready master 73d v1.14.0
BootStrap Token认证
bootstrap token是kubeadm部署系统的时候,为了方便node加入到集群,从而提供了一个后门。该token对应的user拥有自动签发客户端CSR的权限,这样添加一台新节点的时候,就不用管理员到系统上面手动签发CSR请求了。
bootstrap-token都是以“bootstrap-token-”开头的名称,其中auth-extra-groups指定了其所属的group信息。clusterrolebinding也就是通过绑定clusterrole到该group,从而允许持有该token的kubeadm节点拥有签发证书的权限的。
-
token中的auth-extra-groups信息
# 查看secret内容 $ kcs get secret bootstrap-token-gb4kis -o yaml apiVersion: v1 data: auth-extra-groups: c3lzdGVtOmJvb3RzdHJhcHBlcnM6a3ViZWFkbTpkZWZhdWx0LW5vZGUtdG9rZW4= description: VGhlIGRlZmF1bHQgYm9vdHN0cmFwIHRva2VuIGdlbmVyYXRlZCBieSAna3ViZWFkbSBpbml0Jy4= expiration: MjAxOS0wNi0xM1QyMToyNjozMyswODowMA== token-id: Z2I0a2lz token-secret: cW40M3d6ZGJzd2c4ZjdlOA== usage-bootstrap-authentication: dHJ1ZQ== usage-bootstrap-signing: dHJ1ZQ== kind: Secret metadata: creationTimestamp: "2019-06-12T13:26:33Z" name: bootstrap-token-gb4kis namespace: kube-system resourceVersion: "168" selfLink: /api/v1/namespaces/kube-system/secrets/bootstrap-token-gb4kis uid: b228ddbb-8d15-11e9-83ed-00163e149cf2 type: bootstrap.kubernetes.io/token # 解出auth-extra-groups对应的base64编码信息为 $ echo "c3lzdGVtOmJvb3RzdHJhcHBlcnM6a3ViZWFkbTpkZWZhdWx0LW5vZGUtdG9rZW4=" | base64 -d system:bootstrappers:kubeadm:default-node-token # 其中system:bootstrappers为group信息 #接下来重点关注该group对应的clusterrolebinding $ kcs get clusterrolebinding | grep kubeadm kubeadm:kubelet-bootstrap 14h kubeadm:node-autoapprove-bootstrap 14h kubeadm:node-autoapprove-certificate-rotation 14h kubeadm:node-proxier 14h
-
绑定的clusterrole
clusterrolebinding | clusterrole |
---|---|
kubeadm:kubelet-bootstrap | system:node-bootstrapper |
kubeadm:node-autoapprove-bootstrap | system:certificates.k8s.io:certificatesigningrequests:nodeclient |
kubeadm:node-autoapprove-certificate-rotation | system:certificates.k8s.io:certificatesigningrequests:selfnodeclient |
kubeadm:node-proxier | system:node-proxier |
静态Token认证
api server参数:
–token-auth-file string
If set, the file that will be used to secure the secure port of the API server via token authentication.
api server通过 --token-auth-file=SOMEFILE
读取文件中的Token。当前,token是无期限持续的,除非重启api server。token文件是一个至少包含3列的csv文件: token, user name, user uid
,后跟可选的组名。
如果您有多个组,则列必须是双引号,例如:
token,user,uid,"group1,group2,group3"
用token唯一标识客户端,只要api server存在该token,则认为认证通过,但是如果需要新增Token,则需要重启kube-apiserver组件。当通过客户端使用 bearer token 认证时,API服务器需要一个值为带有 Bearer THETOKEN
值的Authorization头。bearer token必须是一个字符序列,能够放在HTTP请求头中。
HTTP Basic Auth
api server参数:
–basic-auth-file string
If set, the file that will be used to admit requests to the secure port of the API server via http basic authentication.
基础认证模式通过在api server中设置 -–basic-auth-file=SOMEFILE
来启用。一旦api server服务启动,加载的用户名和密码信息就不会发生改变,任何对源文件的修改必须重启api server才能生效。
静态密码文件是CSV格式的文件,每行对应一个用户的信息:
password,user,uid,"group1,group2,group3"
当Http客户端使用基础认证时,api server需要一个带有Basic BASE64ENCODED(USER:PASSWORD) 值的Authorization头。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- OAuth 2.0 授权认证详解
- Laravel多用户认证系统示例详解
- K8S认证、授权与准入控制(RBAC)详解
- 基于 Laravel Auth 实现自定义接口 API 用户认证详解
- SpringBoot + Spring Security 学习笔记(二)安全认证流程源码详解
- 身份认证之双因素认证 2FA
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。