RBAC概述

在任何将资源或服务提供给有限使用者的系统上,认证和授权都是两个必不可少的功能,认证用于身份鉴别,负责用于验证”来者是谁”,而授权则实现权限分配,负责验证”它有权做哪些事情”,kubernetes完全分离了身份验证和授权功能,将二者分别以多种不同的插件实现。另外,它还支持准入控制机制,用于补充授权机制以实现更精细的访问控制功能,还能在”写”请求上辅助完成更为精细的操作验证及变异功能

访问控制器概述

  • API Server作为kubernetes集群系统的网关,是访问及管理集群资源对象的唯一入口,它默认监听TCP的6443端口,通过HTTPS协议暴露了一个RESTful峰哥的接口,所有需要访问集群资源的集群组件或者客户端,包括kube-controller-manager、kube-scheduler、kubelet和kube-proxy等集群组件,coreDNS等集群的附加组件,以及此前使用的kubectl命令等都需要经过API Server对集群进行访问管理,并且由它对每次一次的访问请求进行合法性校验,包括用户身份鉴别、操作权限验证以及操作是否符合全局规范的约束等。所有检查均正常完成且对象配置信息合法性检验无误之后才能访问或存入数据到后端存储系统etcd当中
    kubernetes-安全-ServiceAccount - 图1
  • 客户端认证操作由API Server配置的一到多个认证插件来完成,收到请求后,API Server依次调用配置的认证插件来校验客户端身份,直到其中一个插件可以识别出请求者的身份为止。授权操作则由一到多个授权插件完成,这些插件负责确定通过认证的用户是否有权限执行发出的资源操作请求,如创建、读取、删除或者修改指定资源对象的资源操作请求。随后通过授权检测的用户请求的相关操作还要经由一到多个准入控制插件的遍历式检测,例如使用默认值补足要创建的目标资源对象中未定义的各字段,检查目标Namespace资源对象是否存在、检查请求创建的Pod对象是否违反系统资源限制等,而其中的任何检查失败都有可能会导致写入操作失败

用户账户与用户组

  • kubernetes并不会存储由认证插件从客户端请求中提取出的用户及所属组的信息,他们仅仅用于检验用户是否有权限执行其所请求的操作。kubernetes系统上的用户账户及用户组的实现机制与常规应用略有不同,客户端访问API服务的途径通常有三种:kubectl,客户端库或者直接使用REST接口进行请求,而可以执行此类请求的主体也被kubernetes分为两类:现实中的”人”和Pod对象,他们的用户身份分别对应于应用账户(User Account)和服务账号(Service Account,简称SA)
    • User Account(用户账户):其使用主体往往是”人”,一般由外部的用户管理系统存储和管理,kubernetes本身并不维护这一类的任何用户账户信息,他们不会被存储到API Server之上,仅仅用于检验用户是否有权限执行其所请求的操作。kubernetes中不存在表示此类用户账号的对象,因此不能被直接添加进kubernetes系统中,一般是由独立于kubernetes之外的其他服务管理的用户账号,例如由管理分发的秘钥,keystone一类的用户存储,甚至是包含有用户名和密码列表的文件等
    • Service Account(服务账号):其使用主体是”应用程序”,专用于为Pod资源中的服务进程提供访问kubernetes API时的身份标识(identify)。serviceaccount资源通常需要绑定到特定的名称空间,它们由API Server自动创建或者通过API调用,由管理员手动创建,通常附带着一组访问API Server的认证凭据—secret,可由同一名称的Pod应用访问API Server时使用
    • User Account(用户账户):通常用于复杂的业务逻辑管控,它作用于系统全局,因而名称必须全局唯一。kubernetes并不会存储由认证插件从客户端请求中提取的用户及所属的组信息,因而也就没有办法对普通用户进行身份认证,它们仅仅用于检查该操作主体是否有权限执行其所请求的操作。相比较来说,serviceaccount则隶属于名称空间级别,仅用于实现某些特定的操作任务,因此功能上要轻量的多。这两类账户都可以隶属于一个或者多个用户组。用户组只是用户账户的逻辑集合,它本身没有执行系统操作的能力和权限,但附加于组上的权限则可由其内部的所有用户继承,以实现高效的授权管理机制
  • kubernetes有着以下几个内建的用于特殊目的的组
    • system:unauthenticated: 未能通过任何一个授权插件来检验的账号,所有未通过认证测试的用户统一隶属的用户组
    • system:authenticated: 认证成功后的用户自动加入的一个专用组,用于快捷引用所有正常通过认证的用户账户
    • system:serviceaccounts: 当前系统上所有名称空间中的serviceaccount对象
    • system:serviceaccounts:<namespace>: 特定名称空间内所有的serviceaccount对象
  • 对于API Server来说,来自客户端的请求要么与用户账户绑定,要么以某个服务账户的身份进行,要么被视为匿名请求。这意味着集群内部或外部的每个进程,包括由人类用户使用kubectl,以及各节点上运行的kubelet进程,再到控制平面的成员组件,必须在向API Server发出请求时进行身份验证,否则被视为匿名用户。

认证,授权与准入控制基础

  • API Server处理请求的过程中,认证插件负责鉴定用户的身份,授权插件则用于操作权限许可鉴别,而准入控制机制则用于在资源对象上的创建、删除、更新或连接(proxy)操作时实现更精细的许可检查
  • kubernetes使用身份验证插件对API请求进行身份验证,支持的方式包括客户端证书,承载令牌(bearer tokens)、身份验证代理( authenticating proxy)或HTTP basic认证等
  • 如前所述,kubernetes使用身份验证插件对API请求进行身份验证,它允许管理员自定义服务账户和用户账户要启用或禁用的插件,并支持各自同时启用多种认证机制。具体设定时,至少应该为服务账户和用户账户各自启用一个认证插件。如果启用了多种认证机制,账号认证过程由认证插件以串行方式进行,直到其中一种认证机制成功完成即结束。若认证失败,服务器则以401状态码响应,反之,请求者会被kubernetes识别为某个具体的用户(以其用户进行标识),并且该连接上随后的操作都会以此用户身份进行。API Server对于接收到的每个访问请求都会调用认证插件,并且尝试将以下属性与访问请求相关联
    • Username: 用户名,例如kubernetes-admin等
    • UID:用户的数字标签符,用于确保用户身份的唯一性
    • Groups:用户所属的组,用于权限指派和继承
    • Extra:键值数据类型的字符串,用于提供认证时需要用到的额外信息
  • kubernetes使用身份验证插件对API请求进行身份验证,支持的方式包括客户端证书,承载令牌(bearer tokens,也称为不记名令牌)、身份验证代理( authenticating proxy)和HTTP basic认证等。具体来说,API Server支持以下几种具体的认证方式,其中所有的令牌认证机制通常被称为”承载令牌认证”
    • X509客户端证书认证:客户端在请求报文中携带X509格式的数字证书用于认证,其认证过程类似于HTTPS协议通信模型,认证通过后,证书中的主体标识(Subject)将被识别为用户标识,其中的字段CN(Common Name)的值是用户名,字段O(organization)
      的值是用户所属的组,例如,/CN=Linux/O=opmasters/O=admin中,用户名为linux,其属于opmasters和admin两个组;该认证方式可以通过--client-ca-file=SOMEFILE选项启用即可
    • 静态令牌文件(Static token file)认证:即保存用于认证的令牌信息的静态文件,由kube-apiserver的命令选项—token-auth-file加载,且API Server进程启动后不可更改。HTTP协议的客户端也能基于承载令牌(Authorization: Bearer <token>表头)对静态令牌文件进行身份验证,它将令牌编码后通过请求报文中的Authorization头部承载并传递给API Server即可;建议仅将该认证方式用于非生产环境中
    • 静态密码文件认证:将用户名和密码等信息以明文形式存储在CSV格式的文件中,又kube-apiserver在启动时通过—basic-auth-file选项予以加载,添加或删除用户都需要启动API Server。客户端通过在HTTP Basic认证(Authorization: Basic <base64-encoded-username:password>标头)方式中将用户名和密码编码后对该文件进行认证,显然,该认证方式应该在非生产环境当中使用(kuerbenets1.6之后废弃,使用静态令牌文件的方式替换)
    • 引导令牌(Bootstrap Tokens)认证:一种动态管理承载令牌进行身份认证的方式,常用于简化组件新建kubernetes集群时将节点加入集群的认证过程,需要由kube-apiserver通过—experimental-bootstrap-token-auth选项启用。新的工作节点首次加入时,master使用引导令牌确认节点身份的合法性之后自动为其签署数字证书以用于后续的安全通信。kubeadm初始化的集群也是这种认证方式;这些令牌作为secret存储在kube-system命名空间中,可以动态管理和创建它们,并由controller Manager的tokencleaner控制器负责删除过期的引导令牌
    • Service Account(服务账户令牌)认证:该认证方式由kube-apiserver程序自动启用,它同样可以使用签名的承载令牌来验证请求。该认证方式还支持通过可选项—service-account-key-file加载签署承载令牌的秘钥文件,未指定时将使用API Server自己的TLS秘钥。ServiceAccount通常由API Server自动创建,并通过serviceaccount准入控制器将其注入Pod对象,包括serviceaccount上的承载令牌,容器中的应用程序请求API Server的服务时以此完成身份认证
    • OpneID Connect令牌认证:简称为OIDC,是OAuth 2协议的一种扩展,由Azure AD、Salesforce和Google accounts等OAuth 2服务商所支持,协议的主要扩展是返回的附加字段,其中的访问令牌也称为ID令牌;它属于json web令牌(JWT)类型,有服务器签名过的常用字段,例如email等;kube-apiserver启用这种认证功能的相关选项较多
    • webhook令牌:webhook身份认证是用于验证承载令牌的钩子;HTTP协议的身份验证允许将服务器的URI注册为webhook,并接收带有承载令牌的POST请求进行身份认证;客户端使用kubeconfig格式的配置文件,在文件中”user”指的是API Server的webhook,而Cluster则指的是API Server
    • 代理认证:API Server支持从请求头部的值中识别用户,例如常用的X-Remote-User、X-Remote-Group和几个以X-Remote-Extra-开头的头部,它与身份证验证代理服务相结合,由该代理设置相应的请求头部;为了防止头欺骗,在检查请求表头之前,需要身份认证代理服务向API Server提供有效的客户端证书,以验证指定CA(由选项—requestheader-client-ca-file等进行指定)的代理是否合法
    • 匿名请求:那些未被任何验证插件明确拒绝的用户即为匿名用户,该类用户会被自动标识,并且标识的用户名为system:annoymous,并且隶属于system:unauthenticated用户组。若API Server启用了AlwaysAllow以外的认证机制时,则匿名用户处于启用状态。但是,通常处于安全因素的考虑,建议管理员通过—annoymous-auth=false选项将其禁用
  • API Server允许用户通过模拟头部冒充另一个用户,这些请求可以以手动方式覆盖请求中用于身份证验证的用户信息。例如,管理员可以使用此功能临时模拟其他用户来查看请求是否被拒绝,以进行授权策略调试
  • 除了身份信息,一个请求报文还需要提供操作方法及其目标对象,例如针对某Pod资源对象进行的创建,查看,修改或者删除操作等。具体来说,请求报文包含如下信息
    • API:用于定义请求的目标是否为一个API资源
    • Request path:请求的非资源型路径,如/api或/healthz
    • API group:需要访问的API组,仅对资源型请求有效,默认为core API group
    • Namespace:目标资源所属的名称空间,仅对隶属于名称空间类型的资源有效
    • API request verb:API请求类的操作,即资源型请求(对资源执行的操作),包括get、list、create、update、patch、watch、proxy、redirect、delete和deletecollection等
    • HTTP request verb:HTTP请求类的操作,即非资源型请求的操作,如get、post、put和delete
    • Resource:请求的目标资源的ID或者名称
    • Subresource:请求的子资源
  • 为了核验用户的操作许可,成功通过身份认证后的操作请求还需要转交给授权插件进行许可权限检查,以确保其拥有执行相应操作的许可。API Server主要支持四类内置的授权插件来定义用户的操作权限
    • Node:基于Pod资源的目标调度节点来实现对kubelet的访问控制
    • ABAC:attribute-based access control,基于属性的访问控制
    • RBAC:role-base access control,基于角色的访问控制
    • webhook:基于HTTP回调机制实现外部REST服务检查,确认用户是授权的访问控制
  • 另外,还有AlwaysDeny(总是拒绝)和AlwasAllow(总是运行)两个特殊的插件,其中AlwaysDeny仅用于测试,而AlwasAllow则用于不期望进行授权检查时直接在授权检查阶段放行所有的操作请求。在启动API Server时,使用--authorization-mode选项用于定义API Server要启用的授权机制,多个选项值彼此间以逗号进行分隔
  • 而准入控制器(Admission Controller)则用于在客户端请求经过身份验证和授权检查之后,将对象持久化存储到etcd之前拦截请求,从而实现在资源的创建,更新和删除操作期间强制执行对象的语义验证功能,而当前资源信息的操作请求则不会经由准入控制器检查。API Server内置了许多准入控制器,常用的包含下面列出的几种。不过,其中的个别控制器仅在交心版本的kubernetes中才被支持
    • AlwaysDeny和AlwaysAdmit:前者拒绝所有请求,后者允许所有请求
    • AlwaysPullImages:总是下载镜像,即每次创建Pod对象之前都要去下载镜像,常用于多租户环境中,以确保私有镜像仅能够由拥有权限的用户使用
    • NamespaceLifecycle:拒绝在不存在的名称空间中创建资源,而删除名称空间则会级联删除其下的所有其他资源
    • LimitRanger:可用资源范围界定,用于对设置了LimitRange的对象所发出的所有请求进行监控,以确保其资源不会超限
    • ServiceAccount:用于实现服务账户管控机制的自动化,实现创建Pod对象时自动为其附加相关的Service Account对象
    • PersistentVolumeLabel:为那些由云计算服务商提供的PV自动附加region或zone标签,以确保这些存储卷嫩正确关联且仅能关联到所属的region或zone
    • DefaultStorageClass:监控所有创建PVC对象的请求,以保证那些没有附加任何专用storageclass的请求会被自定设定一个默认值
    • ResourceQuota:用于为名称空间设置可用资源上限,并确保在其中创建的任何设置了资源限额的资源对象都不会超出名称空间的资源配额
    • DefaultTolerationSeconds:如果Pod对象上不存在污点宽容期限,则为它们设置默认的宽容期,以宽容notready:NoExecute和unreachable:NoExecute类的污点五分钟时间
    • ValidatingAdmissionWebhook: 并行调用匹配当前请求的所有验证类的webhook,任何一个校验失败,即请求失败
    • MutatingAdmissionWebhook:串行调用匹配当前请求的所有变异类的webhook,每个调用都可能会更改对象
  • 早起的准入控制器代码需要由管理员编译进kube-apiserver中才能使用,实现方式缺乏灵活性。于是kubernetes自1.7版本引入了initialize和External Admission Webhooks来尝试突破此限制,而且自1.9版本起,External Admission Webhooks被分为Mutating-AdmissionWebhook和ValidatingAdmissionWebhook两种类型,分别用于在API种执行对象配置的变异和验证操作。检查期间,只有那些顺利通过所有准入控制器检查的资源操作请求的结果才能保存到etcd中,而任何一个准入控制器的拒绝都将会导致写入请求失败

测试使用API Server的访问控制机制

  • 需要注意的是,kubernetes自1.16版本开始已经废弃了使用静态文件的方式进行认证,所以下面的配置只做了解
  • 如前所述,认证,授权和准入控制功能都以API Server插件形式存在,它们都可以由kube-apiserver相应的选项进行启用和配置。由kubeadm部署的kubernetes集群的API Server以静态Pod形式运行,相关配置清单(默认路径:/etc/kubernetes/manifests/kube-apiserver.yaml)中配置kube-apiserver如下的一部分选项
  1. spec:
  2. containers:
  3. - command:
  4. - kube-apiserver
  5. - --advertise-address=172.18.14.244
  6. - --allow-privileged=true
  7. - --authorization-mode=Node,RBAC # 启用Node和RBAC授权插件
  8. - --client-ca-file=/etc/kubernetes/pki/ca.crt #启用X509数字证书认证
  9. - --enable-admission-plugins=NodeRestriction # 额外启用的准入控制器列表
  10. - --enable-bootstrap-token-auth=true # 启用Bootstrap token认证
  11. ...
  12. - --etcd-servers=https://127.0.0.1:2379
  13. - --insecure-port=0 # API Server监听的非安全端口(HTTP协议),0表示禁用
  14. ...
  15. - --requestheader-allowed-names=front-proxy-client
  16. - --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
  17. - --requestheader-extra-headers-prefix=X-Remote-Extra- #代理相关的配置
  18. - --requestheader-group-headers=X-Remote-Group
  19. - --requestheader-username-headers=X-Remote-User
  20. - --secure-port=6443 #API Server监听的安全端口(HTTPS协议)
  21. - --service-account-key-file=/etc/kubernetes/pki/sa.pub
  22. - --service-cluster-ip-range=10.96.0.0/12
  23. - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
  24. - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
  • API Server的几乎每个认证插件有自己专用的一支多个配置选项,例如上面配置中启用X509的证书认证、Bootstrap Token认证和代理认证、ServiceAccount认证默认处于启用状态,—service-account-key-file选项仅指定用于签署承载令牌的密钥文件,未配置时默认使用API Server的TLS密钥。认证操作由各插件以”短路”方式进行,客户端请求会依次经由认证插件进行检查,任何一个插件认证成功既终止认证过程
  • 启用的授权插件需要显式指定,他们需要以列表值的格式统一定义在—authorization-mode选项之上,例如上面配置中启用了Node和RBAC授权插件。启用的各授权插件同样以”短路”机制运行,任何一个授权插件鉴定成功即可结束授权检查过程
  • API Server默认会启用一部分准入控制器,额外需要启用的准入控制器需要以列表值的形式定义在—enable-admission-plugins选项之上,需要显式禁用准入控制器以列表值的形式定义在—disable-admission-plugins选项之上。与认证和授权不同的是,一个请求必须要成功通过所有准入控制器的检查,否则既会被拒绝
  • 不同版本的kubernetes默认启用的准入控制器可能存在区别,要了解当前使用的版本上默认启用的准入空气,可在kube-system名称空间中API Server相关的静态Pod内部运行kube-apiserver -h |grep 'enable-admission-plugins'命令获取
  • 测试或者开发环境当中,使用静态密码文件认证是添加普通用户的快捷途径。API Server的静态密码认证文件遵循CSV格式,每一行存储一个用户账户信息,格式为password,user,uid,"group1,group2,group3",用户组一段可以省略,而多个用户组也可以逗号分隔,但需要使用双引号将所有用户组进行整体引用。例如,我们可以在master节点上的/etc/kubernetes/authfiles目录中创建拥有类似如下内容的文件passwd.csv,它提供了ilinux和ik8s两个用户,二者都属于kubernetes用户组

静态密码认证(已废弃)

  1. [root@kube-master-01 kubernetes]# mkdir authfiles
  2. [root@kube-master-01 kubernetes]# cd authfiles/
  3. [root@kube-master-01 authfiles]# cat passwd.csv
  4. ilinux@123456,ilinux,1009,"kubernetes,defaultadmin"
  5. ik8s@123456,ik8s,1010,"kubernetes,defaultadmin"
  6. [root@kube-master-01 authfiles]#
  • API Server的--basic-auth-file选项要通过本地路径加载该文件以启用静态密码文件认证方式,因为kube-apisevrer是运行在静态Pod里面,所以我们需要将宿主机的密码文件挂载进kube-apiserver的静态Pod里,这里采用hostPath存储卷的方式将宿主机目录/etc/kubernetes/authfiles关联到静态Pod资源kube-apiserver的相同目录下。修改master节点上的/etc/kubernetes/manifests/kube-apiserver.yaml文件,添加hostPath存储卷及卷挂载配置,需要改动的配置部分如下:
  • 值得注意的是,在kubernetes1.16开始--basic-auth-file已经弃用了,替换它的随之是静态令牌的的身份验证
  1. spec:
  2. containers:
  3. - command:
  4. - kube-apiserver
  5. - --basic-auth-file=/etc/kubernetes/authfiles/passwd.csv
  6. ...
  7. volumeMounts:
  8. ...
  9. - mountPath: /etc/kubernetes/authfiles
  10. name: static-auth-files
  11. readOnly: true
  12. volumes:
  13. - hostPath:
  14. path: /etc/kubernetes/authfiles
  15. type: DirectoryOrCreate
  16. name: static-auth-files
  • kubelet的调谐循环会监视节点上指定的用于加载静态Pod配置清单的目录,默认为/etc/kubernetes/manifests。该目录中的任何清单发生变动时,都会由kubelet自动做出相应的处理,例如重新创建相关的Pod资源,因而配置清单修改完之后很快就会由kubelet重新创建kube-apiserver相关的静态Pod,从而启动静态密码文件认证机制

静态令牌认证

  • 静态令牌文件同样也是CSV格式的文件,它与静态密码文件的不同之处仅在于第一个字段提供的是令牌而非密码字符串,该令牌采用[a-z0-9]{6}.[a-z0-9]{16}的格式,第一部分代表令牌ID,第二部分则是令牌密钥。客户端认证时,直接在HTTP中以Authorization:Bearer <token>标头完成认证。我们可以在前面静态密码文件认证配置的示例上完成静态令牌文件认证的测试
  • 步骤一:
  • 执行类似如下如下命令,在/etc/kubernetes/authfiles/目录下创建token.csv文件,生成相关的用户配置
  1. [root@kube-master-01 authfiles]# echo "$(openssl rand -hex 3).$(openssl rand -hex 8),ilinux,1009,\"kubernetes,defaultadmin\"" \
  2. > >> /etc/kubernetes/authfiles/token.csv
  3. [root@kube-master-01 authfiles]#
  4. [root@kube-master-01 authfiles]# echo "$(openssl rand -hex 3).$(openssl rand -hex 8),ik8s,1010,\"kubernetes,defaultadmin\"" \
  5. > >> /etc/kubernetes/authfiles/token.csv
  6. 79e86f.ff78158dc5de4c8c,ik8s,1010,"kubernetes,defaultadmin"/etc/kubernetes/authfiles/token.csv
  7. [root@kube-master-01 authfiles]#
  8. [root@kube-master-01 authfiles]# chmod 400 /etc/kubernetes/authfiles/token.csv
  9. [root@kube-master-01 authfiles]#
  10. [root@kube-master-01 authfiles]# cat /etc/kubernetes/authfiles/token.csv
  11. 6867d5.0a4bf20e5a946a7a,ilinux,1009,"kubernetes,defaultadmin"
  12. 560b4c.11522a404e18bc3e,ik8s,1010,"kubernetes,defaultadmin"
  13. [root@kube-master-01 authfiles]#
  • 步骤二:
  • 编辑/etc/kubernetes/manifests/kube-apiserver.yaml配置清单,为kube-apiserver添加配置选项--token-auth-file=/etc/kubernetes/authfiles/token.csv
  1. spec:
  2. containers:
  3. - command:
  4. - kube-apiserver
  5. - --token-auth-file=/etc/kubernetes/authfiles/token.csv
  6. ...
  7. volumeMounts:
  8. ...
  9. - mountPath: /etc/kubernetes/authfiles
  10. name: static-token-file
  11. readOnly: true
  12. volumes:
  13. - hostPath:
  14. path: /etc/kubernetes/authfiles
  15. type: DirectoryOrCreate
  16. name: static-token-file
  • 步骤三:
  • API Server默认监听TCP的6443端口,未指定用户身份并以curl命令向master节点的6443端口上发起HTTPS服务的访问会被识别为匿名用户,但会出现该用户不具有访问相应资源权限的错误信息。例如下面的测试命令及响应结果所显示,API Server标识成功认证并识别用户名,但该用户并不具有指定资源的访问权限而被拒绝
  1. [root@kube-master-01 manifests]# TOKEN=$(awk -F "," '$2=="ilinux"{print $1}' /etc/kubernetes/authfiles/token.csv)
  2. [root@kube-master-01 manifests]# curl -s -H "Authorization: Bearer $TOKEN" -k https://172.18.14.244:6443/
  3. {
  4. "kind": "Status",
  5. "apiVersion": "v1",
  6. "metadata": {
  7. },
  8. "status": "Failure",
  9. "message": "forbidden: User \"ilinux\" cannot get path \"/\"",
  10. "reason": "Forbidden",
  11. "details": {
  12. },
  13. "code": 403
  14. }[root@kube-master-01 manifests]#
  • 步骤四:
  • 为了让ilinux用户获取资源操作权限,我们可以将API Server的--authorization-mode的选项值改为AlwaysAllow,但这样会将所有权限开放给任意用户。因而,我们接下来基于RBAC授权插件,将默认的集群角色(ClusterRole)admin通过角色绑定(RoleBinding)机制,为ilinux用户授权default名称空间的管理权限来测试认证用户的授权功能
  1. [root@kube-master-01 manifests]# kubectl create rolebinding default-ns-admin --clusterrole=admin --user=ilinux -n default
  2. rolebinding.rbac.authorization.k8s.io/default-ns-admin created
  3. [root@kube-master-01 manifests]#
  • 步骤五:
  • 以ilinux用户承载令牌认证的访问向API Server发起资源操作请求进行访问测试,,此时,ilinux用户拥有default名称空间及其内部资源对象的管理权限,我们可以通过该用户尝试访问该名称空间,以及该名称空间下的所有资源、指定类型的资源或者指定的资源对象,例如,使用下面的命令获取default名称空间的资源
  1. [root@kube-master-01 manifests]# TOKEN=$(awk -F "," '$2=="ilinux"{print $1}' /etc/kubernetes/authfiles/token.csv)
  2. [root@kube-master-01 manifests]# curl -s -H "Authorization: Bearer $TOKEN" -k https://172.18.14.244:6443/api/v1/namespaces/default
  3. {
  4. "kind": "Namespace",
  5. "apiVersion": "v1",
  6. "metadata": {
  7. "name": "default",
  8. "selfLink": "/api/v1/namespaces/default",
  9. "uid": "2b9536d0-c5b3-4977-9476-440588ef95a1",
  10. "resourceVersion": "157",
  11. "creationTimestamp": "2021-08-04T09:40:04Z",
  12. "managedFields": [
  13. {
  14. "manager": "kube-apiserver",
  15. "operation": "Update",
  16. "apiVersion": "v1",
  17. "time": "2021-08-04T09:40:04Z",
  18. "fieldsType": "FieldsV1",
  19. "fieldsV1": {"f:status":{"f:phase":{}}}
  20. }
  21. ]
  22. },
  23. "spec": {
  24. "finalizers": [
  25. "kubernetes"
  26. ]
  27. },
  28. "status": {
  29. "phase": "Active"
  30. }
  31. }[root@kube-master-01 manifests]#

ServiceAccount及认证

  • 运行过程中,Pod资源里的容器进程在某些场景中需要调用kubernetes API或者其他类型的服务,而这些服务通常需要认证客户端身份,如调度器,Pod控制器或节点控制器,甚至是获取启动容器的镜像访问的私有registry服务等。服务账户就是用于让Pod对象内的容器进程访问其他服务时提供身份证信息的账户。一个serviceaccount资源一般由用户名及相关的secret对象组成
  • kubernetes原生的应用程序意味着专为运行于kubernetes系统之上而研发的应用程序,这些程序托管在kubernetes之上,能够直接与API Server进行交互,并进行资源状态的查询或更新,例如flannel和CoreDNS等。显然,API Server同样需要对这类来自Pod资源中的客户端程序进行身份验证,账户服务也是专用于这类场景的账号。serviceaccount资源一般由用户身份信息及保存了认证信息的secret对象组成

Service Account自动化

  • 此前我们创建的每个Pod资源都自动关联到了一个存储卷,并尤其容器挂载至默认路径/var/run/secrets/kubernetes,io/serviceaccout目录。例如,使用kubectl describe pod pod_name命令显示的某Pod对象描述信息的片段:
  1. Containers
  2. ...
  3. Mounts:
  4. /etc/config from config-volume (ro)
  5. /etc/config/alert_rules.d from prometheus-alter-rules (ro)
  6. /etc/localtime from sync-time (rw)
  7. /var/run/secrets/kubernetes.io/serviceaccount from prometheus-token-k7dhw (ro)
  8. Volumes:
  9. prometheus-token-k7dhw:
  10. Type: Secret (a volume populated by a Secret)
  11. SecretName: prometheus-token-k7dhw
  12. Optional: false
  • 各容器的该挂载点目录中通常存在3个文件:ca.crt、namespace和token,其中,token文件保存了serviceaccount的认证令牌,容器中的进程使用该账户认证到API Server,进而由认证插件完成用户认证并将其用户名传递给授权插件,每个Pod对象都只有一个服务账户,若创建Pod资源时未明确指定,则ServiceAccount准入控制器会为其自动附加当前名称空间中默认的服务账户,其名称通常为default
  1. [root@jenkins prometheus-monitor]# kubectl describe serviceaccount default
  2. Name: default
  3. Namespace: default
  4. Labels: <none>
  5. Annotations: <none>
  6. Image pull secrets: <none>
  7. Mountable secrets: default-token-2hs6d
  8. Tokens: default-token-2hs6d
  9. Events: <none>
  10. [root@jenkins prometheus-monitor]#
  • kubernetes系统通过三个独立的组件间的相互协作来实现服务账户的自动化,三个组件具体为:ServiceAccount准入控制器,令牌控制器(token controller)和serviceAccount控制器。serviceaccount控制器负责为名称空间管理相应的资源,它需要确保每个名称空间中都存在一个名为default的服务账户对象。ServiceAccount准入控制器是API Server服务的一部分,它内置在API Server中,负责在创建或更新Pod时按需进行ServiceAccount资源对象相关信息的修改,这包括如下操作
    • 若Pod没用明确定义使用的ServiceAccount对象,则将其设置为”default”
    • 若Pod显式引用了ServiceAccount,则负责检查被引用的对象是否存在,不存在时将拒绝Pod资源的创建请求
    • 若Pod中不包含imagePullSecrets,则把ServiceAccount的imagePullSecrets附加其上
    • 为带有访问API的令牌的Pod对象添加一个存储卷
    • 为Pod对象中的每个容器添加一个volumeMounts,将ServiceAccount的存储卷挂载至/var/run/secret/kubernetes.io/serviceaccount
  • 令牌控制器是controller-manager的子组件,工作于异步模式。其负责完成的任务具体如下:
    • 监控Service Account的创建操作,并为其添加用户访问API的Secret对象
    • 监控Service Account的删除操作,并删除其相关的所有serviceaccount令牌密钥
    • 监控Secret对象的添加操作,确保其需要引用的serviceaccount存在,并在必要时为secret对象添加认证令牌
    • 监控Secret对象的删除操作,以确保删除每个serviceaccount中对此secret的引用
  • 需要注意的是,为确保完整性等,必须为kube-controller-manager使用--service-account-private-key-file选项指定一个私钥文件,用于对生成的ServiceAccount令牌进行签名,该私钥文件必须是PEM格式。同时,还要为kube-apiserver使用--service-account-key-file指定与前面的私钥配对的公钥文件,用于在认证期间对认证令牌进行校验

Service Account基础应用

  • ServiceAccount是kubernetes API 上的一种资源类型,它属于名称空间级别,用于让Pod对象内部的应用程序在与API Server通信时完成身份认证。如前所述,同样名为serviceaccount的准入控制器实现了服务账户自动化,该准入控制器为每个名称空间都自动生成了一个名为default的默认资源对象。如下面的命令结果所显示,其可用于让Pod对象有权限读取同一名称空间中的其他资源对象的元数据信息。需要赋予Pod对象更多操作权限时,则应该由用户按需创建自定义的serviceaccount资源
  1. [root@jenkins prometheus-monitor]# kubectl get serviceaccount --all-namespaces
  2. NAMESPACE NAME SECRETS AGE
  3. default default 1 29d
  4. frontend default 1 22d
  5. ingress-nginx default 1 13d
  6. ingress-nginx ingress-nginx 1 13d
  7. ingress-nginx ingress-nginx-admission 1 13d
  8. kube-node-lease default 1 29d
  9. kube-ops default 1 23d
  10. kube-ops prometheus 1 9d
  11. kube-public default 1 29d
  12. kube-system attachdetach-controller 1 29d
  13. kube-system bootstrap-signer 1 29d
  14. kube-system certificate-controller 1 29d
  15. kube-system clusterrole-aggregation-controller 1 29d
  16. kube-system coredns 1 29d
  17. kube-system cronjob-controller 1 29d
  18. kube-system daemon-set-controller 1 29d
  19. kube-system default 1 29d
  20. kube-system deployment-controller 1 29d
  21. kube-system disruption-controller 1 29d
  22. kube-system endpoint-controller 1 29d
  23. kube-system endpointslice-controller 1 29d
  24. kube-system endpointslicemirroring-controller 1 14d
  25. kube-system expand-controller 1 29d
  26. kube-system filebeat 1 7d22h
  27. kube-system flannel 1 10d
  28. kube-system generic-garbage-collector 1 29d
  29. kube-system horizontal-pod-autoscaler 1 29d
  30. kube-system job-controller 1 29d
  31. kube-system kube-proxy 1 29d
  32. kube-system kube-state-metrics 1 9d
  33. kube-system namespace-controller 1 29d
  34. kube-system node-controller 1 29d
  35. kube-system persistent-volume-binder 1 29d
  36. kube-system pod-garbage-collector 1 29d
  37. kube-system pv-protection-controller 1 29d
  38. kube-system pvc-protection-controller 1 29d
  39. kube-system replicaset-controller 1 29d
  40. kube-system replication-controller 1 29d
  41. kube-system resourcequota-controller 1 29d
  42. kube-system service-account-controller 1 29d
  43. kube-system service-controller 1 29d
  44. kube-system statefulset-controller 1 29d
  45. kube-system token-cleaner 1 29d
  46. kube-system ttl-controller 1 29d
  47. [root@jenkins prometheus-monitor]#
  • 每个Pod对象可附加其所属名称空间中的一个serviceaccount资源,且只能附加一个。不过,一个serviceaccount资源可以被同一个名称空间当中的多个Pod对象共享使用。创建Pod资源时,用户可以使用.spec.serviceAccountNmae属性直接指定需要使用的serviceaccout对象。或者省略此字段让其自动附加当前名称空间中默认的serviceaccount(default),以确保每个Pod对象至少基于该服务账户有权限读取当前名称空间中其他资源对象的元素据信息
  • kubernetes也支持用户按需创建ServiceAccount资源并将其指定到特定应用的Pod对象之上,结合集群启用的授权机制为该serviceaccount资源赋予所需要的更多权限,从而构建出更加灵活的权限委派模型

创建serviceaccount对象

  • serviceaccount资源对象创建的方式同样也有两种
    • 基于命令式的方式进行创建,使用命令kubectl create serviceaccount serviceaccount_name进行创建
    • 使用资源配置清单的方式进行创建

使用命令方式创建serviceaccount

  1. [root@jenkins prometheus-monitor]# kubectl create serviceaccount my-service-account
  2. serviceaccount/my-service-account created
  3. [root@jenkins prometheus-monitor]
  • kubernetes会为创建的serviceaccount资源自动生成并附加一个secret对象,该对象以serviceaccount资源名称为前缀,如下面命令的执行结果所示
  1. [root@jenkins prometheus-monitor]# kubectl get serviceaccount/my-service-account -o jsonpath={.secrets[0].name}
  2. my-service-account-token-dftwd
  3. [root@jenkins prometheus-monitor]#
  • 该secret对象隶属于特殊的kubernetes.io/service-account-token类型,它包含ca.crt,namespace和token这三个数据项,他们分别包含kubernetes Root CA证书,Secret对象所属的名称空间和访问API Server的令牌。由Pod对象以Secret存储卷的方式将该类型的secret对象挂载至/var/run/secrets/kubernetes.io/serviceaccount目录后,这三个数据项映射为同名的三个文件
  1. [root@jenkins prometheus-monitor]# kubectl get secrets/my-service-account-token-dftwd -o yaml
  2. apiVersion: v1
  3. data:
  4. ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeE1EZ3dOREE1TXprek9Gb1hEVE14TURnd01qQTVNemt6T0Zvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBSjQxCng4Qm5YcVZjcnM3cGRxd2FyOG50dDI3K291U29aa2o0emxFOUcrNElMZnNnWWNFQTJHcmNCbFg4VElqUDNNY3AKUkJZT2pwL1ZYY210QU4vbUpjWnFEQmUyWVFJZ3FmRDUwMHB5NVJkS2t5Z1NTanhJWDNWYmExblpkbExFTTIvUApKdC9tcG0xRXhFU0Z3eUJjck5oR1U4YXFWcjk1ZWFTTVBvRlZNVXJ4R0trcGZCMHFmMXJVWTZac3M2ZFJucXd6CkVnUktlZFgyRTFoL002bnA0N25vaUNtaXpYbm0xRU1zV3ozdXV4VmQwVVl1NnhZRDFQWmR0eXpmajh5Wi9wQlkKb0g0cDh3T29JeHRTYURHWmU5ZndjNHhTdkl3bWtpbUg5ZEVJcU56dUV1bE4vL0FJUEhob2JnSXh4eEVtMWg3QgpVaFlMRVhxM3BMREw1Vm1LdS84Q0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFKZDAwSFZBMnFTMXpkYXZ4VUYyVHdOU0dxdWYKZ0hkek0vT2ZYSVpLYWI2UThNVFJReVlkazhtbjQydWl6VkVhQTNwM1VXTXJsUTI5UzQ0aUUySjBqT09RVnZSNwpKUHlrMGVmN2pnTklKU0VKdXAvMjdkV2R4Ymt3V05lK0VwRDJCd0dPUUJQUXVneXllK1FEVUpIdDlhVUxQMEZjCmh5SkpmRWdzcVUxRk0rbVNaSHNrNG1CZ2UvQ0Z3T0FZNEVWb3l0YkxvMnZCUCtaZ1BZTlV2THJrWkhncmFtNUMKMmJ3eEJxRDFmdTBoUENUNE5LVmQzSWdSV1JDNTY3dy9iOGJiRnh4aWpKanhERXk0VUNDeGFidkgvNmlqbGNBNgo0T3gwT1h3aGx1ellrM0tXdTVsZG1KenJBdDYycUwxZVRFRDNuY2xjc1dPNlRrQkkwNUZvVG1RQm9icz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
  5. namespace: ZGVmYXVsdA==
  6. token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNkluSlVVVFF5VjNWNFlVZFZkWGd6YUVsRU5URjJhVVJWTXpCdmFuZEVjbmhwWXpGWFJrUjNVa1ZuY204aWZRLmV5SnBjM01pT2lKcmRXSmxjbTVsZEdWekwzTmxjblpwWTJWaFkyTnZkVzUwSWl3aWEzVmlaWEp1WlhSbGN5NXBieTl6WlhKMmFXTmxZV05qYjNWdWRDOXVZVzFsYzNCaFkyVWlPaUprWldaaGRXeDBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5elpXTnlaWFF1Ym1GdFpTSTZJbTE1TFhObGNuWnBZMlV0WVdOamIzVnVkQzEwYjJ0bGJpMWtablIzWkNJc0ltdDFZbVZ5Ym1WMFpYTXVhVzh2YzJWeWRtbGpaV0ZqWTI5MWJuUXZjMlZ5ZG1salpTMWhZMk52ZFc1MExtNWhiV1VpT2lKdGVTMXpaWEoyYVdObExXRmpZMjkxYm5RaUxDSnJkV0psY201bGRHVnpMbWx2TDNObGNuWnBZMlZoWTJOdmRXNTBMM05sY25acFkyVXRZV05qYjNWdWRDNTFhV1FpT2lJNFl6SmlObVpoTXkwMU1XVm1MVFE0TkRRdE9XRTVOUzA0TURBMVl6aGpPREl5Wm1ZaUxDSnpkV0lpT2lKemVYTjBaVzA2YzJWeWRtbGpaV0ZqWTI5MWJuUTZaR1ZtWVhWc2REcHRlUzF6WlhKMmFXTmxMV0ZqWTI5MWJuUWlmUS5hRGVjTFQweVduWFZhYnFNV0ZRazdrYThlT3ZmS2pYTmRiTkhNZ29vLVA0aEdldmFONVNreW4tWTQ5MUtGVVVldktrbVFuRlBaQU9VNWIxbi1rLTBnQktlMlBRY25TOE1rengxQkhYUTYwMlVEendGSUtmZlo1a0VQLW8zbVNaRHZUa2hXcVdLZFVLdG1rbk4tNXJyQVJWTWh4TGE5cmlkLWRWTzlJZzBtVDJDYUtYSURjY1JtVnlmd2ZsX0g3TFBVR0lyYXpBdF9FV0piYUM2ZmtUMi1vdHU4ZEl0OEVYajVpMXlsbDJkVDF1TzU0a0JCMllhbG15NjlXY1pwRFR1UU5jd01YU3RoSW9SZkRkQUhiNWNrRFVjcldlLTVieFdEWm5vZExqTk1yMTRDUWJobzl5aEF3dEc4azA1YnlJYzV5Umc5NHBjVUgyQkZWbksyQWJ0TEE=
  7. kind: Secret
  8. metadata:
  9. annotations:
  10. kubernetes.io/service-account.name: my-service-account
  11. kubernetes.io/service-account.uid: 8c2b6fa3-51ef-4844-9a95-8005c8c822ff
  12. creationTimestamp: "2021-09-03T03:01:45Z"
  13. managedFields:
  14. - apiVersion: v1
  15. fieldsType: FieldsV1
  16. fieldsV1:
  17. f:data:
  18. .: {}
  19. f:ca.crt: {}
  20. f:namespace: {}
  21. f:token: {}
  22. f:metadata:
  23. f:annotations:
  24. .: {}
  25. f:kubernetes.io/service-account.name: {}
  26. f:kubernetes.io/service-account.uid: {}
  27. f:type: {}
  28. manager: kube-controller-manager
  29. operation: Update
  30. time: "2021-09-03T03:01:45Z"
  31. name: my-service-account-token-dftwd
  32. namespace: default
  33. resourceVersion: "6844471"
  34. selfLink: /api/v1/namespaces/default/secrets/my-service-account-token-dftwd
  35. uid: 5ba96782-e213-4dca-b911-971273a420df
  36. type: kubernetes.io/service-account-token
  37. [root@jenkins prometheus-monitor]#

使用资源清单方式创建

  • 事实上,以资源规范式创建Secret对象时,以类似如上命令结果的形式,为Secret对象使用资源注解kubernetes.io/service-account.name引用一个现存的serviceaccount对象,并指定资源类型为特定的kubernetes.io/service-account-token,我们便可以将指定的serviceaccount对象引用的secret对象予以置换,该sercret对象同样会自动生成固定的三个数据项
  • 更完善的创建serviceaccout资源的方式是使用配置清单,serviceaccout的资源清单比较简单,它没用spec字段,而是将几个关键定义直接通过一级字段给出,具体的清单配置格式如下:
  1. apiVersion: v1 #ServiceAccount所属的API群组及版本
  2. kind: ServiceAccount #资源类型标识
  3. metada:
  4. name: <string> #资源名称
  5. namespace: <> #所属的名称空间,serviceaccount是名称空间级别的资源
  6. automountServiceAccountToken: <boolean> #是否让Pod自动挂载API令牌
  7. secrets: <[]Object> #以该SA运行的Pod需要使用的secret对象组成的列表
  8. apiVersion: <string> #引用的secret对象所属的API群组及版本,可省略
  9. kind: <string> #引用的资源类型,这是指secret,可省略
  10. name: <string> #引用的secret对象的名称,通常仅给出该字段即可
  11. namespace: <string> #引用的secret对象所属的名称空间
  12. uid: <string> #引用的secret对象的标识符
  13. imagePullSecrets: <[]Object> #引用的用于下载Pod种容器镜像的secret对象列表
  14. name: <string> #docker-registr类型的secret资源名称
  • 下面的配置清单是一个serviceaccount资源示例,它位于serviceaccount-demo.yaml文件中,它仅指定了资源名称,以及运行Pod对象将其自动挂载为存储卷,引用的secret对象则交由系统自动生成
  1. apiVersion: v1
  2. kind: ServiceAccount
  3. metadata:
  4. name: namespace-admin
  5. namespace: default
  6. automountServiceAccountToken: true
  • 将配置清单种的namespace-admin资源创建到集群上,serviceaccount控制器会自动为其附加以该资源名称为前缀的secret对象。如下面的命令结果所示。
  • 随后,用户便可以在创建的Pod对象上引用该自定义的serviceaccount对象,以借助权限管理机制实现自主控制Pod对象资源访问权限
  • Pod向API Server发出请求时,其携带的认证令牌在通过认证后将由授权插件来判定相关的serviceaccount是否有权限访问其所请求的资源。kubernetes支持多种授权插件,由管理员负责选定及配置,RBAC是目前较为主流的选择
  1. [root@jenkins serviceaccount]# kubectl apply -f serviceaccount-demo.yaml
  2. serviceaccount/namespace-admin created
  3. [root@jenkins serviceaccount]#
  4. [root@jenkins serviceaccount]# kubectl get serviceaccount/namespace-admin -o jsonpath={.secrets[0].name}
  5. namespace-admin-token-gmpv8
  6. [root@jenkins serviceaccount]#

调用imagePullSecret资源对象

  • ServiceAccount资源还可以基于.spec.imagePullSecret字段附带一个由下载镜像专用的Secret资源组成的列表,让Pod对象在创建容器时且从私有镜像仓库下载镜像文件之前完成身份认证。下面的示例定义了一个从本地私有仓库Harbor下载镜像文件时的Secret对象信息的ServiceAccount
  1. apiVersion:
  2. kind: ServiceAccount
  3. metadata:
  4. name: docker-registry
  5. namespace: default
  6. imagePullSecrets:
  7. - name: local-harbor-secret
  • 其中local-harbor-secret是docker-registry类型的secret对象,由用户提前手动创建,它可以通过键值数据提供镜像仓库服务器的地址,用户名,密码及用户的电子邮件等信息。认证通过后,引用了此serviceaccount的Pod资源即可从指定的镜像仓库中下载由image字段指定的镜像文件

Pod资源上使用ServiceAccount

  • 借助权限分配模型,按需应用”最小权限法则”将不同的资源操作权限配置给不同的账户,是有效降低安全风险的法则之一。有相当一部分kubernetes原生应用程序依赖的权限都会大于Pod默认Serviceaccount继承到的权限,且彼此间各有不同,为这类应用定制一个专有的ServiceAccount并授予所需要的全部权限是主流解决方案
  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: pod-with-sa
  5. namespace: default
  6. spec:
  7. serviceAccountName: namespace-admin
  8. containers:
  9. - name: adminbox
  10. image: harbor.hub.shzhanmeng.com/toolbox/admin-toolbox:v1.0
  11. imagePullPolicy: IfNotPresent
  • 该Pod资源创建完成后会以Secret存储卷的形式自动挂载serviceaccont/namespace-admin的secret对象,如下面的命令结果所示
  1. [root@jenkins serviceaccount]# kubectl apply -f pod.yaml
  2. pod/pod-with-sa created
  3. [root@jenkins serviceaccount]#
  4. [root@jenkins serviceaccount]# kubectl get pods/pod-with-sa -o jsonpath='{range .spec.volumes[*]}{.name}{end}'
  5. namespace-admin-token-gmpv8
  6. [root@jenkins serviceaccount]#
  • Secret对象默认的挂载路径是/var/run/secrets/kubernetes.io/serviceaccount。与API Server交互时,工作负载进程会使用该目录下的ca.crt证书文件验证API Server的服务器证书是否为自己信任的证书颁发机构(所在kubernetes-ca)所签发;验证服务器身份成功通过后,工作负载向API Server请求操作namespace文件指定的名称空间中的资源时,会将token文件中的令牌以承载令牌的方式提交给API Server进行验证,权限校验则由授权插件完成。我们可以在pods/pod-with-sa的交互式接口中进行访问测试

  • 切换到pod容器里面,进入到secret对象的挂载点,以便于加载所需要的文件

  1. [root@jenkins serviceaccount]# kubectl exec -ti pod-with-sa /bin/bash
  2. kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
  3. [root@pod-with-sa /]$ cd /var/run/secrets/kubernetes.io/serviceaccount/
  4. [root@pod-with-sa /var/run/secrets/kubernetes.io/serviceaccount]$
  5. [root@pod-with-sa /var/run/secrets/kubernetes.io/serviceaccount]$ ls
  6. ca.crt namespace token
  7. [root@pod-with-sa /var/run/secrets/kubernetes.io/serviceaccount]$
  • 在容器中使用curl命令向API Server发起访问请求,--cacert选项用于指定验证服务器服务端的CA证书,而-H选项用于定义头部,它指定了使用的承载令牌;下面的命令使用了”命令引用”机制来加载token和namespace文件的内容,其结果显示容器进程使用指定的serviceaccount进行身份认证成功,但是无权限访问资源
  1. [root@pod-with-sa /var/run/secrets/kubernetes.io/serviceaccount]$ curl --cacert ca.crt -H "Authorization: Bearer $(cat token)" https://kubernetes/api/v1/namespaces/$(cat namespace)
  2. {
  3. "kind": "Status",
  4. "apiVersion": "v1",
  5. "metadata": {
  6. },
  7. "status": "Failure",
  8. "message": "namespace \"default\" is forbidden: User \"system:serviceaccount:default:namespace-admin\" cannot get resource \"namespace\" in API group \"\" at the cluster scope",
  9. "reason": "Forbidden",
  10. "details": {
  11. "name": "default",
  12. "kind": "namespace"
  13. },
  14. "code": 403
  15. }[root@pod-with-sa /var/run/secrets/kubernetes.io/serviceaccount]$
  • 接下来,单独向serviceaccount/namespace-admin授权,允许其管理default名称空间内的资源,pods/pod-with-sa中的进程便能借助该serviceaccount的身份来管理相应名称空间下的资源,这可以使用类似于向普通用户ilinux授权的方式进行

  • 切换到kubernetes集群的管理节点,使用kubectl运行如下命令

  1. [root@jenkins serviceaccount]# kubectl create rolebinding namespace-admin-binding-admin --clusterrole=admin --serviceaccount=default:namespace-admin -n default
  2. rolebinding.rbac.authorization.k8s.io/namespace-admin-binding-admin created
  3. [root@jenkins serviceaccount]#
  • 回到pod-with-sa容器内部,再次运行命令访问default名称空间的资源。事实上,它拥有该名称空间中所有资源的CRUD权限
  1. [root@pod-with-sa /var/run/secrets/kubernetes.io/serviceaccount]$ curl --cacert ca.crt -H "Authorization: Bearer $(cat token)" https://kubernetes/api/v1/namespaces/$(cat namespace)
  2. {
  3. "kind": "Namespace",
  4. "apiVersion": "v1",
  5. "metadata": {
  6. "name": "default",
  7. "selfLink": "/api/v1/namespaces/default",
  8. "uid": "2b9536d0-c5b3-4977-9476-440588ef95a1",
  9. "resourceVersion": "157",
  10. "creationTimestamp": "2021-08-04T09:40:04Z",
  11. "managedFields": [
  12. {
  13. "manager": "kube-apiserver",
  14. "operation": "Update",
  15. "apiVersion": "v1",
  16. "time": "2021-08-04T09:40:04Z",
  17. "fieldsType": "FieldsV1",
  18. "fieldsV1": {"f:status":{"f:phase":{}}}
  19. }
  20. ]
  21. },
  22. "spec": {
  23. "finalizers": [
  24. "kubernetes"
  25. ]
  26. },
  27. "status": {
  28. "phase": "Active"
  29. }
  30. }[root@pod-with-sa /var/run/secrets/kubernetes.io/serviceaccount]$
  • 但是,default名称空间引用了serviceaccounts/default资源中Pod的容器进程却不具有如上权限,因为他们并未获得相应的授权。事实上,kube-system名称空间中的许多应用都使用了专用的serviceaccount资源,例如flannel,CoreDNS,kube-proxy以及多种控制器等。有兴趣的朋友可以自行通过命令了解相应的serviceaccount资源信息