K8s学习笔记 (9)
@ wgjak47 | 星期三,七月 31 日,2019 年 | 8 分钟阅读 | 更新于 星期三,七月 31 日,2019 年

k8s学习笔记

身份与权限认证

Kubernetes中提供了良好的多租户认证管理机制,如RBAC、ServiceAccount还有各种Policy等。

Service Account

  • 当用户访问集群时,apiserver 会将用户认证为一个特定的 User Account(目前通常是admin,除非您的系统管理员自定义了集群配置)。
  • Pod容器访问集群时也会被认证为一个特定的Service Account (例如default)

使用默认的 Service Account 访问 API server

  • 创建Pod时未指定service account(spec.serviceAccountName),会自动在pod的namespace下分配一个default service account。
  • 可以使用pod中自动挂在的/var/run/secrets/kubernetes.io/serviceaccount/token service account凭证来访问apiserver
  • 通过automountServiceAccountToken: false,来取消自动挂载API凭证,可以是全局也可以是指定的Pod,其中Pod的优先级更高一些

使用多个Service Account

  • 每个 namespace 中都有一个默认的叫做 default 的 service account 资源。
  • 可以创建一个SerivceAccount对象:
$ cat > /tmp/serviceaccount.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
EOF
$ kubectl create -f /tmp/serviceaccount.yaml
serviceaccount "build-robot" created
  • 通过授权插件来设置service account的权限
  • 指定spce.serviceAccountName来设置使用的serviceAccount
  • Pod的service Account一旦创建就无法更改

手动创建 service account 的 API token

$ cat > /tmp/build-robot-secret.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
name: build-robot-secret
annotations:
# 指定要更换token的service account
kubernetes.io/service-account.name: build-robot
type: kubernetes.io/service-account-token
EOF
$ kubectl create -f /tmp/build-robot-secret.yaml
secret "build-robot-secret" created

为 service account 添加 ImagePullSecret

ImagePullSecret创建参见:https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod

cat <<EOF > pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: foo
namespace: awesomeapps
spec:
containers:
- name: foo
image: janedoe/awesomeapp:v1
imagePullSecrets:
- name: myregistrykey
EOF

RBAC 基于角色的访问控制

基于角色的访问控制(Role-Based Access Control, 即”RBAC”)使用”rbac.authorization.k8s.io” API Group实现授权决策,允许管理员通过Kubernetes API动态配置策略。 要启用RBAC,请使用–authorization-mode=RBAC启动API Server。

Role与ClusterRole

  • 一个角色包含了一套表示一组权限的规则
  • 权限以纯粹的累加形式累积
  • 角色可以由命名空间(namespace)内的Role对象定义, 只能用于授予对某一单一命名空间中资源的访问权限
  • 整个Kubernetes集群范围内有效的角色则通过ClusterRole对象实现,包括
  • 集群范围资源(例如节点,即node)
  • 非资源类型endpoint(例如”/healthz”)
  • 跨所有命名空间的命名空间范围资源(pod)

例子,授予pod读访问权限:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # 空字符串""表明使用core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]

例子,授予所有命名空间中的secret的读访问权限:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
# 鉴于ClusterRole是集群范围对象,所以这里不需要定义"namespace"字段
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"]

RoleBinding与ClusterRoleBinding

  • 角色绑定将一个角色中定义的各种权限授予一个或者一组用户。
  • 角色绑定包含了一组相关主体(即subject, 包括用户——User、用户组——Group、或者服务账户——Service Account)以及对被授予角色的引用。
  • 在命名空间中可以通过RoleBinding对象授予权限
  • 集群范围的权限授予通过ClusterRoleBinding对象完成。

例子,允许用户”jane”从”default”命名空间中读取pod

# 以下角色绑定定义将允许用户"jane"从"default"命名空间中读取pod。
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io

对资源的引用

对于像pod的logs这种子资源,需要使用线来划分资源 与子资源:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list"]

还可以通过设置resourceNames将”get”、”delete”、”update”以及”patch”等动词的请求限定到资源列表中所包含的资源实例上:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: configmap-updater
rules:
# 只能更新/获取名为my-configmap的configmap对象
- apiGroups: [""]
resources: ["configmap"]
resourceNames: ["my-configmap"]
verbs: ["update", "get"]

注意:如果设置了resourceNames,则请求所使用的动词不能是list、watch、create或者deletecollection。

Subject

  • Subject可以是Group,User或者Service Account
  • User/Group名称由字符串表示,但是不能以system:为前缀,因为后者是kubernetes保留的
  • ServiceAccount拥有包含 system:serviceaccount:前缀的用户名,并属于拥有system:serviceaccounts:前缀的用户组。

例子:

subjects:
- kind: Group
name: "frontend-admins"
apiGroup: rbac.authorization.k8s.io

默认角色与默认角色绑定

  • API Server会创建一组默认的ClusterRole和ClusterRoleBinding对象,有许多包含system:前缀,表明这些资源由Kubernetes基础组件”拥有”。
  • 修改这些组件可能会导致k8s无法工作
  • 所有默认的ClusterRole和ClusterRoleBinding对象都会被标记为kubernetes.io/bootstrapping=rbac-defaults
  • 每次启动时,API Server都会更新默认ClusterRole所缺乏的各种权限,并更新默认ClusterRoleBinding所缺乏的各个角色绑定主体。 这种自动更新机制允许集群修复一些意外的修改。由于权限和角色绑定主体在新的Kubernetes释出版本中可能变化,这也能够保证角色和角色 绑定始终保持是最新的。

默认角色列表

https://kubernetes.io/docs/reference/access-authn-authz/rbac/#default-roles-and-role-bindings

初始化与预防权限升级

  • RBAC API会阻止用户通过编辑角色或者角色绑定来升级权限。
  • 用户只有在拥有了角色所包含的所有权限的条件下才能创建/更新一个角色,这些操作还必须在角色所处的相同范围内进行
  • 为了能够让用户创建/更新角色,需要
  • 授予用户一个角色以允许他们根据需要创建/更新Role或者ClusterRole对象。
  • 授予用户一个角色包含他们在Role或者ClusterRole中所能够设置的所有权限。如果用户尝试创建或者修改Role或者ClusterRole以设置那些他们未被授权的权限时,这些API请求将被禁止。
  • 用户只有在拥有所引用的角色中包含的所有权限时才可以创建/更新角色绑定(这些操作也必须在角色绑定所处的相同范围内进行)或者用户被明确授权可以在所引用的角色上执行绑定操作。
  • 为了能够让用户创建/更新角色绑定,需要:
  • 授予用户一个角色以允许他们根据需要创建/更新RoleBinding或者ClusterRoleBinding对象。
  • 授予用户绑定某一特定角色所需要的权限:通过授予用户所有所引用的角色中所包含的权限或者通过授予用户在特定Role(或者ClusterRole)对象上执行bind操作的权限

Service Account权限最佳实践

对某一特定应用程序的服务账户授予角色,要求应用程序在其pod规范(pod spec)中指定serviceAccountName字段,并且要创建相应服务账户(例如通过API、应用程序清单或者命令kubectl create serviceaccount等)。

例如,在”my-namespace”命名空间中授予服务账户”my-sa”只读权限:

kubectl create rolebinding my-sa-view \
--clusterrole=view \
--serviceaccount=my-namespace:my-sa \
--namespace=my-namespace

Network Policy

网络策略说明一组 Pod 之间是如何被允许互相通信,以及如何与其它网络 Endpoint 进行通信。 NetworkPolicy 资源使用标签来选择 Pod,并定义了一些规则,这些规则指明允许什么流量进入到选中的 Pod 上。 Network Policy 的作用对象是 Pod,也可以应用到 Namespace 和集群的 Ingress、Egress 流量。Network Policy 是作用在 L3/4 层的,即限制的是对 IP 地址和端口的访问,如果需要对应用层做访问限制需要使用如 Istio 这类 Service Mesh。

前提条件

网络策略通过网络插件来实现,所以必须使用一种支持 NetworkPolicy 的网络方案(如 calico)—— 非 Controller 创建的资源,是不起作用的。

隔离的与未隔离的 Pod

默认 Pod 是未隔离的,它们可以从任何的源接收请求。 具有一个可以选择 Pod 的网络策略后,Pod 就会变成隔离的。 一旦 Namespace 中配置的网络策略能够选择一个特定的 Pod,这个 Pod 将拒绝任何该网络策略不允许的连接。(Namespace 中其它未被网络策略选中的 Pod 将继续接收所有流量)

NetworkPolicy 资源

例子:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
# 选中的pod
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
# 入站规则
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
# 出站规则
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978

默认策略

通过创建一个可以选择所有 Pod 但不允许任何流量的 NetworkPolicy,你可以为一个 Namespace 创建一个 “默认的” 隔离策略,如下所示:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector:
matchLabels:
role: db

这确保了即使是没有被任何 NetworkPolicy 选中的 Pod,将仍然是被隔离的。 可选地,在 Namespace 中,如果你想允许所有的流量进入到所有的 Pod(即使已经添加了某些策略,使一些 Pod 被处理为 “隔离的”),你可以通过创建一个策略来显式地指定允许所有流量:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector:
ingress:
- {}