Kubernetes 学习15 kubernetes 认证及serviceaccount

一、概述

  1、通过此前描述可以知道k8s是以后运行我们生产环境中重要应用程序的尤其是无状态程序的一个非常重要的平台。这里面能托管一些核心应用以及核心数据,很显然对于k8s对应接口的访问不是任何人都可以轻易使用的,比如kubectl 这种工具进行访问,如果人人都可以通过kubectl 进行访问那么很显然它能够随意操作我们的应用程序,这是非常危险的,因此k8s对于我们整个系统的认证,授权和访问控制等做了非常精密和精心的设计,考虑到k8s诞生到今天为止还不算太长,但是到目前为止模型设计上已经做的足够安全了。整个k8s集群来说我们apiserver是作为访问控制的唯一入口,如果我们在上面部署了应用程序后通过ingress或者通过service把他们暴露出去之后它是不需要apiserver访问的,它是通过我们节点的nodeport 或者通过我们ingress中ingress controall定义的daemoset 共享宿主机节点网络名称空间监听的宿主机地址,也就是我们的节点空间监听的宿主机的地址,也就是我们的节点地址,直接进入即可。我们作为部署的pod的容器中的应用程序的客户端他们的访问无需经过apiserver,apiserver是我们作为管理平台上的对应的我们部署的各种资源对象而使用的,我们也讲过,apiserver中的api他们还是分了群组的,他们还可以自动做迭代,但是不管怎么讲任何用户试图到这个平台上来操作资源对象时他们必须要经历三种安全相关的操作

    a、认证:任何客户端在经由apiserver做操作之前得先完成认证操作,也就意味着用户得有访问k8s的正确的账号和能够通过安全认证才可以

    b、授权:认证通过以后只是证明他是一个合法的当前系统用户,它是否拥有删除对应资源的权限还需要做授权检查。

    c、准入控制:授权检查完以后貌似我们已经可以操作某些资源了,但是有些资源的操作还要关联到其它资源和相应的环境才能满足他的兼容条件,因此,一个授权操作对于某个资源对象要做的操作虽然用户获得授权但是关联到的其它资源是否有权限呢?以及他是不是在我们指定的操作范围内,还有第三关检查机制,我们称为准入控制。意思是你虽然得到了授权但是这次操作因为要关联到其它的资源或者是其它相关操作我是不是允许你执行这个操作就有准入控制的检查。

    

二、三种安全相关操作

  1、认证:k8s是高度模块化设计的,因此他的认证授权和准入控制各自都通过插件的方式可由用户自定义选择用什么样的插件来完成何种控制逻辑,比如说对认证来讲他可能有n个认证插件,支持多种不同的认证方式。

    a、令牌认证:我们可以支持令牌认证,令牌认证是指双方有一个域共享秘钥,服务端存在的密码就像mysql一样,我们在服务器上事先先创建一个密码存下来随后在登陆时就拿这个密码登陆,这种登陆方式就称之类似于秘钥登陆方式,而且叫对称秘钥认证方式,但是由于k8s提供的是restful 风格的接口,他的所有服务都是通过http协议提供的,因此我们认证信息只能经由http协议的认证守护进行传递,这种认证守护在传递时我们通常称为叫做认证令牌 (token),此处我们可以称为承载令牌,因为他要经历我们的http协议的守护来实现从客户端,kubectl要拿着这个令牌转为http协议来传输并发给apiserver并由apiserver进行认证。这是最简单的认证方式。这种认证一般就是双方只需要交换一下是否拥有域共享秘钥就足够了。

    b、ssl认证:对于k8s访问来讲,ssl认证能让我们客户端去确认服务器的身份,大家知道我们去和服务器通信之前先要求服务器发一个服务器的证书过来我们先看一看这个证书是否是我们认可的ca签署的。如果是我们认可的ca签署的而且里面的信息也就是subject信息与服务器的访问目标主机保持一致那么就认为这个服务器的身份得到认证了,反过来,在k8s通信中重要的是服务器还要认证客户端的身份,因此,kubectl自己也应该有一个证书,也应该有一个私钥,而且这个证书也必须是server端所认可的ca所翻发的证书,更重要的是,客户端身份也要与我们证书当中标识的身份保持一致。所以双方都需要做双向证书认证。认证完以后他们还可以基于ssl会话实现加密通信,也就意味着二者要通过https进行通信了。

    c、认证插件可能有很多,但是用户经过任何一个认证插件通过以后即表示认证通过,无需再经由其它插件检查就进入授权阶段。

  2、授权:也支持n中授权插件来完成用户的权限检查,kubernetes 1.6之后开始支持基于RBAC的认证,此前有ABAC之类的认证,比如基于属性的访问控制,现在用的比较广泛的而且我们认为比较安全的方式叫RBAC,除此之外他还有node认证(基于节点的认证),还有webhook基于我们http协议回调机制通过web的rest服务来实现认证的检查机制。

    a、RBAC:其中最重要的就是RBAC(基于角色的访问控制机制)的授权检查机制,这种机制通常只有许可授权没有拒绝授权,因为默认都是拒绝的,我们只是许可这个用户能操作什么什么。默认情况下我们使用kubeadm 这个工具部署的kubernetes集群是强制启用了RBAC认证的。我们到今天为止还没有涉及到所谓授权操作控制逻辑,我们一直在使用我们k8s的最高管理权限系统管理员来进行操作,而不是普通用户,随后,如果我们要使用admin这样的用户,或者使用一个普通用户你会发现很有可能用户只有只读权限,只能看见我们有哪些资源对象而无法编辑,删除,创建。甚至其只能看到一个名称空间的资源对象,因此RBAC可以定制的非常非常灵活。用户经过任何一个插件授权通过以后都可以表示获得了访问控制权限,因此RBAC,ABAC,node,webhook等等可以同时启用都是没有问题的

    b、当然我们也可以定义比较独特的访问控制逻辑,比如alwaysdeny(什么都不被允许),alwaysall(什么都允许)等等。

  3、准入控制:准入控制本身只是用来定义和对应授权检查完成以后的后续的其它安全检查操作,了解即可。

三、从用户的请求操作来讲,客户端对API server发起请求,API server要识别这个用户到底有没有请求的权限,要识别这个用户本身能不能通过API server来执行相应的操作,需要哪些信息来识别用户的所有相关信息才能完成对用户的访问控制

  1、user: username,uid

  2、group

  3、extra(提供额外信息)

  4、更重要的是,这个用户账号拿着信息去请求的时候一定会请求某个特定的API资源,而k8s的API server是分了组的,所以到底向哪个组的哪个版本的哪个API资源对象发起请求我们这里必须要进行标识,而标识则通过用户在http中,因为其是restful请求,因此其所有的请求资源都是通过靠一个所谓的url path来进行标识,比如我们要去请求default名称空间下一个叫做myapp-deploy的deployment控制器,其访问路径就应该是/apis/apps/

apis为访问入口,api组叫apps,apps组下面现在一般有三个版本,可通过kubectl api-versions来查看

[root@k8smaster docker]# kubectl api-versions
admissionregistration.k8s.io/v1beta1
apiextensions.k8s.io/v1beta1
apiregistration.k8s.io/v1
apiregistration.k8s.io/v1beta1
apps/v1
apps/v1beta1
apps/v1beta2
authentication.k8s.io/v1
authentication.k8s.io/v1beta1
authorization.k8s.io/v1
authorization.k8s.io/v1beta1
autoscaling/v1
autoscaling/v2beta1
batch/v1
batch/v1beta1
certificates.k8s.io/v1beta1
events.k8s.io/v1beta1
extensions/v1beta1
networking.k8s.io/v1
policy/v1beta1
rbac.authorization.k8s.io/v1
rbac.authorization.k8s.io/v1beta1
scheduling.k8s.io/v1beta1
storage.k8s.io/v1
storage.k8s.io/v1beta1
v1

    可以看到apps下有三个版本并存,我们自己定义资源时,用哪个版本我们对应的 大家知道我们每一次创建一个资源对象都有apiversion的定义,所以如果自己使用的版本是apps/v1那么就在apps/v1下去找,若是其它版本则到对应版本下去找,这也是k8s的一个重要特性,它允许同一个群组下的多版本同时并存,这样才能向前兼容老的版本,因为很可能1.9的时候才能支持到v1beta1,1.10的时候才能支持到v1beta2,因此我们早些时候在1.9上创建的资源配置清单到1.11上如果只保留v1版本的可能不支持。多版本并存的时候这几个版本下的资源可能都有deployment,但是他们可能略有区别,因为beta阶段的api级别版本大家知道我们任何的应用程序通常在定义版本级别时有阿尔法,贝塔,stable,阿尔法一般是内测,这种版本一般来讲很有可能随时会被废弃掉,因此默认情况下在k8s上阿尔法版本都是禁用的,万一使用了下一个版本这个api废了都有可能,所以一般能拿来公开使用的只有贝塔版本。对于贝塔版本来讲他也不是不变化的,但是变化的不是资源对象本身,只是资源对象可能多一个属性,真正将来迭代到稳定版本时它可能少了或多了一个属性,或属性定义要求格式不一样,但只是略微的细小变化,因此,v1中虽然有deployment,v1beta2中也有,但v1beta2中的定义不一定完全兼容,只不过我们在1.9上使用v1beta2定义的,到1.11上这儿可以用,因为它这个api还存在。

    比如我们在 /apis/apps/v1 一般而言我们资源要么属于名称空间要么属于集群,所有名称空间级别的资源我们都应该指明namespaces,并给上namespaces的名称。

    /apis/apps/v1/namespaces/default/deployments/myapp-deploy/  #表示在apis访问入口的apps访问组下的v1版本下的名称空间叫default的deployments下名称为myapp-deploy的资源,这就是他的url,我们可以对这个url发起增删改查,增的时候基于这个url去创建一个资源对象,当我们需要删除时向这个url请求就行,请求方式为对   http://192.168.10.10:6443/apis/apps/v1/namespaces/default/deployments/myapp-deploy/这个链接发送相应请求

四、相关操作

  1、kubectl proxy:这是kubectl 自带的一个功能,首先,kubectl自身拥有认证能力,我们在本地配置好了他自带的配置文件中拥有认证信息。我们刚使用我们kubeadm部署好集群以后要求我们复制一个配置文件到当前用户的家目录下叫  .kube/config ,这里面就包含了客户端证书和客户端私钥,之所以每次用kubectl时不需要做认证是因为这些认证信息自动用命令进行过了,随时带的有认证信息。

[root@k8smaster ~]# cat /root/.kube/config 
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1EVXdPREV3T
URFeU5Gb1hEVEk1TURVd05URXdNREV5TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTHdQCm1YZkU4M2dsdG1jWjJqTnltVVBFWDk5bE1LNVR2RGh6eU11bFY0S0NZa0VaSXA1Nk0ybGVDaWIwNTU1M2xMZFMKV0dpMFRFUmVJV0sxNXVEVFVad0RrNDFvYXRqY2xYVHhwK3hXVGxsdVpmbksyeWlkY1I0ejU3VjY5VHJBdksyUApyTk1RczlxbnQ2Q052WTNuM2NkdnZxeW1GbmdkTzBqdWlsd09ieHVBVW1oNFNxM0FOdS9QemtSa3M2dlJYSXdjCml3aU5yM2V2YmFraE5yKzljT0xtcmFlUGFDcTY2eHB1U29NZVAvaWUyMUpCaFllWlMwZk9yUGdPL1p0YlpHQ28KR213VGp4OGpmK2hPYlBqcitmV3NWNGk0SityOHBzS3pUek44alF1anFsbm90RllYWm9TZDAyUUwwUzVIK21aUQpVMDg0NkVtaTZtbmt0UFo3ZzhzQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFCSlRGcExHMHZxUlNMRFhRWTZaZU5jcjIzSE4KUlp2OUs3bGlUYklNRHR6aDdYM2FSdVJqSUcyZklWUjVFa0lyazdnb1lHNlI3Y1RIejM2YkJSV3gxQTQ2di81cQpXdWloa0lSQ1BpVkYzWTREQitoeU9oRE5uYnlNU2RFa1poRlJ6RUIrN2dCQXp0ek1hS1dBU3pHYS81d3NuZGtUCmRLWExjdXc4aENuWHBwYmhVaU91Y3BRcVNCdDF0T1hwbkdjUlFQdklCQThMTFZvdEtCL1E0aUhQVmVkakV4VHIKUHVzT2x2clNOV2R4b0tVaE9Lc0dMMkNrNlN5MmthV0I1K0F4Y3V3NjZZQmpKdE82Q0NPSThUbCt4aHo3ZzVMRwo2bHlNOTZXR3ZrbWs3Nm96MzVKMGRqSmlTRkcvZTdpV044SGpRbDdaT1FyRVVabmM0NlRqTHpDcGQ0Zz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=    server: https://192.168.10.10:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJVlNST093YmJHdzh3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T1RB
MU1EZ3hNREF4TWpSYUZ3MHlNREExTURjeE1EQXhNamxhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXIrMUxOVWRZNndQUy80YzAKay9RemRVbnJUYU14VUhwWmVYT0FoWEtHaUNBcHQ5dGxPaG9YaGxGVmxNS1pmNHZ2czNnblZGQ1M1NEVIYk1PQgpLVnVva2F1TEo1NkFvY0V4Y1hMWFRqQnFLTVpFeTdGY3N6dzcwQmZHRGVlRy9DMXBhK1ViaWxkOVBKZmFiSWRNClJIbGRvYjZibzlGYUh4cjVhYkpxVDJGRHJCcHc1L1ZJWExCQSsrT3l4QmtBZ0FETEZ4S0UrN2RQREk4MHlyM0gKUWJWRHkwb0pFWksxSFZwMnpxcHhacDZGL0RIMElmMC9SQ0NUMW9vWG5FSEZScWJSeEFWUDdqTkdmQXljNFZiUwoyby9qRXZENlh0NVJJUjZpZkZ5N25ja0lyQ3pxSzJMZVliR3EzazM3VVRZRWdZWXU2OEZhWHg5S3ZRWWhrME9kCmN3SnJBUUlEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFGMmg0Wkk3aUVlbTF1RFloLzFvY1puTEg1Mmk4a2NLcHJ1TQpIbWlRdU05dmFpYUU4VEdTU1BBR0RCZXNKbXllbFhXSCtSYm5nQjhEQlowMHlUTjZSUVFQR1o2K2N6eVBtL1NRCjFPWHcrUGN2Y3dhMk9EMDk0dUZSOWR1NnJaUFFNZ0luc1Y1MFY3aWtNREFRcXNlZHJackFrcVhTdUpXMmVlVmcKdDY1eW40S2FvOW1hOXJCYWpnK1Fid0p0RjFRWjNPdFUwVnphcUxqZDc0NW9CdENyZHpsY2dZV2l1OVZTUXlWZQpjVDh5SDlMMEVmOVZUNXE3RUVoalVjTThYbDVKNi92K2hsQVh2ZElFRXYxeGZLNVVjRTI4bDFXT3FHUVNqQnBjCm5HNUlIYjVDWFZoV05obEI5SCtXSEwxSlBFdzZrMm1sc0hJKzZUcnJ2UjhrNlZFYTRRWT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=    client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBcisxTE5VZFk2d1BTLzRjMGsvUXpkVW5yVGFNeFVIcFplWE9BaFhLR2lDQXB0OXRsCk9ob1hobEZWbE1LWmY0dnZzM2duVkZDUzU0RUhi
TU9CS1Z1b2thdUxKNTZBb2NFeGNYTFhUakJxS01aRXk3RmMKc3p3NzBCZkdEZWVHL0MxcGErVWJpbGQ5UEpmYWJJZE1SSGxkb2I2Ym85RmFIeHI1YWJKcVQyRkRyQnB3NS9WSQpYTEJBKytPeXhCa0FnQURMRnhLRSs3ZFBESTgweXIzSFFiVkR5MG9KRVpLMUhWcDJ6cXB4WnA2Ri9ESDBJZjAvClJDQ1Qxb29YbkVIRlJxYlJ4QVZQN2pOR2ZBeWM0VmJTMm8vakV2RDZYdDVSSVI2aWZGeTduY2tJckN6cUsyTGUKWWJHcTNrMzdVVFlFZ1lZdTY4RmFYeDlLdlFZaGswT2Rjd0pyQVFJREFRQUJBb0lCQUNYUDlPaEFxNFhuem9RSgpoVzEvZ1VmbVdXTFlmcEx6bVNPWGhib3BBVzFrckZMT0h4Vzc0ZTZHc01SR2gwTjR5azVpdHVGU2FDREdCTmlGCnRNODAyaWhsSElXcGRiQk9tOWZzZlFaYk5aWUo5Mk5vZmFvd2VoS2g2WG0zbDdXLzlQYXh5WmVVY21DQnF2ckUKb2NuZDVCZ05wZG94OXhMVWMyTWFhK3NmMXJHNHFkcWFLYTFNK2J3VUJ1SDYxVkFGVEJzdm5sUmNpTElJNWtPVQpWMjVEa2p0S0E4QTlRT2R5VGdZUGFWaG1NQzZ5VkNOOS9zUVk2MXk4b3NkRmJnMXE4LzRJOTJKNFp1amlEVmtKCmVRclJMdUs0eWJjLzNEbEdsSE9rdVZ4d3A0WWljaXBlaGVPQW9lRUQ4dTJWang3b2Q2MHZPRUdUMisweHgrMTAKTDU2bEdQa0NnWUVBM1BrQWwwOG43M0tNUG9UMTd6RjE1dVZVNGhWYlZvdnZJRTRPdjBTNndlYm9FRSsxbGVKSQo2SVRqbUJNL0RxT2lPaXU3K2dHMEd1MTVnU3J1TUFzNit2MG0reUIyZVhCSmYxQmlFZElpRHFYQnNIYnZLNVpECkpFMHlYbE1IeW9OWXM4RGF1NEVXRXRqL2tGaW1QTWV0QWRINTNTb0t4azlwYlVrbCtMaGtIbk1DZ1lFQXk5QloKc3JMQ1lrOW9NWEJJNnp3YVd1OVdjK2JzMWREanJxRitUbXQrdTZJNWYxQkI3bFJxNk1DSlVvT0s3WklFd0pTZgpGSlp1Rk5tbk9TT0FWdjBhTE9kclEzblFRaXcwSGlERlVYbW1QMTFPZDZycDBDUFZCeVBXLy9jVXhZRnlQN1RaCjZqWE1ZbUNVWTVuTERSc282ZE9jYlR4cm5kRCtSMVRvdk1hKzM3c0NnWUVBMmFlbXptTlltY0dCcEg5QTQ1Y2IKWkJCV09NOENoZEFWL1FNR0FaNUlPb0FmNnhrb2FuZFdpem1DR0tRMGcwM29tRlhGdFc4Q0lWZnlTNm1tcmNvUwpFWEZUZVI2enM5QkhoTkQvbUVBYjdjT1ZjaVRrVmxHTzF1MzNBL1BUQThXMmxIQU13NDVWMk1ESGtqM1BtS1N4Cm84NVl5R0VGOWVuNGxYM3NtZjIrR0VNQ2dZQjBjMDNjeVVCQk5ZZWR2NzhhRUpRcVl0ZHRqNExBUkFMaTgwaWMKZTlURVZsTXR4K2h6eU8zd29KbVZlSzAzUWhmUEJOdkR3cE9RL0M4TWVabEptb0dMS0lwajJrVEFta3NJNzhadAozK2k2Q1pEYzFOMlUyL1JLaVJLOTJ5bVdFM2o0cDFkZTkzQVl3WC9uVEtiMGpSRWFVSnJ1MnZmT0N1eE9TMWhUCkMrZGhJd0tCZ1FETWhIUjZSb0dZSVpQZmZORnVIbUlaZVpJNTZnMVI4eDc5a3kvbVpWSWYzQ0cvVXd4WWgvY0EKQk9DV0dlR1JkQVNUQmgyVENzNWx4QVdlTTQzSDFFYjVBdERPWWFHYndERS9SRTg4VTJIcnc1bHJ6YkZZaGNRMgpEVTFkQVZwWTk5emFMbkNiNitESTNKSjZSNnQyd1dCc1NSa1NQeWsvS2x5MEFhUGVMdGtPVEE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=

  2、所以我们使用kubectl 不需要认证但是我们使用curl时是需要认证的。kubectl是允许远程的,只要把其配置文件复制走,在另外的节点上安装好kubectl,我们让我们需要使用curl节点运行kubectl proxy命令,他在本地作为服务器运行的,它监听在自己指定的端口上,比如127.0.0.1:8080,随后使用curl命令就访问本地的8080端口,这个对8080端口的访问是怎么访问的呢?是由我们的kubectl 反向代理至 apiserver,它与apiserver之间进行认证,这样我们curl与kubectl proxy之间就不需要认证

[root@k8smaster /]# nohup kubectl proxy --port=8080 &
[1] 103524
 
[root@k8smaster /]# netstat -anpt|grep 8080
tcp        0      0 127.0.0.1:8080          0.0.0.0:*               LISTEN      103524/kubectl      
tcp        0      0 10.244.0.1:40836        10.244.0.20:8080        TIME_WAIT   -                   
[root@k8smaster /]# curl http://localhost:8080/api/v1/namespaces #可以看到列出了我们集群中的名称空间信息
{
  "kind": "NamespaceList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/namespaces",
    "resourceVersion": "1149390"
  },
  "items": [
    {
      "metadata": {
        "name": "default",
        "selfLink": "/api/v1/namespaces/default",
        "uid": "5928b0ed-7178-11e9-be24-000c29d142be",
        "resourceVersion": "18",
        "creationTimestamp": "2019-05-08T10:02:11Z"
      },
      "spec": {
        "finalizers": [
          "kubernetes"
        ]
      },
      "status": {
        "phase": "Active"
      }
    },
    {
      "metadata": {
        "name": "ingress-nginx",
        "selfLink": "/api/v1/namespaces/ingress-nginx",
        "uid": "66c3137b-8d7a-11e9-b839-000c29d142be",
        "resourceVersion": "543048",
        "creationTimestamp": "2019-06-13T01:27:26Z",
        "annotations": {
          "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"ingress-nginx\",\"namespace\":\"\"}}
\n"        }
      },
      "spec": {
        "finalizers": [
          "kubernetes"
        ]
      },
      "status": {
        "phase": "Active"
      }
    },
    {
      "metadata": {
        "name": "kube-public",
        "selfLink": "/api/v1/namespaces/kube-public",
        "uid": "59359501-7178-11e9-be24-000c29d142be",
        "resourceVersion": "41",
        "creationTimestamp": "2019-05-08T10:02:11Z"
      },
      "spec": {
        "finalizers": [
          "kubernetes"
        ]
      },
      "status": {
        "phase": "Active"
      }
    },
    {
      "metadata": {
        "name": "kube-system",
        "selfLink": "/api/v1/namespaces/kube-system",
        "uid": "5933f410-7178-11e9-be24-000c29d142be",
        "resourceVersion": "40",
        "creationTimestamp": "2019-05-08T10:02:11Z"
      },
      "spec": {
        "finalizers": [
          "kubernetes"
        ]
      },
      "status": {
        "phase": "Active"
      }
    }
  ]
}

  3、访问coredns的deployment,对于deployment来讲其属于apps群组,事实上对于整个k8s来讲所有的api都起源于一个根apis,表示api的复数,刚才之所以能用api是因为它是一个特殊的链接,只有核心群组才有这样的访问逻辑,不是核心群组的都要起始于apis

[root@k8smaster /]# curl http://localhost:8080/apis/apps/v1/namespaces/kube-system/deployments/
{
  "kind": "DeploymentList",
  "apiVersion": "apps/v1",
  "metadata": {
    "selfLink": "/apis/apps/v1/namespaces/kube-system/deployments/",
    "resourceVersion": "1150541"
  },
  "items": [
    {
      "metadata": {
        "name": "coredns",
        "namespace": "kube-system",
        "selfLink": "/apis/apps/v1/namespaces/kube-system/deployments/coredns",
        "uid": "5c037db1-7178-11e9-be24-000c29d142be",
        "resourceVersion": "970930",
        "generation": 1,
        "creationTimestamp": "2019-05-08T10:02:16Z",
        "labels": {
          "k8s-app": "kube-dns"
        },
        "annotations": {
          "deployment.kubernetes.io/revision": "1"
        }
      },
      "spec": {
        "replicas": 2,
        "selector": {
          "matchLabels": {
            "k8s-app": "kube-dns"
          }
        },
        "template": {
          "metadata": {
            "creationTimestamp": null,
            "labels": {
              "k8s-app": "kube-dns"
            }
          },
          "spec": {
            "volumes": [
              {
                "name": "config-volume",
                "configMap": {
                  "name": "coredns",
                  "items": [
                    {
                      "key": "Corefile",
                      "path": "Corefile"
                    }
                  ],
                  "defaultMode": 420
                }
              }
            ],
            "containers": [
              {
                "name": "coredns",
                "image": "k8s.gcr.io/coredns:1.1.3",
                "args": [
                  "-conf",
                  "/etc/coredns/Corefile"
                ],
                "ports": [
                  {
                    "name": "dns",
                    "containerPort": 53,
                    "protocol": "UDP"
                  },
                  {
                    "name": "dns-tcp",
                    "containerPort": 53,
                    "protocol": "TCP"
                  },
                  {
                    "name": "metrics",
                    "containerPort": 9153,
                    "protocol": "TCP"
                  }
                ],
                "resources": {
                  "limits": {
                    "memory": "170Mi"
                  },
                  "requests": {
                    "cpu": "100m",
                    "memory": "70Mi"
                  }
                },
                "volumeMounts": [
                  {
                    "name": "config-volume",
                    "readOnly": true,
                    "mountPath": "/etc/coredns"
                  }
                ],
                "livenessProbe": {
                  "httpGet": {
                    "path": "/health",
                    "port": 8080,
                    "scheme": "HTTP"
                  },
                  "initialDelaySeconds": 60,
                  "timeoutSeconds": 5,
                  "periodSeconds": 10,
                  "successThreshold": 1,
                  "failureThreshold": 5
                },
                "terminationMessagePath": "/dev/termination-log",
                "terminationMessagePolicy": "File",
                "imagePullPolicy": "IfNotPresent",
                "securityContext": {
                  "capabilities": {
                    "add": [
                      "NET_BIND_SERVICE"
                    ],
                    "drop": [
                      "all"
                    ]
                  },
                  "readOnlyRootFilesystem": true,
                  "allowPrivilegeEscalation": false
                }
              }
            ],
            "restartPolicy": "Always",
            "terminationGracePeriodSeconds": 30,
            "dnsPolicy": "Default",
            "serviceAccountName": "coredns",
            "serviceAccount": "coredns",
            "securityContext": {
              
            },
            "schedulerName": "default-scheduler",
            "tolerations": [
              {
                "key": "CriticalAddonsOnly",
                "operator": "Exists"
              },
              {
                "key": "node-role.kubernetes.io/master",
                "effect": "NoSchedule"
              }
            ]
          }
        },
        "strategy": {
          "type": "RollingUpdate",
          "rollingUpdate": {
            "maxUnavailable": 1,
            "maxSurge": "25%"
          }
        },
        "revisionHistoryLimit": 10,
        "progressDeadlineSeconds": 600
      },
      "status": {
        "observedGeneration": 1,
        "replicas": 2,
        "updatedReplicas": 2,
        "readyReplicas": 2,
        "availableReplicas": 2,
        "conditions": [
          {
            "type": "Progressing",
            "status": "True",
            "lastUpdateTime": "2019-05-09T01:37:06Z",
            "lastTransitionTime": "2019-05-09T01:37:06Z",
            "reason": "NewReplicaSetAvailable",
            "message": "ReplicaSet \"coredns-78fcdf6894\" has successfully progressed."
          },
          {
            "type": "Available",
            "status": "True",
            "lastUpdateTime": "2019-07-03T01:58:48Z",
            "lastTransitionTime": "2019-07-03T01:58:48Z",
            "reason": "MinimumReplicasAvailable",
            "message": "Deployment has minimum availability."
          }
        ]
      }
    }
  ]
}

  4、HTTP request verb(动作)有哪些呢:get ,post,put,delete,要将这些请求方法转换成对api对象的请求,我们具体的操作有 get,list(列出,既能列出一个对象又能列出一组对象),create,update(修改),patch(打补丁),watch(监视),proxy(代理),redirect(重定向),deletecollection(删除)

  5、Resource:请求的资源,subresource:子资源,namespace:名称空间,API group:所述的API群组,刚才整个Request path把这些都表达进来了。

五、在k8s上需要与apiserver打交道的组件或客户端

  1、在k8s中运行的pod,比如我们运行的coredns这种系统管理级的addons(附件)需要与apiserver打交道。

  2、我们还会安装一个apiserver的或者说整个k8s的图形控制接口叫dashbond,其自身也是个Pod,它可以通过service暴露到外部,可以通过浏览器打开它,并去访问这个dashbond,而我们有可能通过此dashbond在当前集群中去增删改查资源,也就意味着我们要去通过这个pod要去创建其它pod,或者其它名称空间都有可能,很明显这种操作也需要与apiserver进行交互。

  3、所以我们发现我们与apiserver打交道的客户端有两类,第一类是我们一直在用的集群之外的客户端,这种客户端我们每次访问apiserver时都使用我们apiserver监听的节点地址,所以要通过apiserver的对外通信的监听地址来与外部客户端进行通信。那么我们在集群之上的客户端与apiserver进行通信时要怎么通信呢?pod有pod的网络,因此它与apiserver通信时用的是另外一个地址,apiserver还有一个专用在集群内的工作地址,可以使用kubectl get svc查看到

[root@k8smaster ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   61d

[root@k8smaster ~]# kubectl describe svc kubernetes #我们可以看到将集群外部的服务引入到集群内部
Name:              kubernetes
Namespace:         default
Labels:            component=apiserver
                   provider=kubernetes
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP:                10.96.0.1
Port:              https  443/TCP
TargetPort:        6443/TCP
Endpoints:         192.168.10.10:6443
Session Affinity:  None
Events:            <none>

    通过这种方式我们pod就可以直接请求我们apiserver服务了,因此pod请求api服务就是通过请求10.96.0.1来进行的。但是不要忘了,我们apiserver是需要做认证的。

    a、首先apiserver要把自己的证书传递给客户端,客户端去校验服务端(apiserver)身份,同时apiserver还要去校验客户端身份,这样就比较麻烦了,也就意味着服务器apiserver发给每一个pod客户端的时候他的证书中所标明的自己的身份不能再是192.168.10.10这个地址,这个地址应该是10.96.0.1,所以在我们的apiserver上自己手动建证书必须要确保证书持有者名称能解析到两条A记录,这两个地址都要能访问进来,或者干脆使用ip地址,这两个地址都要包含进来,意思是我只要发起证书以后验证身份是10.96.0.1时里面有,是192.168.10.10时里面也有才可以。这是第一点。

    b、第二点,我们pod客户端也需要证书,apiserver也需要验证客户端,apiserver的核心功能就是验证客户端,不然谁都能操作,因此任何pod客户端访问apiserver时只要需要与apiserver打交道那么就必须要认证,我们使用kubectl时给其提供配置文件进行认证,pod和其打交道怎么认证呢?比如我们pod中配置的是一个nginx,这个nginx开发不可能说是我事先内置的,因此,认证不可能是内部的应用程序来提供,而是应该由pod来提供,问题是靠什么来提供的?我们每创建一个pod资源时,我们的 pod.spec下有个serviceAccount(现在已经废除了),现在已经用serviceAccountName(服务账号名称)代替,服务账号就是让pod去连接apiserver时使用的账号,整个k8s的api账号有两类,第一类叫实实在在的现实中的人这类用户,第二类用户叫pod客户端。kubectl自己不会去访问一般来讲是人发起去访问的,可以写个脚本,叫人类用户,第二类用户叫pod用户客户端,人用的账号叫userAccount,pod去连接apiserver时使用的账号叫serviceAccount,事实上每一个pod都需要与apiserver打交道,只不过其权限有大有小而已,因此在每一个pod运行时他默认会有相关信息

[root@k8smaster manifests]# kubectl get pods
NAME                            READY     STATUS    RESTARTS   AGE
liveness-httpget-pod            1/1       Running   9          56d
myapp-deploy-67f6f6b4dc-76ddb   1/1       Running   0          1m
myapp-deploy-67f6f6b4dc-dfdjv   1/1       Running   0          1m
myapp-deploy-67f6f6b4dc-gjlqd   1/1       Running   0          1m
[root@k8smaster manifests]# kubectl describe pods myapp-deploy-67f6f6b4dc-gjlqd
Name:               myapp-deploy-67f6f6b4dc-gjlqd
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               k8snode1/192.168.10.11
Start Time:         Tue, 09 Jul 2019 16:05:42 +0800
Labels:             app=myapp
                    pod-template-hash=2392926087
                    release=canary
Annotations:        <none>
Status:             Running
IP:                 10.244.1.149
Controlled By:      ReplicaSet/myapp-deploy-67f6f6b4dc
Containers:
  myapp:
    Container ID:   docker://003f24a0b6dada95b0f188de4a25c805f93a15fe749466fd64edd7f4649f55fa
    Image:          ikubernetes/myapp:v2
    Image ID:       docker-pullable://ikubernetes/myapp@sha256:85a2b81a62f09a414ea33b74fb8aa686ed9b168294b26b4c819df0be0712d358
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Tue, 09 Jul 2019 16:05:44 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-jvtl7 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:  #对应的每一个pod无论你定义与否它都有一个存储卷,这个存储卷名称为default-token-jvtl7,这就是pod 在service上用到的认证信息。
  default-token-jvtl7:
    Type:        Secret (a volume populated by a Secret) #他通过secret来定义,因为是很敏感的认证信息所以我们保存在一个secret资源中,并以存储卷的方式关联到pod上,从而让pod内运行的应用通过secret中保存的认证信息来连接apiserver从而来完成认证。
    SecretName:  default-token-jvtl7
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  3m    default-scheduler  Successfully assigned default/myapp-deploy-67f6f6b4dc-gjlqd to k8snode1
  Normal  Pulled     3m    kubelet, k8snode1  Container image "ikubernetes/myapp:v2" already present on machine
  Normal  Created    3m    kubelet, k8snode1  Created container
  Normal  Started    3m    kubelet, k8snode1  Started container
[root@k8smaster manifests]# kubectl get secret #可以看到有个默认的secret default-token-jvtl7,不只此名称空间,其它名称空间也一样存在
NAME                    TYPE                                  DATA      AGE
default-token-jvtl7     kubernetes.io/service-account-token   3         61d
mysql-root-password     Opaque                                1         19d
tomcat-ingress-secret   kubernetes.io/tls  

    c、名称空间中的默认的 default-token secret作用在于该名称空间中的pod资源试图去联系apiserver时隐藏的一个预置的一个认证信息,所以所有的pod都能够直接连接apiserver,这个secret中所包含的认证信息仅仅是包含pod自身的,仅有权限去获取当前pod自身的相关属性,不能随便观看别人的,如果我们想扩展一个pod,比如这个pod运行的应用就是管理类的应用,它是管其它Pod的,甚至管其它的deployment等各种各样的资源对象,必须自己手动去创建一个serviceAccount,并且创建pod时给他附加我们自己定义的serviceAccount而不要使用默认的serviceAccount,默认的serviceAccount一般而言权限都非常小,如果想增加提升它的权限首先得知道怎么去给pod额外加一个自定义的服务账号。

六、serviceAccount

  1、serviceAccount属于标准的k8s资源,可以创建一个serviceAccount,创建完以后然后由我们创建的pod使用serviceAccountName去加载我们自己定义的serviceAccount就够了。

  2、创建serviceAccount,serviceAccount本身不带权限,只是换个账号而已,我们将来可以使用rbac来实现对这个serviceAccount授予重大权限,所以授权不属于serviceAccount,我只不过可以换一个专用账号给这个pod,回头我可以给这个专用账号授予重大权限。

    a、使用kubectl create

[root@k8smaster manifests]# kubectl create serviceaccount mysa -o yaml --dry-run #dry-run表示只生成一个框架不真正创建。
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: null
  name: mysa

    b、在我们创建资源时可以通过这种方式将对应的配置文件导出

[root@k8smaster manifests]# kubectl get pods myapp-deploy-67f6f6b4dc-gjlqd -o yaml --export
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  generateName: myapp-deploy-67f6f6b4dc-
  labels:
    app: myapp
    pod-template-hash: "2392926087"
    release: canary
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: myapp-deploy-67f6f6b4dc
    uid: 58e8e8a4-a220-11e9-8818-000c29d142be
  selfLink: /api/v1/namespaces/default/pods/myapp-deploy-67f6f6b4dc-gjlqd
spec:
  containers:
  - image: ikubernetes/myapp:v2
    imagePullPolicy: IfNotPresent
    name: myapp
    ports:
    - containerPort: 80
      name: http
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-jvtl7
      readOnly: true
  dnsPolicy: ClusterFirst
  nodeName: k8snode1
  priority: 0
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - name: default-token-jvtl7
    secret:
      defaultMode: 420
      secretName: default-token-jvtl7
status:
  phase: Pending
  qosClass: BestEffort

    c、创建一个sa

[root@k8smaster manifests]# kubectl create serviceaccount admin  #创建一个名叫admin的sa
serviceaccount/admin created 
[root@k8smaster manifests]# kubectl get sa
NAME      SECRETS   AGE
admin     1         9s
default   1         61d
[root@k8smaster manifests]# kubectl describe sa admin
Name:                admin
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   admin-token-xnplt
Tokens:              admin-token-xnplt  #可以看到admin本身也调用了一个token,专用的token,会自动给他生成一个token信息
Events:              <none>
[root@k8smaster manifests]# kubectl get secret #发现多了一个信息叫admin-token,这是k8s自动生成的,用于让这个sa连接至当前系统apiserver信息,注意,认证代表不了权限,能登陆进k8s,能认证k8s,但是做不了别的事情,所有做的事情要授权。
NAME                    TYPE                                  DATA      AGE
admin-token-xnplt       kubernetes.io/service-account-token   3         48s
default-token-jvtl7     kubernetes.io/service-account-token   3         61d
mysql-root-password     Opaque                                1         19d
tomcat-ingress-secret   kubernetes.io/tls                     2         25d

  3、使用sa,重复一遍,k8s集群有两类认证时的用户账号一类叫userAccount,通常称为用户账号,通常对应现实中的人对应的账号,第二类叫serviceAccount,也称为服务账号,它是指pod中一种程序托管运行在k8s基础上想访问当前k8s集群的apiserver时里面要用到的认证信息,包括用户名,账号,密码等。

[root@k8smaster manifests]# cat pod-sa-demo.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-sa-demo
  namespace: default
  labels: #也可以在此处写上{app:myapp,tier:frontend}代替下面两行
    app: myapp #应用层级标签
    tier: frontend #架构层级标签,在分层架构中属于frontend层
  annotations:
    wohaoshuai.com/created-by: "cluster admin"
spec:
  containers: #是一个列表,具体定义方式如下
  - name: myapp
    image: ikubernetes/myapp:v1
    ports: #不暴露端口其实也可以被访问,目的是为了说明启动的端口有哪些
    - name: http #service 中可以通过名称来引用端口
      containerPort: 80
  serviceAccountName: admin

[root@k8smaster manifests]# kubectl apply -f pod-sa-demo.yaml 
pod/pod-sa-demo created
[root@k8smaster manifests]# kubectl describe pods pod-sa-demo
Name:               pod-sa-demo
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               k8snode1/192.168.10.11
Start Time:         Tue, 09 Jul 2019 17:50:49 +0800
Labels:             app=myapp
                    tier=frontend
Annotations:        kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{"wohaoshuai.com/created-by":"cluster admin"},"labels":{"app":
"myapp","tier":"frontend"},"nam...                    wohaoshuai.com/created-by=cluster admin
Status:             Running
IP:                 10.244.1.151
Containers:
  myapp:
    Container ID:   docker://10cbc471231dd6475d75618c69b30278e8653bc2a88880681ec554b94ffbd462
    Image:          ikubernetes/myapp:v1
    Image ID:       docker-pullable://ikubernetes/myapp@sha256:9c3dc30b5219788b2b8a4b065f548b922a34479577befb54b03330999d30d513
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Tue, 09 Jul 2019 17:50:50 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from admin-token-xnplt (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  admin-token-xnplt:  #可以看到使用了我们的admin-token
    Type:        Secret (a volume populated by a Secret)
    SecretName:  admin-token-xnplt
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  46s   default-scheduler  Successfully assigned default/pod-sa-demo to k8snode1
  Normal  Pulled     46s   kubelet, k8snode1  Container image "ikubernetes/myapp:v1" already present on machine
  Normal  Created    46s   kubelet, k8snode1  Created container
  Normal  Started    45s   kubelet, k8snode1  Started container

   4、我们此前讲过,每一次如果我们要创建我们写的资源清单提交给apiserver时apiserver告诉我们的kubelet,就是node节点要创建并运行一个pod,而这个pod中的容器的启动要依赖一个私有registry之上的镜像时这个服务器有可能需要认证才能获得私有镜像,这个认证信息我们在pod中也可以不用imagePullSecret,而可以直接使用serviceAccountName,因为我们使用它的时候相当于使用一个sa账号,而这个sa账号是可以附带认证到私有registry上的secret认证信息的。因此我们为Pod来获取私有镜像时的两种认证方式,第一,在pod上直接使用 ImagePullSecrets字段指定能认证完成时使用的secret对象。第二,在pod上自定义serviceAccount,在serviceAccount上附加这个pod获取镜像时认证使用的secret对象。

[root@k8smaster manifests]# kubectl describe sa admin
Name:                admin
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none> #以后创建secret对象以后不要定义在pod上可以定义在sa上,然后把sa定义在pod上,这样我们的pod也能完成资源下载时的认证了。这样在我们pod配置文件清单中就不会泄露出去我们secret到底是用的哪个相关信息了。
Mountable secrets:   admin-token-xnplt
Tokens:              admin-token-xnplt
Events:              <none>

六、RBAC:基于角色的访问控制

  1、kubectl 连接服务器是怎么认证的?,所有连往apiserver的客户端在认证时如果我们要基于配置文件来保存客户端的认证信息而不是通过serviceAccount 使用token方式来认证的话我们就应该给他配置为一个配置文件,k8s集群的所有除了apiserver组件比如controler-manager等等都需要连入apiserver,都需要被apiserver所认证,所以他们都算的上是apiserver的客户端,包括kubectl,每一个组件为了能够连入正确的集群,能提供正确的账号,证书,私钥等认证时的信息我们需要把这个配置信息保存到一个文件,这个配置文件有一个称呼就叫kubeconfig,这个kubeconfig是apiserver客户端连入apiserver时使用的认证格式的客户端配置文件,我们的kubectl也是这样的客户端,他也有自己的配置文件,要打印配置文件内容可以用kubectl  config view命令来查看,可以看出其也是一个标准的k8s资源对象。

[root@k8smaster ~]# kubectl config view
apiVersion: v1
clusters: #集群列表
- cluster:
    certificate-authority-data: REDACTED
    server: https://192.168.10.10:6443
  name: kubernetes
contexts: #上下文列表
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes #当前上下文
kind: Config
preferences: {}
users: #用户列表
- name: kubernetes-admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

  2、可以看到这个配置文件不单单让你访问一个k8s集群的,如果你有多个k8s集群却只有一台主机做客户端,为了让我们一个kubectl能控制多个集群,我们可以这样干,提供配置文件第一叫集群列表,这样我们就有了多个集群,对每一个集群来讲我们可能会用到多个账号,也有可能都使用的admin,于是我们事先定义好几个账号,因此我们接下来定义context,其指明我们用哪个账号访问哪个集群。一个context就包含一个用户名和集群,它用来指明用哪个账号访问哪个集群。

  3、我们自己做一个证书和私钥作为另外一个账号去认证到k8s apiserver上来,来了解一下他是怎么生成的。

    a、先创建一个私钥生成一个签署证书,证书中的证书持有者和用户名必须保持一致,因为证书持有者的名称就是我们的用户账号名,我们服务器账号就是证书的subject。

    b、首先,我们做一个私钥

[root@k8smaster ~]# cd /etc/kubernetes/pki/
[root@k8smaster pki]# ls
apiserver.crt              apiserver-etcd-client.key  apiserver-kubelet-client.crt  ca.crt  etcd                front-proxy-ca.key      front-proxy-client.key  sa.pub
apiserver-etcd-client.crt  apiserver.key              apiserver-kubelet-client.key  ca.key  front-proxy-ca.crt  front-proxy-client.crt  sa.key
[root@k8smaster pki]# (umask 077; openssl genrsa -out wohaoshuai.key 2048)
Generating RSA private key, 2048 bit long modulus
..................+++
..................+++
e is 65537 (0x10001)

    c、接下来我们基于这个私钥去生成一个证书,由我们的ca.crt来签署。

[root@k8smaster pki]# openssl req -new -key wohaoshuai.key -out wohaoshuai.csr(证书签署请求) -subj "/CN=wohaoshuai" #名称就是你的用户账号名字

    d、接下来就可以签证了,用证书去签

[root@k8smaster pki]# openssl x509 -req -in wohaoshuai.csr -CA /etc/kubernetes/pki/ca.crt (用这个ca签) -CAkey /etc/kubernetes/pki/ca.key(CA私钥) -CAcreateserial(用CA自己的认证符号信息) -out wohaoshuai.crt(保存为证书文件为此文件) -days 365(签一年)
Signature ok
subject=/CN=wohaoshuai
Getting CA Private Key

    e、用kubeadm部署集群有一个问题,证书有效期为1000天还是三年,证书过期就比较麻烦

    f、现在证书已经有了,自签证书,当然也可以去查看证书信息

[root@k8smaster pki]# openssl x509 -in wohaoshuai.crt -text -noout
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            94:c3:56:c4:2d:29:e4:33
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=kubernetes #kubernetes自己的CA证书签署的
        Validity
            Not Before: Jul 12 03:45:37 2019 GMT
            Not After : Jul 11 03:45:37 2020 GMT
        Subject: CN=wohaoshuai #作为账号去连入k8s被k8s识别为用户身份
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:a7:26:b9:7f:12:a2:8a:e0:67:ca:d3:d5:64:29:
                    00:42:3c:42:51:28:62:99:b8:07:a6:f1:83:92:43:
                    62:55:bb:4e:5a:a5:06:1a:14:3e:b1:8c:13:e3:26:
                    c6:10:41:b1:76:fc:e3:22:4a:55:01:25:d9:3d:c8:
                    cd:01:1f:e4:64:53:f0:4d:b0:b1:46:73:ab:56:90:
                    de:f1:4e:b4:ca:9a:c2:dc:0e:6a:06:52:b0:a4:3e:
                    26:c0:b7:ef:0d:a3:28:a9:8e:c4:a4:45:1e:18:e2:
                    38:16:75:26:3d:fd:7f:50:7b:b0:d8:d7:50:a2:77:
                    c5:4d:f1:88:fe:8d:98:00:51:7e:eb:c5:25:b8:6e:
                    57:ce:02:5d:9a:fe:9a:15:f0:3d:e1:4c:f1:27:6a:
                    79:50:4b:6e:7b:0e:40:bc:3e:f3:b3:2d:ff:82:70:
                    94:bb:83:3c:cf:ce:53:6e:54:41:a3:8e:d1:f0:4a:
                    d4:04:2f:c7:87:2e:7c:b1:5c:c1:e6:78:23:95:d8:
                    f8:b5:b8:be:47:41:1d:75:3b:16:98:3f:fe:4d:d8:
                    a0:6a:f9:b0:78:92:7b:b6:ce:6b:8b:dc:09:81:d9:
                    f9:5b:9c:ac:d8:26:56:b5:6c:88:4e:cf:34:35:78:
                    81:58:97:e2:86:c8:81:e4:5f:b1:bd:4a:6b:1f:1d:
                    98:99
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         25:d0:00:4c:d0:75:6c:45:62:32:04:0e:ff:87:3b:04:65:17:
         5e:b3:ed:db:ba:36:51:83:3d:b3:7f:ab:df:63:ab:7c:87:9a:
         82:f2:d9:f8:7a:77:ca:76:d0:71:04:6a:ee:90:78:19:f1:c4:
         db:fd:e9:9e:5a:ae:67:14:14:85:8d:28:d2:76:af:c7:b4:8c:
         67:ca:e8:d2:7f:c5:2e:84:d7:2a:fc:60:00:ac:fa:88:56:7e:
         eb:0b:64:87:7c:5a:aa:5f:ad:88:eb:e4:75:af:20:02:ba:22:
         23:64:d5:db:8b:45:a6:fd:27:e3:b4:68:6a:ee:e8:af:3b:93:
         29:8c:e6:0f:5c:19:32:04:aa:85:1c:73:6a:3d:ab:3a:83:f1:
         a2:cb:ab:d1:c6:b7:ff:c2:b0:8e:ab:a6:2a:38:23:28:4d:52:
         71:47:86:6b:5d:da:52:0d:fa:38:c5:ca:76:00:7c:f4:f4:e8:
         20:b7:af:ee:f9:e4:4c:a0:c5:0e:5c:c6:7e:7c:ca:ac:80:08:
         67:ff:88:64:07:c1:8d:56:b4:65:94:e9:b4:52:c7:51:ae:3f:
         85:e9:a6:d5:24:93:97:77:bc:64:1c:54:0e:a0:0e:f2:97:c1:
         86:35:bb:48:ad:5f:92:1c:aa:b7:1e:a6:98:7f:56:e1:cf:82:
         9e:63:33:54

    g、接下来我们把这个用户账号信息给他添加到我们去认证为连接k8s集群的信息。而且他是由同一个k8s集群的CA授权的,所以他创建的证书认证是不会有问题的。

    e、我们接下来创建一个用户

[root@k8smaster pki]# kubectl config set-credentials wohaoshuai(用户的标识符) --client-certificate=/etc/kubernetes/pki/wohaoshuai.crt --client-key=/etc/kubernetes/pki/wohaoshuai.key --embed-certs=true (将相应信息隐藏)
User "wohaoshuai" set.
[root@k8smaster pki]# kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: REDACTED
    server: https://192.168.10.10:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
- name: wohaoshuai
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

    f、然后我们设定上下文让wohaoshuai也能访问kubernetes

[root@k8smaster pki]# kubectl config set-context wohaoshuai@kubernetes --cluster=kubernetes --user=wohaoshuai
Context "wohaoshuai@kubernetes" created.
[root@k8smaster pki]# kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: REDACTED
    server: https://192.168.10.10:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
- context:
    cluster: kubernetes
    user: wohaoshuai
  name: wohaoshuai@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
- name: wohaoshuai
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

     g、现在切换到wohaoshuai账户,这个账号是没有管理员的权限的

[root@k8smaster ~]# kubectl config use-context wohaoshuai@kubernetes
Switched to context "wohaoshuai@kubernetes".
[root@k8smaster ~]# kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: REDACTED
    server: https://192.168.10.10:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
- context:
    cluster: kubernetes
    user: wohaoshuai
  name: wohaoshuai@kubernetes
current-context: wohaoshuai@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
- name: wohaoshuai
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
[root@k8smaster ~]# kubectl get pods #可以看到没有权限
No resources found.
Error from server (Forbidden): pods is forbidden: User "wohaoshuai" cannot list pods in the namespace "default"

  4、当然我们少给大家演示了一步,就是设置cluster,如果我们新生成一个配置文件或者在当前配置文件中新定义一个集群,设置集群时方法其实也比较简单,第一,指定集群名,然后指定集群的CA的证书。因为我们要使用这个CA证书验证集群APIserver发过来的证书的,那么我们怎么去信任这个服务器证书呢?所以我们指明证书时apiserver发过来信息做认证时它才能对他完成认证。所以最关键就是我们要去设定哪个集群指明集群名字,指明集群服务访问地址,指明集群证书。即服务上级机构的证书。也就是当前pki路径下的ca.crt,所以我们最简单的办法就是我们指明server是谁,指明ca的证书是谁,指明把证书隐藏起来(--embed-certs=true)就行了。

    a、首先将用户换成kubernetes-admin

[root@k8smaster ~]# kubectl config set-cluster --help
Sets a cluster entry in kubeconfig. 

Specifying a name that already exists will merge new fields on top of existing values for those fields.

Examples:
  # Set only the server field on the e2e cluster entry without touching other values.
  kubectl config set-cluster e2e --server=https://1.2.3.4
  
  # Embed certificate authority data for the e2e cluster entry
  kubectl config set-cluster e2e --certificate-authority=~/.kube/e2e/kubernetes.ca.crt
  
  # Disable cert checking for the dev cluster entry
  kubectl config set-cluster e2e --insecure-skip-tls-verify=true

Options:
      --embed-certs=false: embed-certs for the cluster entry in kubeconfig

Usage:
  kubectl config set-cluster NAME [--server=server] [--certificate-authority=path/to/certificate/authority]
[--insecure-skip-tls-verify=true] [options]

Use "kubectl options" for a list of global command-line options (applies to all commands).
[root@k8smaster ~]# cd /etc/kubernetes/pki/ && ls
apiserver.crt              apiserver-etcd-client.key  apiserver-kubelet-client.crt  ca.crt  ca.srl  front-proxy-ca.crt  front-proxy-client.crt  sa.key  wohaoshuai.crt  wohaoshuai.key
apiserver-etcd-client.crt  apiserver.key              apiserver-kubelet-client.key  ca.key  etcd    front-proxy-ca.key  front-proxy-client.key  sa.pub  wohaoshuai.csr
[root@k8smaster pki]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".

    b、现在我们设置一个集群,我们新定义一个配置文件,我们不使用默认配置文件,我们刚刚所有设置都是保存在默认配置文件。kubectl默认加载配置文件路径为当前用户家目录下的.kube这个目录中的config文件,如果想把它保存在别的位置也可以,使用--kubeconfig选项即可。

[root@k8smaster pki]# kubectl config set-cluster mycluster --kubeconfig=/tmp/test.config --server="https://192.168.10.10:6443" --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-cer
ts=trueCluster "mycluster" set.
[root@k8smaster pki]# kubectl config view --kubeconfig=/tmp/test.config
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: REDACTED
    server: https://192.168.10.10:6443
  name: mycluster
contexts: []
current-context: ""
kind: Config
preferences: {}
users: []

 

posted @ 2019-07-08 16:08  Presley  阅读(2009)  评论(0编辑  收藏  举报