kubernetes从入门到放弃4--(安全机制)

Kubernetes作为一个分布式集群的管理工具,保证集群的安全性是其一个重要的任务。API Server是集群内部各个组件通信的中介,也是外部控制的入口。所以Kubernetes的安全机制基本就是围绕保护API Server来设计的。
Kubernetes使用了认证(Authentication)、鉴权(Authorization)、准入控制(Admission Control)三步来保证API Server的安全。

我的理解是,认证是保证访问双方都是可信的;鉴权是检查请求者是否有所访问资源的权限;准入控制是API Server的功能插件集合,可以为API Server添加一些额外的处理请求的功能。

一 认证

推荐的API Server配置是开启TLS,关闭匿名访问。

--insecure-bind-address=127.0.0.1 \
--kubelet-https=true \
--anonymous-auth=false \
--tls-cert-file=/etc/kubernetes/ssl/kubernetes.pem \
--tls-private-key-file=/etc/kubernetes/ssl/kubernetes-key.pem \

这样除了localhost访问外,如果没有受API Server信任的证书,就不能访问API Server。
Kubernetes提供的认证方式挺多:X509 Client Certs、Static Token File、Bootstrap Tokens、Static Password File、Service Account Tokens....具体看文档。在这里就提几个与证书访问相关的方式。

1.1 证书

TLS需要一个CA机构,用于给服务器和客户端发布证书。API Server基本只提供给集群内部访问,所以自签发一个CA根证书就好了。可以参考下kubeasz的创建CA证书和密钥
再来看看需要访问API Server的都有谁。

  • 管理员:使用kubectl或是UI界面(dashborad)访问
  • master节点:Controller Manager、Scheduler
  • Node节点:kubelet、kube-proxy、Pod容器中的进程

可以将他们大概分为两类:

  • Kubenetes组件对API Server的访问:kubectl、Controller Manager、Scheduler、kubelet、kube-proxy
  • Kubernetes管理的Pod对容器的访问:Pod(dashborad也是以Service形式运行)

先看看组件,Controller Manager、Scheduler与API Server在同一台机器,所以直接使用API Server的非安全端口访问,--insecure-bind-address=127.0.0.1
其他组件比如kubectl、kubelet、kube-proxy访问API Server就都需要证书了。

1.1.1 手动签发

其中kubectl、kube-proxy需要手动地用CA根证书签发。首先创建证书请求文件:

{
  "CN": "admin",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "HangZhou",
      "L": "XS",
      "O": "system:masters",
      "OU": "System"
    }
  ]
}

然后就可以向CA申请证书:

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

之后就可以在本地生成了三个文件:

  • admin.csr:证书请求
  • admin-key.pem:公钥
  • admin.pem:私钥

1.1.2 Bootstrap Tokens

kubelet可以使用Bootstrap Tokens,动态地让master分配证书。所谓Bootstrap Tokens就是创建集群时,API Server与kubelet约定好一个token,kubelet首次访问API Server时,使用token做认证,通过后,Controller Manager会为kubelet生成一个证书,以后的访问都是用证书做认证了。
使用Bootstrap Tokens,可以不用一个一个地为Node生成kubelet的证书,而只需要一个统一的token,可以方便集群的创建。关于Bootstrap Tokens,可以看看文档这篇博客。写到这里我有个疑问,如果Bootstrap Tokens是为了不用在创建集群时,一个个地为Node生成kubelet证书。那么同为运行在Node上的组件的kube-proxy为什么又需要先生成证书才能访问API Server呢.....

1.1.3 kubeconfig

有了证书之后,还需要生成kubeconfig文件。kubeconfig文件包含集群参数(CA证书、API Server地址),客户端参数(上面生成的证书和私钥),集群context信息(集群名称、用户名)。Kubenetes组件通过启动时指定不同的kubeconfig文件可以切换到不同的集群。kubelet的kubeconfig文件是通过Bootstrap Tokens获取到证书后生成的。关于kubeconfig的文档

1.1.4 ServiceAccount

上面提到的是Kubenetes组件访问API Server的情况,另一种情况是Pod中的容器访问API Server。因为Pod的创建、销毁是动态的,所以要为它手动生成证书就不可行了。Kubenetes使用了Service Account解决Pod 访问API Server的认证问题。
使用Service Account要在API Server启动时,带上--admission-controller=ServiceAccount参数。

1.1.4.1 Secret

Kubernetes设计了一种资源对象叫做Secret,分为两类,一种是用于ServiceAccount的service-account-token, 另一种是用于保存用户自定义保密信息的Opaque。我们在ServiceAccount中用到包含三个部分:Token、ca.crt、namespace。

  • token是使用API Server私钥签名的JWT。用于访问API Server时,Server端认证。
  • ca.crt,根证书。用于Client端验证API Server发送的证书。
  • namespace, 标识这个service-account-token的作用域名空间。
root@kube-1:~# kubectl get secret --all-namespaces
NAMESPACE     NAME                               TYPE                                  DATA      AGE
default       default-token-gnlqz                kubernetes.io/service-account-token   3         11d
kube-public   default-token-pcql2                kubernetes.io/service-account-token   3         11d
kube-system   default-token-5gm9r                kubernetes.io/service-account-token   3         11d
kube-system   kubernetes-dashboard-key-holder    Opaque                                2         11d

以上三个service-account-token都是系统默认添加的,会在每个namespace默认的ServiceAccount中使用。

root@kube-1:~# kubectl describe secret default-token-5gm9r --namespace=kube-system
Name:         default-token-5gm9r
Namespace:    kube-system
Labels:       <none>
Annotations:  kubernetes.io/service-account.name=default
              kubernetes.io/service-account.uid=99473738-64d1-11e8-80e9-fa163e39e787

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1346 bytes
namespace:  11 bytes
token:      eyjh......7FcRPVz0g

对token使用JWT解码,可以看到service-account-token的一些基本信息,会用于后续的鉴权。

再回过头来看看ServiceAccount,默认情况下,每个namespace都会有一个ServiceAccount,如果Pod在创建时没有指定ServiceAccount,就会使用Pod所属的namespace的ServiceAccount。

root@kube-1:~# kubectl describe sa default --namespace=kube-system
Name:                default
Namespace:           kube-system
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   default-token-5gm9r
Tokens:              default-token-5gm9r
Events:              <none>
  • Image pull secrets 用于指定pull镜像时的Secret。
  • Mountable secrets 指定需要挂载到Pod中的Secret。exec到容器中,就可以在目录中看到Secret的三个文件了。
    root@nginx-7587c6fdb6-bv84b:/# ls /run/secrets/kubernetes.io/serviceaccount/
    ca.crt  namespace  token
  • Tokens 指定用于访问API Server认证的Secret。

1.2 summary

简单总结下,基于TLS证书的API Server认证如下图所示:

二 鉴权

上面认证过程,只是确认通信的双方都确认了对方是可信的,可以相互通信。而鉴权是确定请求方有哪些资源的权限。在Kubernetes中,默认使用的,也是使用较多的是RBAC(Role-Based Access Control)。
RBAC定义了4个资源对象:Role、ClusterRole、RoleBinding、 ClusterRoleBinding。其中Role(ClusterRole)定义了一个角色(集群角色)在namespace(clutser)范围内对某些资源的操作权限。RoleBinding(ClusterRoleBinding)将用户、组、ServiceAccount同角色进行绑定,绑定的账户就拥有了角色(集群角色)所指定的权限。

需要注意的是Kubenetes并不会提供用户管理,那么User、Group、ServiceAccount指定的用户又是从哪里来的呢?

  • Kubenetes组件(kubectl、kube-proxy)或是其他自定义的用户在向CA申请证书时,需要提供一个证书请求文件:
    root@kube-1:~# cat /etc/kubernetes/ssl/admin-csr.json 
    {
      "CN": "admin",
      "hosts": [],
      "key": {
        "algo": "rsa",
        "size": 2048
      },
      "names": [
        {
          "C": "CN",
          "ST": "HangZhou",
          "L": "XS",
          "O": "system:masters",
          "OU": "System"
        }
      ]
    }
    

    API Server会把客户端证书的CN字段作为User,把names.O字段作为Group。

  • kubelet使用TLS Bootstaping认证时,API Server可以使用Bootstrap Tokens或者Token authentication file验证token,无论哪一种,Kubenetes都会为token绑定一个默认的User和Group。相关文档

  • Pod使用ServiceAccount认证时,service-account-token中的JWT会保存User信息。

有了用户信息,再创建一对角色/角色绑定(集群角色/集群角色绑定)资源对象,就可以完成权限绑定了。使用 RBAC 控制 kubectl 权限这篇博文的列子把这一过程解释的很清楚。

三 准入控制

准入控制是API Server的插件集合,通过添加不同的插件,实现额外的准入控制规则。甚至于API Server的一些主要的功能都需要通过Admission Controllers实现,比如ServiceAccount。
官方文档上有一份针对不同版本的准入控制器推荐列表,其中最新的1.9和1.10的推荐列表是:

NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota

列举几个插件的功能:

  • NamespaceLifecycle: 防止在不存在的namespace上创建对象,防止删除系统预置namespace,删除namespace时,连带删除它的所有资源对象。
  • LimitRanger:确保请求的资源不会超过资源所在Namespace的LimitRange的限制。
  • ServiceAccount: 实现了自动化添加ServiceAccount。
  • ResourceQuota:确保请求的资源不会超过资源的ResourceQuota限制。
Comments
Write a Comment