K8S之安全机制
# K8S之安全机制
Kubernetes通过一系列机制来实现集群的安全控制,其中包括APIServer的认证授权、准入控制机制及保护敏感信息的Secret机制等
集群安全性考虑几个目标:
(1)保证容器与其所在宿主机的隔离。
(2)限制容器给基础设施或其他容器带来的干扰。
(3)最小权限原则—合理限制所有组件的权限,确保组件只执行它被授权的行为,通过限制单个组件的能力来限制它的权限范围。
(4)明确组件间边界的划分。
(5)划分普通用户和管理员的角色。
(6)在必要时允许将管理员权限赋给普通用户。
(7)允许拥有Secret数据(Keys、Certs、Passwords)的应用在集群中运行。
# Secret私密凭据
Secret的主要作用是保管私密数据,比如密码(拉取私有镜像)、OAuth Tokens、SSH Keys等信息。 每个单独的Secret大小最好不能超过1MB,Kubernetes不鼓励创建大的Secret,使用的Secret,会占用API Server和kubelet的内存
在启动之前,如果Secret不存在或暂时无法连接到API Server,则kubelet按一定的时间间隔定期重试获取该Secret,并发送一个Event来解释Pod没有启动的原因。 在kubelet启动Pod中的Container后,Container中和Secret相关的Volume不会被改变,即使Secret本身被修改,除非删除pod,重新创建新的pod
使用方式:
(1)在创建Pod时,通过为Pod指定Service Account来自动使用该Secret。
(2)通过挂载该Secret到Pod来使用它。
(3)在Docker镜像下载时使用,通过指定Pod的spc.ImagePullSecrets来引用它。
(4)Secret分为 kubernetes.io/service-account-token、kubernetes.io/dockerconfigjson、Opaque 三种类型
# 创建Secret
查看帮助:kubectl create secret --help
- 方式一
echo admin > user
kubectl create ns devtest #空间名使用 devtest
kubectl create secret generic user --from-file=./user -n devtest
kubectl create secret generic passwd --from-literal=passwd=yfk123456 -n devtest
2
3
4
5
方式二
[root@manage-01 devtest_config]# echo admin |base64 YWRtaW4K [root@manage-01 devtest_config]# echo yfk123456 |base64 eWZrMTIzNDU2Cg==
[root@manage-01 secret]# cat testsecret.yaml
apiVersion: v1
kind: Secret
metadata:
name: testsecret
namespace: devtest
type: Opaque
data:
user: YWRtaW4K
passwd: eWZrMTIzNDU2Cg==
2
3
4
5
6
7
8
9
10
创建secret:kubectl apply -f testsecret.yaml
查看
[root@manage-01 secret]# kubectl get secrets -n devtest NAME TYPE DATA AGE default-token-8m289 kubernetes.io/service-account-token 3 5h12m passwd Opaque 1 49s testsecret Opaque 2 20m user Opaque 1 3m29s
# secret使用
# secret通过Volume挂载
apiVersion: v1
kind: Pod
metadata:
labels:
app: nginx-test
name: nginx-test
namespace: devtest
spec:
containers:
- image: nginx:1.20.2
name: nginx
volumeMounts:
- name: nginx-testsecret
mountPath: /opt/testsecret
readOnly: true
- name: nginx-testsecret2
mountPath: /opt/testsecret2
readOnly: true
volumes:
- name: nginx-testsecret
secret:
secretName: testsecret
- name: nginx-testsecret2
projected:
sources:
- secret:
name: user
- secret:
name: passwd
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
查看会发现,secretName里面有两个,会当作两个文件拷贝到容器里面,而不是像ConfigMap做软链接
[root@manage-01 secret]# kubectl exec -it -n devtest nginx-test cat /opt/testsecret/passwd
yfk123456
[root@manage-01 secret]# kubectl exec -it -n devtest nginx-test cat /opt/testsecret2/passwd
yfk123456
[root@manage-01 secret]# kubectl exec -it -n devtest nginx-test cat /opt/testsecret/user
admin
# secret配置到环境变量
apiVersion: v1
kind: Pod
metadata:
labels:
app: nginx-test
name: nginx-test
namespace: devtest
spec:
containers:
- image: nginx:1.20.2
name: nginx
env:
- name: sec_user
valueFrom:
secretKeyRef:
name: testsecret
key: user
- name: sec_passwd
valueFrom:
secretKeyRef:
name: testsecret
key: passwd
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
查看值
[root@manage-01 secret]# kubectl exec -it -n devtest nginx-test bash
root@nginx-test:/# echo $sec_user
admin
root@nginx-test:/# echo $sec_passwd
yfk123456
# ImagePullSecrets
imagePullSecrets 是对同一命名空间中 Secret 的引用列表,用于拉取引用此 ServiceAccount 的 Pod 中的任何镜像。
imagePullSecrets 与 Secrets 不同,因为 Secrets 可以挂载在 Pod 中,但 imagePullSecrets 只能由 kubelet 访问。
- 登录docker私有仓库,查看dockercfg
docker login harbor.yfklife.cn
cat ~/.dockercfg |base64
2
apiVersion: v1
data:
.dockerconfigjson: eyJhdXRocyI6eyJoYXJib3IueWZrbGlmZS5jbiI6eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJ5ZmsxMjM0NTYiLCJhdXRoIjoiWVdSdGFXNDZlV1pyTVRJek5EVTIifX19
kind: Secret
metadata:
name: harbor
namespace: devtest
type: kubernetes.io/dockerconfigjson
2
3
4
5
6
7
8
也可以使用命令:kubectl create secret docker-registry harbor --docker-server=harbor.yfklife.cn --docker-username=admin --docker-password=yfk123456 -n devops
- 使用imagePullSecrets
apiVersion: v1
kind: Pod
metadata:
labels:
app: nginx-test
name: nginx-test
namespace: devtest
spec:
containers:
- image: nginx:1.20.2
name: nginx
imagePullSecrets:
- name: harbor #私有仓库密钥
2
3
4
5
6
7
8
9
10
11
12
13
# Service Account
Service Account也是一种账号,但它并不是给Kubernetes集群的用户(系统管理员、运维人员、租户用户等)用的,而是给运行在Pod里的进程用的,它为Pod里的进程提供了必要的身份证明
如果一个Pod在定义时没有指定spec.serviceAccountName属性,则系统会自动为其赋值为default,即大家都使用同一个Namespace下的默认Service Account。
用户可以理解的名称,也可能是外围系统理解的身份标识,可以验证和授权的主体,一组 secret
- 创建sa
apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa
namespace: default
2
3
4
5
# API Server授权管理
当客户端发起API Server调用时,API Server内部要先进行用户认证,然后执行用户授权流程,即通过授权策略来决定一个API调用是否合法。对合法用户进行授权并且随后在用户访问时进行鉴权,是权限与安全系统的重要一环。简单地说,授权就是授予不同的用户不同的访问权限。
授权策略:
AlwaysDeny:表示拒绝所有请求,一般用于测试。
AlwaysAllow:允许接收所有请求,如果集群不需要授权流程,则可以采用该策略,这也是Kubernetes的默认配置。
ABAC(Attribute-Based Access Control):基于属性的访问控制,表示使用用户配置的授权规则对用户请求进行匹配和控制。
Webhook:通过调用外部REST服务对用户进行授权。
RBAC:Role-Based Access Control,基于角色的访问控制。
Node:是一种专用模式,用于对kubelet发出的请求进行访问控制。
# RBAC授权模式详解
基于角色(Role)的访问控制(RBAC)是一种基于组织中用户的角色来调节控制对计算机或网络资源的访问的方法。
RBAC 鉴权机制使用 rbac.authorization.k8s.io API 组来驱动鉴权决定, 允许你通过 Kubernetes API 动态配置策略。
要启用 RBAC,在启动 API 服务器时将 --authorization-mode 参数设置为一个逗号分隔的列表并确保其中包含 RBAC。
RBAC API 声明了四种 Kubernetes 对象:Role、ClusterRole、RoleBinding 和 ClusterRoleBinding。
# Role
一个角色就是一组权限的集合,这里的权限都是许可形式的,不存在拒绝的规则
Role 总是用来在某个名字空间内设置访问权限; 在你创建 Role 时,你必须指定该 Role 所属的命名空间。
- 示例
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: ["","apps"] # "" 标明 core API 组,"apps" 可以使用别的资源如果resorces 添加了,比如deployment,rc等等
resources: ["pods"]
verbs: ["get", "watch", "list"]
2
3
4
5
6
7
8
9
# ClusterRole
ClusterRole 则是一个集群作用域的资源。这两种资源的名字不同(Role 和 ClusterRole) 是因为 Kubernetes 对象要么是名字空间作用域的,要么是集群作用域的,不可两者兼具
定义对某名字空间域对象的访问权限,并将在个别名字空间内被授予访问权限;
为名字空间作用域的对象设置访问权限,并被授予跨所有名字空间的访问权限;
为集群作用域的资源定义访问权限。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# "namespace" 被忽略,因为 ClusterRoles 不受名字空间限制
name: secret-reader
rules:
- apiGroups: [""]
# 在 HTTP 层面,用来访问 Secret 资源的名称为 "secrets"
resources: ["secrets"]
verbs: ["get", "watch", "list"]
2
3
4
5
6
7
8
9
10
# RoleBinding
角色绑定(Role Binding)是将角色中定义的权限赋予一个或者一组用户。 它包含若干 主体(用户、组或服务账户)的列表和对这些主体所获得的角色的引用。
RoleBinding 在指定的名字空间中执行授权,而 ClusterRoleBinding 在集群范围执行授权
apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定允许 "jane" 读取 "default" 名字空间中的 Pod
# 你需要在该命名空间中有一个名为 “pod-reader” 的 Role
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
# 你可以指定不止一个“subject(主体)”
- kind: User
name: jane # "name" 是区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
# "roleRef" 指定与某 Role 或 ClusterRole 的绑定关系
kind: Role # 此字段必须是 Role 或 ClusterRole
name: pod-reader # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配
apiGroup: rbac.authorization.k8s.io
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
当roleRef 引用的king 是ClusterRole ,read-pods 用户也只能访问default里面的资源,因为 RoleBinding 所在的名字空间是 "default"(由其 metadata 决定)。
# ClusterRoleBinding
要跨整个集群完成访问权限的授予,你可以使用一个 ClusterRoleBinding。
创建后不可改变,如果你想要改变现有绑定对象中 roleRef 字段的内容,必须删除重新创建绑定对象。
apiVersion: rbac.authorization.k8s.io/v1
# 此集群角色绑定允许 “manager” 组中的任何人访问任何名字空间中的 Secret 资源
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: Group
name: manager # 'name' 是区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
2
3
4
5
6
7
8
9
10
11
12
13
# 资源引用
通过rules来定义规则
rules:
- apiGroups: [""] resources: ["pods", "pods/log"] verbs: ["get", "list"]
- apiGroups: ["","storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"]
- apiGroups: ["apps"] resources: ["pods","deployments","replicasets","replicationcontrollers","configmaps","services"] verbs: ["get","list","watch","create","update","delete"]
第一个apiGroup,只允许访问核心里面的pod,第二个apiGroups,只允许查看存储资源里面的storageclasses,第三个apiGroups,只允许访问apps组里面的resources对应的资源
# 生成权限控制的kubeconfig
在某些情况,公司的k8s集群要给开发自己去测试,但又不想影响到别的项目(namespace),通过权限控制生成一个config指定在某个空间有权限
比如:Namespace:devtest ,Username:dev
Namespace=devtest
Username=dev
#创建namespace
kubectl create ns $Namespace
test -d ${Namespace}_config || mkdir ${Namespace}_config && cd ${Namespace}_config
2
3
4
5
6
7
- 创建ServiceAccoount
cat >${Username}-sa.yaml<<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: ${Username}-sa
namespace: ${Namespace}
EOF
kubectl apply -f ${Username}-sa.yaml
2
3
4
5
6
7
8
- 创建一个 Role
在用户命名空间下创建 Role,分配给使用者的资源和权限
cat >${Username}-role.yaml<<EOF
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: ${Username}-role
namespace: ${Namespace}
rules:
- apiGroups: ["","apps"]
resources:
- pods
- deployments
- services
- replicasets
- replicationcontrollers
- configmaps
verbs:
- get
- list
- watch
- create
- update
- delete
EOF
kubectl apply -f ${Username}-role.yaml
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- 创建 RoleBinding
将刚刚创建的 SA 和 Role 进行绑定, 上面创建的ServiceAccount 就可以访问 devtest 命名空间下的相应资源了
cat >${Username}-roleBinding.yaml<<EOF
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: ${Username}-binding
namespace: ${Namespace}
subjects:
- kind: ServiceAccount
name: ${Username}-sa
roleRef:
kind: Role
name: ${Username}-role
apiGroup: rbac.authorization.k8s.io
EOF
kubectl apply -f ${Username}-roleBinding.yaml
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- 生成kubeconfig
KUBE_APISERVER=`kubectl config view --minify -o=jsonpath="{.clusters[*].cluster.server}"`
TOKEN_KEY=`kubectl get sa ${Username}-sa -n ${Namespace} -o=jsonpath="{.secrets[0].name}"`
TOKEN=`kubectl get secrets $TOKEN_KEY -n ${Namespace} -o=jsonpath="{.data.token}"`
CLUSTER_AUTH=`kubectl config view --flatten --minify -o=jsonpath="{.clusters[0].cluster.certificate-authority-data}"`
TOKEN_DECODE=`echo $TOKEN | base64 --decode`
# 生成 kubeconfig 文件
cat > $Username.config <<EOF
apiVersion: v1
kind: Config
users:
- name: $Username
user:
token: $TOKEN_DECODE
clusters:
- cluster:
certificate-authority-data: $CLUSTER_AUTH
server: $KUBE_APISERVER
name: $Username-cluster
contexts:
- context:
cluster: $Username-cluster
namespace: $Namespace
user: $Username
name: $Username-cluster
current-context: $Username-cluster
EOF
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- 检查
把 XXX.config 拷贝到 ~/.kube/config里,或者使用参数指定:--kubeconfig=XXX.config
kubectl create deployment nginx-test --image=nginx:1.20.2 -n devtest --kubeconfig=${Username}.config
#有权限的显示,没权限的提示禁止
kubectl get all --kubeconfig=${Username}.config
2
3
4