目录
[一、Kubernetes API访问控制](#一、Kubernetes API访问控制)
[1.传输安全(Transport Security)](#1.传输安全(Transport Security))
[2.1 认证方式](#2.1 认证方式)
[2.2 ServiceAccount和普通用户的区别](#2.2 ServiceAccount和普通用户的区别)
[2.3 ServiceAccount管理方式](#2.3 ServiceAccount管理方式)
[3.2 RBAC](#3.2 RBAC)
[审计策略(Audit Policy)](#审计策略(Audit Policy))
[审计日志的存储(Audit Sink)](#审计日志的存储(Audit Sink))
Kubernetes(K8s)是一个强大的容器编排平台,安全性至关重要。Kubernetes的安全机制可以分为多个层次,包括集群层、网络层、应用层等。以下是Kubernetes中主要的安全机制:Kubernetes API访问控制、Secret、网络策略(NetworkPolicy) 、审计日志等等。
一、Kubernetes API访问控制
Kubernetes API访问控制是一组机制,确保只有经过授权的用户或服务可以访问和操作集群资源。它涵盖了多个层面,包括传输安全、认证、鉴权、准入控制和审计。以下是这些概念的详细介绍。
1.传输安全(Transport Security)
Kubernetes默认使用HTTPS来确保API通信的安全性,防止数据在传输过程中被窃取或篡改。API服务器会使用TLS(传输层安全协议)对请求进行加密:
客户端与服务器间通信加密:通过使用TLS证书来验证服务器和客户端的身份,从而加密通信。
Kubernetes API server的证书管理:需要为Kubernetes集群中的API服务器配置正确的证书(包括根证书和客户端证书)。
保护内部组件的通信:比如etcd的通信需要加密,并使用适当的证书。
2.认证(Authentication)
2.1 认证方式
所有Kubernetes集群都有两类用户:由Kubernetes管理的服务账户(ServiceAccount)、普通用户。所有API请求都需要经过身份认证,以确保请求来自合法用户或服务,并授予适当的权限。Kubernetes支持多种认证方式,其中比较常见的是基于令牌的身份验证、x509证书、OpenID Connect(OIDC)、服务账户(ServiceAccount)等。
x509证书:用户通过x509证书与API服务器进行通信。这种方式通常用于Kubernetes管理员、集群节点和集群内的一些服务。例如:客户端使用带有用户身份的证书,通过kubectl命令访问API服务器。
Bearer Token:Kubernetes使用令牌(Token)进行身份验证,客户端可以通过将Bearer Token附加到HTTP请求中进行身份验证。
OIDC(OpenID Connect):通过外部身份提供者(如Google、AWS、Keycloak等)验证用户身份。OIDC是一种基于OAuth2.0协议的身份验证协议,适合于与外部认证服务集成。
服务账户(ServiceAccount):服务账户用于集群内的应用程序或Pod来访问API服务器,通常与RBAC(基于角色的访问控制)结合使用。
可以指定多个认证模块,在这种情况下,服务器依次尝试每个验证模块,直到其中一个成功。
2.2 ServiceAccount和普通用户的区别
普通用户通常是指通过kubeconfig文件、证书或OIDC等方式认证的用户,通常是Kubernetes集群的管理员或开发者;Kubernetes不会直接在集群中创建或管理普通用户。
普通用户使用场景:普通用户用于手动管理集群资源(例如 kubectl 命令行工具)或访问Kubernetes API。
ServiceAccount是Kubernetes中的一种特殊类型的账户,用于赋予Pod在集群中运行时的身份。它主要用于集群内的自动化服务,而不是手动用户操作。
ServiceAccount使用场景:ServiceAccount常用于需要与API服务器交互的应用程序,或用于Pod自动管理集群资源。例如CI/CD工具、监控工具、控制器等。
2.3 ServiceAccount管理方式
每个ServiceAccount都与一个JSON Web Token (JWT) 关联,该令牌存储在Pod的文件系统中,位于**/var/run/secrets/kubernetes.io/serviceaccount/token** 路径下。Pod启动后,会使用这个令牌与Kubernetes API服务器进行通信,API服务器根据该令牌进行身份验证。ServiceAccount通常与RBAC结合,授予Pod访问某些API资源的权限。
ServiceAccount可以通过自动或手动方式使用。默认情况下,每个命名空间Namespace都有一个默认的ServiceAccount,Pod启动时会自动关联这个ServiceAccount。如果需要更高的权限或特殊用途,我们也可以手动创建并指定ServiceAccount。
自动ServiceAccount示例
创建及查看Pod:
#创建Pod
kubectl run my-pod --image=nginx
#查看Pod的ServiceAccount
kubectl get pod my-pod -o yaml
在输出中,会看到以下部分,表示该Pod使用了default
ServiceAccount:
serviceAccount: default
serviceAccountName: default
查看ServiceAccount令牌:
kubectl exec -it my-pod -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
手动ServiceAccount示例
创建ServiceAccount:
#手动创建一个新的ServiceAccount
kubectl create serviceaccount my-service-account
#查看ServiceAccount的详细信息kubectl get serviceaccount my-service-account -o yaml
创建Pod并绑定自定义的ServiceAccount:
apiVersion: v1
kind: Pod
metadata:
name: my-pod-with-sa
spec:
serviceAccountName: my-service-account # 指定使用的ServiceAccount
containers:
- name: my-container
image: nginx
验证Pod是否绑定了自定义ServiceAccount:
#创建Pod
kubectl apply -f pod-with-sa.yaml
#查看该 Pod 的详细信息kubectl get pod my-pod-with-sa -o yaml
输出中会显示:
serviceAccount: my-service-account
serviceAccountName: my-service-account
为ServiceAccount配置权限(可选):
#授予
my-service-account
读取Pod信息的权限。kubectl create role my-role --verb=get,list,watch --resource=pods
kubectl create rolebinding my-role-binding --role=my-role --serviceaccount=default:my-service-account
ServiceAccount 默认没有太多权限,可以使用Role
和RoleBinding
为它配置权限。
关于权限在**鉴权 (Authorization)**部分说明。
3.鉴权 (Authorization)
3.1鉴权方式
在认证之后,Kubernetes会决定认证通过的用户是否有权限执行特定操作。Kubernetes使用多种授权方式来控制API请求的访问权限。
RBAC (基于角色的访问控制):基于预定义的角色来授予用户或组的权限,通过Role和ClusterRole结合RoleBinding和ClusterRoleBinding来实施访问控制。
ABAC (基于属性的访问控制):通过指定策略文件,根据请求的属性(如用户名、资源类型、动作)决定是否授权。
Webhook模式:将鉴权请求转发到外部服务处理,适合实现自定义的访问控制逻辑。
3.2 RBAC
RBAC(Role-Based Access Control,基于角色的访问控制)是Kubernetes中的一种访问控制机制,用于定义用户或服务账号对 Kubernetes 资源的访问权限。通过 RBAC,集群管理员可以根据角色分配权限,并通过绑定这些角色给用户、组或ServiceAccount来控制访问权限。
RBAC 主要由四个核心组件构成:
- Role :定义某个特定
Namespace
下的权限。它包含了对资源(例如Pods、Services等)的操作规则(如get
、create
、delete
等)。 - ClusterRole :定义集群范围的权限,可以在所有
Namespace
中使用,或直接应用于集群级资源(如节点、PersistentVolumes等)。 - RoleBinding :将
Role
绑定到用户、组或ServiceAccount,使其在指定的Namespace
中拥有相应的权限。 - ClusterRoleBinding :将
ClusterRole
绑定到用户、组或ServiceAccount,使其在整个集群中拥有相应的权限。
Role & RoleBinding示例:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default #作用范围是default命名空间
name: pod-reader
rules:
- apiGroups: [""] #空字符串表示核心API组
resources: ["pods"]
verbs: ["get", "list", "watch"] #授予的操作权限
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects: #绑定的用户或服务账户
- kind: User #可以是User、Group或ServiceAccount
name: "example-user" #用户名
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role #绑定的角色类型
name: pod-reader #绑定的角色名称
apiGroup: rbac.authorization.k8s.io
example-user
现在拥有default
命名空间中读取pods
资源的权限。
ClusterRole & ClusterRoleBinding示例:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-pod-reader
rules:
- apiGroups: [""] # 核心API组
resources: ["pods"]
verbs: ["get", "list", "watch"]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-pods-clusterwide
subjects: #绑定的用户或服务账户
- kind: User
name: "example-user" #用户名
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole #绑定ClusterRole
name: cluster-pod-reader #绑定的角色名称
apiGroup: rbac.authorization.k8s.io
ci-service-account
现在可以读取集群中所有命名空间的Pod信息。
4.准入控制 (Admission Control)
准入控制是对经过认证和授权的API请求进行进一步的检查和修改的一个步骤。在请求进入Kubernetes API Server之前,准入控制器可以阻止请求或修改对象。推荐使用的准入控制器默认情况下都处于启用状态。可以使用--enable-admission-plugins来启用默认设置以外的其他准入控制器。
常见的内置准入控制器:例如NamespaceLifecycle、LimitRanger、PodSecurity、RuntimeClass等,用于特定的访问和资源管理。以下介绍PodSecurity概念:
PodSecurity
Pod 安全性标准(Pod Security Standards,PSS) 是Kubernetes提供的一套安全标准,用于定义和管理Pod 的安全策略。通过使用Pod安全性标准,Kubernetes集群管理员可以控制和限制 Pod在运行时的行为,从而提高集群的整体安全性。这套标准是通过Kubernetes的内置准入控制器PodSecurity来实现的。
默认情况下,Kubernetes不启用PodSecurity,因此没有默认的安全级别和模式。如果启用PodSecurity准入控制器,默认的安全级别和模式需要手动配置。
安全级别
Pod 安全性标准主要定义了三个安全级别(或模式):
-
特权级别(Privileged)
- 用途:最宽松的安全级别,允许Pod以完全特权运行。适用于那些需要完全控制底层主机的Pod,例如需要执行主机级别操作的系统组件或Pod。
- 特点:
- 允许使用特权模式、HostPath挂载、特权容器、HostNetwork等功能。
- 几乎没有安全约束,风险较高。
-
基线级别(Baseline)
- 用途:旨在允许大多数应用程序正常运行,同时施加基本的安全限制。适合一般的应用程序。
- 特点:
- 拒绝特权模式和特权容器。
- 限制HostPath挂载,防止容器访问主机的敏感文件。
- 限制某些Linux特性,如
CAP_SYS_ADMIN
等高危特权。 - 禁止使用
HostNetwork
和HostPID
。
-
受限级别(Restricted)
- 用途:最严格的安全级别,施加了所有可用的最佳安全实践。适用于高度敏感的应用程序,需要严格限制Pod的行为。
- 特点:
- 禁止一切特权操作,包括HostPath挂载、特权容器、HostNetwork、HostPID、HostIPC等。
- 强制限制容器的用户权限(如不能以root用户身份运行容器)。
- 强制限制进程和文件系统的权限,最大限度减少攻击面。
安全实施
Pod 安全性标准的实施分为以下几种操作模式:
- Enforce(执行):强制执行指定的安全策略,如果Pod不符合要求,则禁止其创建或更新。
- Audit(审计):记录违反安全策略的操作,但不阻止Pod创建或更新。
- Warn(警告):向用户发出警告,通知其违反了安全策略,但不阻止Pod创建或更新。
这些模式允许管理员以递进方式加强安全控制,逐步引导开发人员适应更严格的安全标准。
配置示例
apiVersion: v1
kind: Namespace
metadata:
name: restricted-namespace
labels:
pod-security.kubernetes.io/enforce: "restricted" #强制执行受限级别
pod-security.kubernetes.io/audit: "baseline" #审计基线级别
pod-security.kubernetes.io/warn: "baseline" #警告基线级别
在这个示例中,restricted-namespace
命名空间中,强制执行受限级别的Pod安全策略,并在审计和警告模式下评估基线级别的策略。
apiVersion: v1
kind: Namespace
metadata:
name: baseline-namespace
labels:
pod-security.kubernetes.io/enforce: "baseline" #强制执行基线级别
在这个示例中,baseline-namespace
命名空间中,所有创建的Pod必须符合基线级别的安全标准,否则创建或更新请求将被拒绝。
二、审计 (Auditing)
Kubernetes 审计日志会记录API服务器处理的每一个HTTP请求,它包括从请求的接收到最终的处理结果(允许或拒绝),以及返回的响应。审计的事件按照发生的顺序记录下来,管理员可以根据这些日志了解集群的操作情况。
Kubernetes 默认没有开启审计 ,需要在kube-apiserver
的配置文件中启用审计功能,并手动配置审计策略文件。API 服务器不默认生成审计日志,也没有预设的审计级别。
审计架构
审计系统由三个主要组件组成:
- Audit Policy:定义审计事件的记录规则,如记录哪些操作、哪些用户的行为等。
- Audit Sink:审计日志的存储位置,可以是文件、标准输出,或通过HTTP Webhook发送到外部服务。
- Audit Event:每个 API 请求会被记录为一个审计事件,包含详细的上下文信息。
审计策略(Audit Policy)
审计策略通过一个策略文件来定义,策略文件控制什么样的API请求会被记录,以及记录的详细程度。
审计级别
每个请求可以按不同的审计级别记录:
- None:不记录任何内容。
- Metadata:仅记录请求的元数据(如用户、操作、时间等),不记录请求和响应的内容。
- Request:记录请求的元数据以及请求体,但不记录响应体。
- RequestResponse:记录请求的元数据、请求体和响应体,包含了所有详细信息。
审计策略文件示例
一个典型的审计策略文件会定义不同资源、不同用户和操作的记录级别。下面是一个示例策略文件:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse # 对于所有的pod操作,记录请求和响应
resources:
- group: ""
resources: ["pods"]
- level: Metadata #对于所有的secrets操作,记录元数据
resources:
- group: ""
resources: ["secrets"]
- level: None #忽略对serviceaccounts的请求
resources:
- group: ""
resources: ["serviceaccounts"]
- level: Request #记录所有的请求操作和元数据
users: ["system:serviceaccount:kube-system:default"]
verbs: ["create", "update", "patch"]
- level: Metadata #默认记录所有其他请求的元数据
omitStages:
- "RequestReceived"
这个策略文件的规则说明如下:
- 对于所有的Pod操作,记录详细的请求和响应。
- 对于 Secret 操作,仅记录元数据(例如操作的时间、用户)。
- 忽略ServiceAccount的所有操作。
- 对特定的服务账户的
create
、update
、patch
请求,记录请求的详细信息。 - 对所有其他请求,默认记录元数据。
审计日志的存储(Audit Sink)
Kubernetes 支持多种审计日志的输出方式,通常包括:
- 文件输出:将审计日志写入文件。
- Webhook 输出:通过HTTP POST请求将审计日志发送到外部服务。
文件输出是一种常见的方式,API服务器可以将审计日志写入到指定文件。 启动kube-apiserver
时,可以通过以下参数配置文件输出:、
kube-apiserver \
--audit-policy-file=/etc/kubernetes/audit-policy.yaml \
--audit-log-path=/var/log/kubernetes/audit.log \
--audit-log-maxage=30 \
--audit-log-maxbackup=10 \
--audit-log-maxsize=100
--audit-policy-file
:指定审计策略文件路径。--audit-log-path
:审计日志文件的存储路径。--audit-log-maxage
:日志文件保存的最大天数。--audit-log-maxbackup
:保留的旧审计日志文件的最大数量。--audit-log-maxsize
:每个日志文件的最大大小(以 MB 为单位)。
审计事件结构
审计日志中的每个事件都包含丰富的上下文信息,在下面的输出示例中,requestObject
和 responseObject
分别记录了请求和响应的详细内容:
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "RequestResponse",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/default/pods",
"verb": "create",
"user": {
"username": "admin",
"groups": ["system:masters"]
},
"sourceIPs": ["192.168.1.100"],
"objectRef": {
"resource": "pods",
"namespace": "default",
"name": "my-pod"
},
"responseStatus": {
"metadata": {},
"code": 201
},
"requestObject": {
"kind": "Pod",
"metadata": {
"name": "my-pod"
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
},
"responseObject": {
"kind": "Pod",
"metadata": {
"name": "my-pod"
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
}
三、Secret
Secret API为需要保密的配置值提供基本保护。可以回顾 Kubernetes从零到精通(13-Configmap、Secret)
四、网络策略(NetworkPolicy)
Kubernetes 中的网络策略(NetworkPolicy) 是一种控制Pod间流量和Pod与外部网络流量的安全机制。它允许用户定义哪些流量可以进入和离开Pod,以确保集群的安全性。
网络策略仅会在支持网络策略的网络插件CNI(如 Calico)中生效 。Kubernetes 默认的网络实现不支持网络策略。网络插件可以回顾Kubernetes从零到精通(11-CNI网络插件)。
网络策略的作用
NetworkPolicy是通过定义一组规则来允许或拒绝指定Pod的网络流量。这些规则可以基于:
- 命名空间:限制特定命名空间中的 Pod 间的流量。
- Pod 标签:限制带有特定标签的 Pod 间的流量。
- IP Block:限制特定的 IP 地址段的流量。
网络策略的工作原理
Kubernetes 网络策略主要用来定义:
- 入口流量(Ingress):进入Pod的流量。
- 出口流量(Egress):从Pod发送出的流量。
没有配置网络策略时,所有Pod之间的网络流量默认是允许的,一旦定义了网络策略,只有符合规则的流量才会被允许。
网络策略的基本结构
一个网络策略通过以下几部分定义:
- Pod选择器:选择哪些 Pod 应该应用这条策略。
- 策略类型 :
Ingress(不是Ingress、Gateway api,只是名称相同)
或Egress
,指定策略是控制入口流量还是出口流量。 - 规则:指定允许哪些流量通过,规则可以基于Pod标签、IP 地址块、命名空间等定义。
网络策略示例
下面的网络策略将阻止所有流向my-pod
的流量,除了带有特定标签的Pod发送的流量:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-specific-pods
namespace: default
spec:
podSelector:
matchLabels:
app: my-pod #应用此策略的Pod
policyTypes:
- Ingress #定义入口流量规则
ingress:
- from:
- podSelector:
matchLabels:
app: allowed-app #允许带有此标签的Pod发送流量
该策略允许来自特定IP地址段(如192.168.0.0/16)的流量,其他流量会被拒绝:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-ip-range
namespace: default
spec:
podSelector:
matchLabels:
app: my-pod #应用此策略的Pod
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 192.168.0.0/16 #允许的IP地址范围
下面的网络策略允许Pod访问外部网络(注意这里只是在策略上允许访问外部网络,底层网络能不能支持该 Pod访问外部网络,需要看具体网络情况),但限制对特定命名空间内其他 Pod 的访问:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
namespace: default
spec:
podSelector:
matchLabels:
app: my-app
policyTypes:
- Egress #定义出口流量规则
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0 #允许Pod访问外部网络
该策略将完全隔离某个Pod的网络流量,既不允许它接收流量,也不允许它发送流量:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
namespace: default
spec:
podSelector:
matchLabels:
app: isolated-pod #目标Pod
policyTypes:
- Ingress #不允许任何流量进入
- Egress #不允许任何流量离开