4.4.2 Kubectl的认证授权

概览
Kubelet的HTTPS端点对外暴露了用于访问不同敏感程序数据的API,并允许您在节点或者容器内执行不同权限级别的操作。

Kubelet认证
默认情况下,所有未被配置的其他身份验证方法拒绝的,对Kubelet的HTTPS端点的请求将被视为匿名请求,并被授予system:anonymous用户名和system:unauthenticated组。

如果要禁用匿名访问并发送401 Unauthorized的未经身份验证的请求的响应:

  • 启动kubelet时指定 —anonymous-auth=false标志

如果要对kubelet的HTTPS端点启用X509客户端证书身份验证:

  • 启动kubelet时指定 —client-ca-file标志,提供CA bundle以验证客户端证书
  • 启动apiserver时指定 —kubelet-client-certificate和 —kubelet-client-key标志

启用API bearer token(包括service account token)用于向kubelet的HTTPS端点进行身份验证:

  • 确保在API server中开启了authentication.k8s.io/v1beta1 API组。
  • 启动kubelet时指定 —authorization-mode=webhook、—kubeconfig和—require-kubeconfig标志
  • kubelet在配置的API Server上调用SubjectAccessReview API,以确定每个请求是否被授权

4.4.4 创建用户认证授权的kubeconfig文件

创建一个devuser用户并将其绑定到dev和test两个namespace为例说明。

创建CA证书和密钥
创建devuser-csr.json文件

  1. {
  2. "CN": "devuser",
  3. "hosts": [],
  4. "key": {
  5. "algo": "rsa",
  6. "size": 2048
  7. },
  8. "names": [
  9. {
  10. "C": "CN",
  11. "ST": "Beijing",
  12. "L": "Beijing",
  13. "O": "k8s",
  14. "OU": "System"
  15. }
  16. ]
  17. }

我们再在Master节点上为devuser创建证书和密钥,在/etc/kubernetes/ssl目录下执行如下命令:
执行该命令前请先确保该目录下已经包含如下文件:

ca-key.pem ca.pem ca-config.json devuser-csr.json
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes devuser-csr.json|cfssljson -bare devuser

这将生成如下文件:

devuser.csr devuser-key.pem devuser.pem

创建kubeconfig文件

#设置集群参数
export KUBE_APISERVER="https://172.20.0.113:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=devuser.kubeconfig

#设置客户端认证参数
kubectl config set-credentials devuser \
--client-certificate=/etc/kubernetes/ssl/devuser.pem \
--client-key=/etc/kubernetes/ssl/devuser-key.pem \
--embed-certs=true \
--kubeconfig=devuser.kubeconfig

#设置上下文参数
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=devuser \
--namespace=dev \
--kubeconfig=devuser.kubeconfig

#设置默认上下文
kubectl config use-context kubernetes --kubeconfig=devuser.kubeconfig

替换默认为的context配置:

cp -f ./devuser.kubeconfig /root/.kube/config

RoleBinding
使用RBAC创建角色绑定以将该用户的行为限制在某个或某几个namespace空间范围内,例如:

kubectl create rolebinding devuser-admin-binding --clusterrole=admin --user=devuser --namespace=dev
kubectl create rolebinding devuser-admin-binding --clusterrole=admin --user=devuser --namespace=test

这样devuser用户对dev和test两个namespace具有完全访问权限。

4.4.5 IP伪装代理

创建ip-masq-agent
使用如下命令创建ip-masq-agent:

kubectl create -f https://raw.githubusercontent.com/kubernetes-inclubator/ip-masq-agent/master/ip-masq-agent.yaml

为了仅允许ip-masq-agent考虑10.0.0.0/8,可以在名为config的文件中创建以下ConfigMap。

nonMasqueradeCIDRs:
  - 10.0.0.0/8
resyncInternal: 60s

运行如下命令将ConfigMap添加到集群中:

kubectl create configmap ip-masq-agent --from-file=config --namespace=kube-system

这将会更新/etc/config/ip-masq-agent文件,并每隔resyncInterval时间段检查一遍文件,将配置应用到集群的节点中。

要让ip-masq-agent忽略本地链路,可以在ConfigMap中将masqLinkLocal设置为true。

nonMasqueradeCIDRs:
  - 10.0.0.0/8
resyncInterval: 60s
masqLinkLocal: true

4.4.6 使用kubeconfig或token进行用户身份认证

使用kubeconfig(即证书)和token两种认证方式是最简单的认证方式。

以示例讲解两种认证方式:

  • 为brand命名空间下的brand用户创建kubeconfig文件
  • 为集群的管理员(拥有所有命名空间的admin权限)创建token

使用kubeconfig

生成token
需要创建一个admin用户并授予admin角色绑定,使用下面的yaml文件创建admin用户并赋予他管理员权限,然后可以通过token访问kubernetes。

生成kubernetes集群最高权限admin用户的token

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: admin
  annotations:
     rbac.authorization.kubernetes.io/autoupdate: "true"
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: admin
  namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin
  namespace: kube-system
  labels:
     kubernetes.io/cluster-service: "true"
     addonmanager.kubernetes.io/mode: Reconcile

执行命令创建serviceaccount和角色绑定:

kubectl create -f admin-role.yaml

4.4.7 Kubernetes中的用户与身份认证授权

认识Kubernetes中的用户
Kubernetes集群中包含两类用户:一类是由Kubernetes管理的service account,另一类是普通用户。

普通用户被假定为外部独立服务管理。管理员分发私钥,用户存储,甚至包含用户名和密码列表的文件。
Kubernetes中没有代表普通用户账户的对象,无法通过API调用的方式向集群中添加普通用户。

serviceaccount是由Kubernetes API管理的账户。它们都绑定了特定的namespace,并由API server自动创建,或者通过API调用手动创建。Service Account关联了一套凭证,存储在secret,这些凭证同时被挂载到pod中,从而允许pod与kubernetes API之间的调用。

API请求被绑定到普通用户或service account上,或者作为匿名请求对待。意味着集群内部或外部的每个进程,无论从在工作站上输入kubectl 的人类用户到节点上的kubelet,到控制平面的成员,都必须在向API Server发出请求时进行身份验证,或者被视为匿名用户。

认证策略
Kubernetes使用客户端证书、bearer token、身份验证代理或者HTTP 基本身份验证等身份认证插件来对API请求进行身份验证。当有HTTP请求发送到API Server时,插件会尝试将以下属性关联到请求上:

  • 用户名:标识最终用户的字符串。常用值可能是kube-admin或者jane@example.com
  • UID:标识最终用户的字符串,比用户名更加一致且唯一。
  • 组:一组将用户和常规用户组相关联的字符串。
  • 额外字段:包含其他有用认证信息的字符串列表的映射。

当启用了多个认证模式时,第一个认证模块成功认证后将短路请求,不会进行第二个模块的认证。API server不会保证认证的顺序。

system:authenticated 组包含在所有已验证用户的组列表中。

X509客户端证书
使用openssl命令工具生成用于签名认证请求的证书:

openssl req -new -key jbeda.pem -out jbeda-csr.pem -subj "/CN=jbeda/O=app1/O=app2"

静态Token文件
当在命令行上指定—token-auth-file=SOMEFILE选项时,API Server从文件读取bearer token。目前,token会无限期的持续下去,并且不重启API Server的话就无法更改令牌列表。

token文件是一个csv文件,每行至少包含三列:token、用户名、用户uid,其次是可选的组名。
如果有多个组,则该列必须使用双引号。

token,user,uid,"group1,group2,group3"

Service Account Token
Service Account是一个自动启用的验证器,它使用签名的bearer token来验证请求。该插件包括两个可选的标志:

  • —service-account-key-file : 一个包含签名bearer token的PEM编码文件。如果未指定,将使用API Server的TLS密钥。
  • —service-account-looup:如果启用,从API中删除掉的token将被撤销;

Service Account通常由API Server自动创建,并通过ServiceAccount注入控制器关联到集群中运行的Pod上。
Bearer token挂载到pod中众所周知的位置,并允许集群进程与API Server通信。
账户可以使用PodSpec的serviceAccountName字段显式的与Pod关联。

注意:ServiceAccountName通常被省略,因为这会自动生成。

apiVersion: apps/v1beata2
kind: Deployment
metadata: 
   name: nginx-deployment
   namespace: default
spec:
   replicas: 3
   template:
     metadata:
     # ...
     spec:
       containers:
       - name: nginx
         image: nginx:1.7.9
         serviceAccountName: bob-the-bot

Service account bearer token 在集群外使用也是完全有效的,并且可以用于为希望与Kubernetes通信的长期运行作业创建身份。要手动创建service account,只需要使用kubectl create serviceaccount(NAME)命令。这将在当前的namespace和相关联的secret中创建一个service account。

注意:所有值是基于base64编码的,因为secret总是基于base64编码。
经过签名的JWT可以用作bearer token 与给定的service account进行身份验证。
通常情况下,这些secret被挂在到Pod中,以便对集群内的API Server进行访问,但也可以从集群外访问。

Service account验证时用户名system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT),被指定到组system:serviceaccounts和system:serviceaccounts:(NAMESPACE)。

注意:由于service account的token存储在secret中,所以具有对这些secret的读取权限的任何用户都可以作为Service Account进行身份验证。授予Service account权限和读取secret功能时要谨慎。

4.4.8 Kubernetes集群安全性配置最佳实践

端口
注意管理好如下端口:

端口 进程 描述
4149/TCP kubelet 用于查询容器监控指标的cAdvisor端口
10250/TCP kubelet 访问节点的API端口
10255/TCP kubelet 未认证的只读端口,允许访问节点状态
10256/TCP kube-proxy kube-proxy的健康检查服务端口
9099/TCP calico-felix calico的健康检查服务端口(如果使用calico/canal)
6443/TCP kube-apiserver Kubernetes API端口