api访问控制
api访问控制:
客户端访问api-server时需要经过3个步骤:认证、鉴权、准入控制
三个步骤都是经由插件来实现,可多个插件同时使用,如认证插件有2个,其中一个认证通过就进入鉴权(权限检查)
文档: https://kubernetes.io/zh-cn/docs/concepts/security/controlling-access/
api传输安全
默认情况下,Kubernetes API 服务器监听localhost的https协议的6443端口, 受TLS保护。 该端口可以通过 --secure-port 变更,监听 IP 地址可以通过 --bind-address 选项变更。
API 服务器出示证书。该证书可以使用私有证书颁发机构(CA)签名,也可以基于链接到公认的 CA 的公钥基础架构签名。 该证书和相应的私钥可以通过使用 --tls-cert-file 和 --tls-private-key-file 标志进行设置。
如果集群使用自签证书,则需要在客户端的 ~/.kube/config 文件中提供该 CA 证书的副本, 以便信任该连接并确认该连接没有被拦截。
你的客户端可以在此阶段出示 TLS 客户端证书
访问认证:
认证模块包含客户端证书、密码、普通令牌、引导令牌和 JSON Web 令牌(JWT,用于服务账户)
可以指定多个认证模块,在这种情况下,服务器依次尝试每个验证模块,其中一个成功即可
如果请求认证不通过,服务器将以 HTTP 状态码 401 拒绝该请求。 反之,该用户被认证为特定的 `username`,并且该用户名可用于后续步骤以在其决策中使用。 部分验证器还提供用户的组成员身份,其他则不提供
请求鉴权:
请求验证为来自特定的用户后,必须被鉴权
请求必须包含请求者的用户名、请求的行为以及受该操作影响的对象。 如果现有策略声明用户有权完成请求的操作,那么该请求被鉴权通过,如: a对test命名空间有只读权限,当a读取test命名空间时,鉴权允许,若想创建pod,则被拒绝
k8s支持多种鉴权模块,管理员创建集群时,应在api-server中配置使用的鉴权模块。 若配置了多个鉴权模块,则 k8s 会检查每个模块,其中一个通过,请求通过; 若所有模块拒绝该请求,请求将会被拒绝(HTTP 状态码 403)。
准入控制:
准入控制器对创建、修改、删除对象的请求进行控制(不会对只读请求生效)。有多个准入控制器被配置时,服务器将依次调用它们
与身份认证和鉴权模块不同,如果任何准入控制器模块拒绝某请求,则该请求将立即被拒绝。
除了拒绝对象之外,准入控制器还可以为字段设置复杂的默认值。
请求通过所有准入控制器后,将使用检验例程检查对应的 API 对象,然后将其写入对象存储
访问认证:
文档: https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/authentication/
请求api-server的方式:
- 直接请求: curl -k -H "Authorization: Bearer sa的token" https://127.0.0.1:6443/api/v1/namespaces/default
- 请求代理: curl http://127.0.0.1:代理端口/api/v1/namespaces/default
api代理:
执行kubectl proxy命令,运行一个apiserver代理,本地的kubectl能直接访问apiserver是因为本地有配置文件定义了证书(~/.kube/config),而其他访问则没有证书,但可以开启代理,把kubectl当做服务运行,访问代理端口时,就能调用apiserver
kubectl proxy:
kubectl proxy
选项: #关于匹配的基本支持正则
--accept-hosts='^localhost$,^127\.0\.0\.1$,^\[::1\]$' #允许哪些主机访问此代理,支持正则、多个主机
--accept-paths='^.*' #允许访问哪些url,也就是请求对象
--address #监听地址,默认呢监听127.0.0.1
--keepalive=0s #启用长连接,默认0s关闭
-p 端口 #指定监听端口
--reject-methods='^$' #拒绝指定请求方法,支持正则,如:'POST,PUT,PATCH'
--reject-paths='^/api/.*/pods/.' #拒绝指定url请求,支持正则、多个url
例:
#默认监听127.0.0.1
kubectl proxy --port=6343 &
#监听所有端口
kubectl proxy --address 0.0.0.0 -p 6343 &
api访问:
访问api需要的内容:
api属性 | 含义 |
---|---|
user | username、uid。身份验证期间提供的字符串 |
group | 经过身份验证的用户所属的组名列表 |
extra | 由身份验证层提供的任意字符串键到字符串值的映射 |
api | 指示请求是否针对api资源 |
request path | 各种非资源端点的路径,如/api 、 /healthz |
apirequest verb | api动词 get、list、create、update、patch、watch、 proxy、redirect、delete、deletecollection 用于资源请求 |
http request verb | http 动词 get、post、put 和 delete 用于非资源请求 |
resource | 正在访问的资源的id或名称(仅限资源请求)- 对于使用 get、update、patch、delete动词的资源请求,你必须提供资源名称 |
subresource | 正在访问的子资源(仅用于资源请求) |
namespace | 正在访问的对象的名称空间(仅适用于名字空间资源请求) |
api group | 正在访问的api组(仅限资源请求)。空字符串表示核心api组 |
http请求方法:
- GET, HEAD
- POST
- PUT
- PATCH
- DELETE
确定请求方法:
非资源请求: 对除/api/v1/...
或之外的端点的请求/apis/<group>/<version>/...
被视为“非资源请求”,并使用请求的小写HTTP方法。如,GET对端点的请求就像/api
或/healthz
将get
用作动词。
资源请求: 要确定资源API端点的请求谓词,请查看使用的HTTP谓词以及请求是否作用于单个资源或资源集合
api访问url:
http://master主机:6443/apis/api资源组/版本/namespaces/命名空间/kind对象[/具体资源]/
#访问api代理,请求namespace中的default命名空间
curl http://127.0.0.1:6343/api/v1/namespaces/default
#获取k8s admin账号的token,直接访问api-server
token=$(kubectl describe secrets -n `kubectl get secrets -A |awk '/admin-user/{print $1,$2}'` |awk '/^token/{print $2}')
curl -kH "Authorization: Bearer $token" https://2.2.2.15:6443/api/v1/nodes
请求api-server时需要用到用户账号,用于包含:
- service账号(服务账号),为pod提供使用,此账号也可以提供私有docker仓库的认证
- user账号(普通账号),为外部访问apiserver使用
apiserver账号:
为pod提供使用,此账号也可以提供私有docker仓库的认证
serviceaccount资源:
1.22版本之前,创建sa账号后,会自动创建用于访问api的tonken,从1.22后,需要手动创建token
kubectl create serviceaccount | sa 账号
kubectl explain sa
apiVersion: v1
kind: ServiceAccount
medata:
automountServiceAccountToken: 布尔值 #true为自动挂载sa的令牌到pod,fasle为关闭
imagePullSecrets: #定义一组镜像拉取的密钥,这些密钥将被用于验证镜像拉取请求
- 密钥1
secrets: #定义了一组与这个服务账户关联的密钥
- 密钥1
创建token方法:
临时token
kubectl explain TokenRequest
kubectl create token sa用户 [选项]
apiVersion: authentication.k8s.io/v1
kind: TokenRequest
metadata:
name:
namespace:
spec:
audiences: #字符串数组,表示令牌的预期接收者。服务端会验证接收的令牌是否包含在这个列表中的接收者
- api
- istio-ca
boundObjectRef: #可选,将令牌绑定到一个特定的对象。绑定的对象必须在同一个命名空间中,并且必须是Pod或者Secret
kind: 类型
apiVersion: 版本
name: 名称
expirationSeconds: 时间 #过期时间
选项:
--bound-object-kind 类型 #token创建后自动关联的对象类型
#Pod
#Secret
--bound-object-name 名称 #关联的名称
--duration 时间 #创建的token是有有效期的
永久token
可参考前面secret内容
apiVersion: v1
kind: Secret
metadata:
name:
annotations:
kubernetes.io/service-account.name: sa帐户名
type: kubernetes.io/service-account-token
例: 创建一个sa账号,在pod中使用
1)创建service账号
kubectl create serviceaccount hj
kubectl describe sa hj
2)创建永久token
1.22版本之前不需要此步骤
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: t1-token-secret
annotations:
kubernetes.io/service-account.name: hj
type: kubernetes.io/service-account-token
EOF
3)创建pod
apiVersion: v1
kind: Pod
metadata:
name: pod-t1
namespace: default
labels:
app: my-t1
spec:
containers:
- name: t1-alpine
image: alpine
command: ["tail","-f","/etc/hosts"]
serviceAccountName: hj
user账号:
为外部访问apiserver使用
本身也是一个可配置的资源对象
查看:
kubectl config view
字段含义:
clusters(集群列表):
定义k8s的master节点,也就是apiserver的主机
users(账号列表):
定义具有访问apiserver资格的账号
contexts(上下文列表):
定义账号的集群的访问关系
如哪个账号可以访问哪个master节点,也可定义一个账号允许访问多个master节点
current-context(当前上下文):
显示当先正使用的上下文,也就是当前用哪个账号访问哪个集群
kubectl config命令:
kubectl config 子命令
current-context
delete-cluster
delete-context
delete-user
get-clusters
get-contexts
get-users
rename-context
set
set-cluster
set-context
set-credentials #添加账号
unset
use-context #切换当前上下文
view #显示kubeconfig文件信息
选项:
--client-certificate=certfile #设置客户端的证书文件路径。
--client-key=keyfile #设置客户端的私钥文件路径。
--token=自定义token #设置Bearer token用于身份验证。
--username=basic_user #设置基础身份验证的用户名。
--password=basic_password #设置基础身份验证的密码。
--exec-arg= #设置用于执行身份验证插件命令的参数。
--exec-env #设置用于执行身份验证插件命令的环境变量。
--exec-command #设置用于执行身份验证插件的命令。
--exec-api-version=api版本 #设置用于执行身份验证插件的API版本
#client.authentication.k8s.io/v1beta1
#client.authentication.k8s.io/v1
--auth-provider=oidc #设置身份验证提供者类型。
#azure,用于Azure Active Directory身份验证
#gcp,用于Google Cloud Platform身份验证
#oidc,用于OpenID Connect身份验证
#aws,用于Amazon Web Services身份验证
--auth-provider-arg=client-secret=bar #设置身份验证提供者的参数。
--embed-certs=true #如果为true,证书和密钥将被嵌入到kubeconfig文件中,否则,将只存储文件路径
添加用户时,首先要确认当前集群名称
例1: kubeadm部署集群,创建访问api-server的user账号
/etc/kubernetes/pki/ #kubeadm部署后的证书目录
1)生成私钥
cd /etc/kubernetes/pki
(umask 077;openssl genrsa -out hj.key 2048)
2)生成证书请求
openssl req -new -key hj.key -out hj.csr -subj "/CN=hj"
3)签发用户证书
openssl x509 -req -in hj.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out hj.crt -days 3650
openssl x509 -in hj.crt -text -noout
4)添加访问账号
kubectl config set-credentials hj --client-certificate=hj.crt --client-key=hj.key --embed-certs
kubectl config view
5)设置上下文
kubectl config set-context hj@kubernetes --cluster=kubernetes --user=hj
kubectl config view
6)切换当前上下文
kubectl config use-context hj@kubernetes
#此时由于切换了账号,是普通用户权限,就不能执行查看数据操作
kubectl get po #会报权限不够,因为还没有做鉴权允许
7)测试添加一个集群
#切换回原来管理员上下文
kubectl config use-context kubernetes-admin@kubernetes
#创建新集群配置
kubectl config set-cluster testcluster --kubeconfig=/tmp/test.conf --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://2.2.2.10:6443 --embed-certs
#查看创建的测试集群
kubectl config view --kubeconfig=/tmp/test.conf
例2: kubeasz集群,创建访问api-server的user账号
可以使用初始化时,已经生成好的k8s证书
/etc/kubernetes/ssl/ #kubeasz部署的ssl目录,本次使用
/etc/kubeasz/clusters/k8s-01/ssl/ #kubeasz部署时的所有ssl数据目录
使用cfssl工具,直接生成证书。cfssl是专门的证书制作工具,只能以json形式创建
1)写生成证书的json文件
cd /etc/kubeasz/clusters/k8s-01/ssl/
vim hj.json
{
"CN": "hj",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [{
"C": "CN",
"ST": "HB",
"L": "WH",
"O": "k8s",
"OU": "System"
}]
}
2)生成证书
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes hj.json | cfssljson -bare hj
4)添加访问账号到集群
kubectl config set-credentials hj --client-certificate=hj.pem --client-key=hj-key.pem --embed-certs
kubectl config view
kubectl config get-users
5)添加集群访问用户的上下文
#集群名称要对应当前管理员所在的集群
kubectl config set-context hj-cluster1 --cluster=cluster1 --user=hj --namespace=default
kubectl config view
6)切换当前集群访问用户的上下文
kubectl config use-context hj-cluster1
#此时由于切换了账号,是普通用户权限,没有授权资源,就不能执行查看数据操作
kubectl get po
7)创建一个测试集群
#切换上下文回原来的管理员
kubectl config use-context context-cluster1
#创建测试集群
kubectl config set-cluster testcluster --kubeconfig=/tmp/test.conf --certificate-authority=/etc/kubernetes/ssl/ca.pem --server=https://2.2.2.10:6443 --embed-certs
#查看创建的测试集群
kubectl config view --kubeconfig=/tmp/test.conf
请求鉴权:
鉴权插件:
- node #特殊用途的授权模式,为节点的kubelet授权
- abac #属性的访问控制
- rbac #角色的访问控制
- webhook #一般做开发时使用,使用http回调,做一些触发动作
操作权限:
get、list、create、update、patch、watch、proxy、watch、redirect、delete、detelecollection
RBAC(Role-based AC)基于角色的访问控制:
基于组织中用户的角色来调节控制对计算机或网络资源的访问的方法
注意: 关联过的角色,不能再修改,只能删除后重新关联
开启此功能:
kube-apiserver --authorization-mode=Example,RBAC #默认开启了rbac鉴权模式
命名空间资源:
- pods,pods/exec
- 各种控制器
- endpoints
- configmap
- secrets
- service
- ingress
- pvc
- events
集群资源:
- namespace
- node
- role
- clusterrole
- rolebinding
- clusterrolebind
- networkpolicies
- pv
- serviceaccounts
api对象:
对应关系: 把操作许可关联到角色,角色再关联账号
- Role #对命名空间内的资源授予访问权限
- ClusterRole #对集群级别的资源授予访问权限
- RoleBinding #将角色中定义的权限关联给一个或者一组用户,也就是取得命名空间权限,RoleBinding可以引用某ClusterRole
- ClusterRoleBinding #将集群角色的关联给用户
rolebinding和clusterrolebinding关联主体:
- user
- group
- serviceaccount
- role
特殊用法:RoleBinding关联ClusterRole
- 由于ClusterRole授权对象是整个集群,可一次性授权全部资源的访问权限,而RoleBinding是关联某个指定ns,可组合实现某个ns的管理员权限
- 当RoleBinding关联ClusterRole,可以获得整个集群所有资源,但由于RoleBinding只是ns层面,也就是集群资源不会生效,只有ns资源授权生效,且RoleBinding指定了一个ns,那么只有指定的ns资源授权生效
- 如果是Role就要给每个ns资源单独授权,ClusterRole避免了重复操作
role和clusterrole可授权资源:
- 资源组
- 资源
- 非资源的url
- 操作许可
RBAC配置语法:
Role语法:
kubectl explain role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
rules: #权限定义
apiGroups: #:定义规则适用于哪些API组
nonResourceURLs: #定义规则适用于哪些非资源的URL。如,"/healthz","/logs"等
resourceNames: #定义规则适用于哪些具体的资源实例。如果resources是"pods",那么resourceNames可以是特定的pod的名字
resources: #定义规则适用于哪些资源
verbs: #定义了对资源可以执行哪些操作。如,"get", "watch", "list", "create", "update", "delete"等
ClusterRole语法:
kubectl explain ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
aggregationRule: #定义了如何从其他ClusterRole中聚合规则。如果定义了这个字段,那么rules字段将被忽略
clusterRoleSelectors: #使用标签选择器,匹配集群角色
- matchExpressions:
key: 标签
operator: 操作符
#In: 标签的值在指定的列表中。
#NotIn: 标签的值不在指定的列表中。
#Exists: 标签存在。
#DoesNotExist: 标签不存在
values:
- 值1
matchLabels:
标签
rules: #规则,使用方法与role一样
apiGroups: 列表
nonResourceURLs: 列表
resourceNames: 列表
resources: 列表
verbs: 列表
RoleBinding:
kubectl explain RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
roleRef: #定义了被绑定的角色。包括apiGroup(API组)、kind(类型,可以是Role或ClusterRole)和name(角色名称)
apiGroup:
kind: 类型
name: 名称
subjects: #定义了绑定的主体,可以是user、group、sa。每个主体包括kind(类型)、name(名称)和namespace(命名空间,只对服务账户有效)
apiGroup:
kind:
name:
namespace: #仅在类型为sa时有效
ClusterRoleBinding
kubectl explain ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
roleRef:
apiGroup:
kind: 类型
name: 名称
subjects: #定义了绑定的主体,可以是user、group、sa。每个主体包括kind(类型)、name(名称)和namespace(命名空间,只对服务账户有效)
apiGroup:
kind:
name:
namespace: #仅在类型为sa时有效
案例:
例1: Role + RoleBindind
1)用命令生成模板
mkdir /data/role ;cd /data/role
kubectl create role pod-role --verb=get,list,watch --namespace=default --resource=pods --dry-run=client -o yaml > pod-role.yml
2)修改Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-role
namespace: default
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
3)进行role与账号关联
kubectl create rolebinding hj-read-pod --role=pod-role --namespace=default --user=hj --dry-run=client -o yaml > hj-rolebind.yml
kubectl apply -f .
4)查看rolebinding
kubectl describe rolebinding hj-read-pod
5)再次切换账号到hj
kubectl config use-context hj-cluster1
#再次查看,就具备了ns中default的权限,但没有别的ns访问权限
kubectl get po
例2:RoleBinding + ClusterRole
1)创建ClusterRole
kubectl create clusterrole cs-role --verb=* --resource=pods,pods/exec --dry-run=client -o yaml > cl-role.yml
kubectl apply -f cl-role.yml
kubectl describe clusterrole cs-role
2)RoleBinding关联ClusterRole
kubectl create rolebinding hj-role-ns --clusterrole=cs-role --user=hj --dry-run=client -o yaml > role-ns.yml
#此时hj账号就具有了default命名空间的管理权限,可以编辑,删除pod
kubectl describe rolebinding
例3: ClusterRole + ClusterRolebinding
1)创建集群角色
kubectl create clusterrole cs-role --verb=* --resource=pods --dry-run=client -o yaml > cl-role.yml
kubectl apply -f cl-role.yml
2)ns中rolebinding关联到集群role
kubectl create clusterrolebinding hj-clrole-bind --clusterrole=cs-role --user=hj --dry-run=client -o yaml > cl-rolebind.yml
kubectl apply -f cl-rolebind.yml
kubectl describe clusterrolebinding hj-clrole-bind
3)切换hj账号测试
kubectl config use-context hj-cluster1
#删除一个测试pod
kubectl delete pod pod-t1
#现在可以看到除了defualt命名空间以外的
kubectl get po -A
#最后切换回默认的管理员
kubectl config use-context context-cluster1