侧边栏壁纸
博主头像
路小飞博主等级

行动起来,活在当下

  • 累计撰写 72 篇文章
  • 累计创建 12 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

11- Kubernetes 集群安全

路小飞
2024-10-25 / 0 评论 / 0 点赞 / 17 阅读 / 36130 字

11.1 权限管理 RBAC

Kubernetes 创建集群时,会生成一个 kubeconfig 文件,位于 ~/.kube/config,其中包含管理员账号凭证、集群访问信息和上下文配置,方便用户通过 kubectl 命令行工具管理集群。该账号通常拥有完全访问权限,允许执行所有操作。然而,除了管理员,项目负责人和应用开发者等用户也可能需要访问集群,因此进行权限管理显得尤为重要。

11.1.1 RBAC 的基本概念

RBAC(基于角色的访问控制)是一种管理 Kubernetes 集群中用户权限的机制。它通过四种顶级资源对象实现:Role、ClusterRole、RoleBinding 和 ClusterRoleBinding。管理员可以使用 kubectl API 调用这些资源对象,灵活地配置和管理用户的访问权限,从而提高集群的安全性和管理效率。

其在 Kubernetes 1.5 版本中引入,在 1.6 版本中升级为 Beta 版本,并成为 Kubeadm 安装方式下的默认选项,可以通过修改 Master 节点上 apiserver 的静态 Pod 定义文件来设置启动时指定 -authorization-mode=RBAC

cat /etc/kubernetes/manifests/kube-apiserver.yaml 
...
    - --authorization-mode=Node,RBAC
...

11.1.2 Role 和 Cluster Role

Role 和 ClusterRole 的关键区别在于它们的作用范围:

  1. Role:用于定义特定命名空间内的权限。它只在指定的命名空间有效,允许对该命名空间中的资源进行操作。
  2. ClusterRole:作用于整个集群,可以在所有命名空间内使用。它允许对集群范围内的资源进行操作,或在特定命名空间中被引用。

关于权限,RBAC(基于角色的访问控制)中的规则主要是“允许”的,意味着如果没有明确的允许,访问将被拒绝,没有默认的拒绝规则。这种设计使得权限管理更加清晰和可控。

Role

以下是一个 Role 的案例

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: dev
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list"]

  • apiVersion: 定义该资源的 API 版本。

  • kind: 定义资源类型为 Role。

  • metadata:

    • name: Role 的名称。
    • namespace: Role 是作用在单个 Namespace 下的,具有命名空间隔离,所以需要指定 Namespace,不指定则为 default。
  • rules: 定义具体的权限,切片类型,可以配置多个。

    • apiGroups: 定义该资源的 apiGroup 名称,比如 [""] 表示核心 API 组。

    • resources: 定义对哪些资源进行授权,切片类型,可以定义多个,比如 pods、service 等。

    • verbs: 定义可以执行的操作,切片类型,可以定义多个,比如 create、delete、list、get、watch、deletecollection等。

切片类型表示一个数组,可以在其中定义多条规则,每条规则描述不同的权限设置。每条规则可以指定不同的 apiGroupsresourcesverbs,从而允许更细粒度的权限控制。例如,你可以同时允许某个用户查看 Pods 和服务,或者针对不同资源设置不同的操作权限。通过这种方式,可以灵活地管理用户和服务账户的访问权限。

ClusterRole

ClusterRole可以将权限授予整个集群,主要区别在于它适用于集群范围内的资源,因此可以访问以下内容:

  • 集群范围的资源(如 Node)。
  • 非资源端点(如 /healthz)。
  • 跨所有命名空间的资源(如 Pod)。

例如,可以授予对所有命名空间中的 Secret 的读取权限:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

可以看到,当前的 Role 和 ClusterRole 配置相似,主要区别在于将 kind 从 Role 更改为 ClusterRole。

对子资源的引用问题

在很多情况下,我们需要授权用户查看容器日志或执行容器的权限。这时,仅仅将 resources 设置为 Pods 是不够的,还需要对指定资源的子资源进行控制。在 Kubernetes 中,大多数资源通过其名称字符串表示,例如 pods。然而,一些 Kubernetes API 涉及的子资源,如 Pod 的日志,其对应的 Endpoint URL 是:

GET /api/v1/namespaces/{namespace}/pods/{name}/log

在这个示例中,pods 是命名空间级别的资源,而 log 是 Pod 的子资源。要对其进行访问控制,需要用斜杠分隔资源和子资源。

例如,可以定义一个 Role 来允许读取 Pod 及其日志:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-log-reader
  namespace: default  # 指定命名空间
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]  # 允许访问 Pod 和 Pod 的日志
  verbs: ["get", "list", "watch"]    # 允许的操作

对于特定资源,您还可以使用 resourceName 来指定单个具体资源。这允许您更精确地控制访问权限、提供了更大的灵活性和安全性。例如,您可以定义一个 Role,只授予用户对特定 Pod 的日志具有访问权限,而不是对所有 Pods 的权限。

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: specific-pod-log-reader
  namespace: default
rules:
- apiGroups: [""]
  resources: ["pods/log"]  # 只针对子资源 pods/log
  resourceNames: ["my-app"] # 指定特定的 Pod 名称
  verbs: ["get", "list", "watch"]

注意事项:如果使用了 resourceNames,则 verbs 不能是 list、watch、create、deletecollection等。

11.1.3 RoleBinding 和 ClusterRoleBinding

RoleBinding(角色绑定)可以将 Role 中定义的权限授予 User、Group或 ServiceAccount。RoleBinding 和 ClusterRoleBinding 最大的区别在于 RoleBinding 作用于命名空间,ClusterRoleBinding 作用于集群。

相关字段

RoleBinding 可以引用同一命名空间的 Role 进行授权,比如将上述创建的 pod-reader 的 Role 授予 default 命名空间的用户 zs,这将允许 zs 读取 default 命名空间中的 Pod:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: zs  # 用户名
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader  # 绑定的角色名
  apiGroup: rbac.authorization.k8s.io

  • subjects: 配置被绑定对象,如用户、用户组或服务账户,可以配置多个。
    • kind: 这里指定为 User,表示这个 RoleBinding 是绑定给一个用户。
    • name: test 是要绑定的用户的名称。
    • apiGroup: 指定了该用户的 API 组,这里是 rbac.authorization.k8s.io
  • roleRef: 引用要绑定的角色。
    • kind: 指定权限来源,可以是 Role 或 ClusterRole。
    • name: pod-reader 是要绑定的角色的名称。
    • apiGroup: 同样指定了该角色的 API 组。
1. RoleBinding 绑定 Role
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: test
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

说明:

  • RoleBinding 允许在特定命名空间内将 Role 绑定到用户或服务账户。
  • 在这个例子中,read-pods 绑定了 pod-reader 角色,允许用户 testdefault 命名空间内执行与 Pods 相关的操作(例如:获取、列出和观察 Pods)。
2. RoleBinding 绑定 ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-all-pods
  namespace: default
subjects:
- kind: User
  name: test
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

说明:

  • 在这个例子中,RoleBinding 绑定了一个 ClusterRole
  • 这种方式使得在特定命名空间(如 default)内,用户 test 可以拥有 ClusterRole 定义的权限,而不仅仅是一个命名空间内的角色权限。
  • 例如,如果 pod-reader 是一个 ClusterRole,它可能允许用户在所有命名空间中查看 Pods,但通过 RoleBinding 只在 default 命名空间内生效。
3. ClusterRoleBinding 绑定 Role
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-pods-global
subjects:
- kind: User
  name: test
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  namespace: default
  apiGroup: rbac.authorization.k8s.io

说明:

  • ClusterRoleBinding 允许将 Role 绑定到用户或服务账户,但需要注意的是,Role 仍然是命名空间级的。
  • 在这个例子中,read-pods-global 将用户 testdefault 命名空间的 pod-reader 角色关联起来。
  • 这种方式在逻辑上是合理的,但不常见,因为 ClusterRoleBinding 的主要目的是绑定 ClusterRole
4. ClusterRoleBinding 绑定 ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-all-pods-global
subjects:
- kind: User
  name: test
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

说明:

  • 这是一个典型的 ClusterRoleBinding 用法,允许将 ClusterRole 绑定到用户。
  • 在这个例子中,read-all-pods-global 允许用户 test 在集群的所有命名空间中执行与 Pods 相关的操作。
  • 这种绑定适用于需要跨命名空间访问的权限场景。

区别总结

  1. RoleBinding 绑定 Role:

    • 仅在指定命名空间内生效,适用于控制特定命名空间内的权限。
  2. RoleBinding 绑定 ClusterRole:

    • 允许在特定命名空间内赋予跨命名空间的权限(但仍在该命名空间内有效)。
  3. ClusterRoleBinding 绑定 Role:

    • 虽然可以绑定命名空间角色,但不常见,主要用于将集群级别权限与命名空间角色组合(可能有特定需求)。
  4. ClusterRoleBinding 绑定 ClusterRole:

    • 常用方式,允许用户在集群所有命名空间中拥有集群级权限。

11.1.4 config 文件

1. 使用不同的 config 文件

Kubernetes 的默认 kubeconfig 文件通常位于用户主目录下的 .kube/config。您也可以通过 --kubeconfig=/path/to/your/config 参数指定其他配置文件。

可以使用以下命令查看当前使用的配置文件(用户)在指定命名空间中的权限

[root@master-01 .kube]# kubectl auth can-i --list --namespace=default --kubeconfig=/root/.kube/config 
Resources                                       Non-Resource URLs   Resource Names   Verbs
*.*                                             []                  []               [*]
                                                [*]                 []               [*]
selfsubjectaccessreviews.authorization.k8s.io   []                  []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                  []               [create]
                                                [/api/*]            []               [get]
                                                [/api]              []               [get]
                                                [/apis/*]           []               [get]
                                                [/apis]             []               [get]
                                                [/healthz]          []               [get]
                                                [/healthz]          []               [get]
                                                [/livez]            []               [get]
                                                [/livez]            []               [get]
                                                [/openapi/*]        []               [get]
                                                [/openapi]          []               [get]
                                                [/readyz]           []               [get]
                                                [/readyz]           []               [get]
                                                [/version/]         []               [get]
                                                [/version/]         []               [get]
                                                [/version]          []               [get]
                                                [/version]          []               [get]
  1. 资源权限 (*.*):
    • *.* 表示对所有资源的所有操作都有权限。这是一个非常广泛的权限设置,通常意味着该用户拥有对 Kubernetes 中所有资源的完全访问权限。
  2. 非资源 URL:这部分列出了用户可以访问的非资源 API 端点。
    • 权限:
      • selfsubjectaccessreviews.authorization.k8s.io:可以创建自我主体访问审查请求,通常用于检查用户是否有权限执行某个动作。
      • selfsubjectrulesreviews.authorization.k8s.io:可以创建自我主体规则审查请求,通常用于查看用户在当前上下文中的权限。
    • /api/*, /api, /apis/*, /apis 等:允许执行 GET 操作,表示可以获取 Kubernetes API 的相关信息。
    • /healthz, /livez, /readyz:用于检查集群健康状态的端点,允许执行 GET 操作。
    • /openapi/*, /openapi:可以获取 OpenAPI 规范,允许执行 GET 操作。
    • /version//version:可以获取版本信息,允许执行 GET 操作。
2. 格式
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: <CA证书的Base64编码>
    server: <API服务器地址>
  name: <集群名称>
contexts:
- context:
    cluster: <集群名称>
    user: <用户名称>
  name: <上下文名称>
current-context: <上下文名称>
kind: Config
preferences: {}
users:
- name: <用户名称>
  user:
    client-certificate-data: <用户证书的Base64编码>
    client-key-data: <用户密钥的Base64编码>

在 Kubernetes 集群的控制节点上,CA 证书通常位于 /etc/kubernetes/pki/ca.crt。你可以用以下命令查看内容并进行 Base64 编码:

cat /etc/kubernetes/pki/ca.crt | base64 | tr -d '\n'
3. 案例
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJME1ETXlOakF4TURZek5sb1hEVE0wTURNeU5EQXhNRFl6Tmxvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBS1FkCjVXTXNjYWpvS0htUEpWb2loQ3RqL1l1SlFTVkhmd1Z5MURXZjJveDR4ai9DTkVLWC9VMUFDczZtQ3JOcElIWnEKMk9KQVFDU3pGMXRCMkF2VDIyQ1h4TitOR3VGUnQ2Rko2WWVNZkNXV3JsV2Qxa1NvRWZRWWZjYlJmR3YrcmlKZAoyeDFTRlNOOUl0dEhvNVJINU43UkF0NWowUTA5Sms0dk96aGdaZGMzK3pCQzhPTWtLVmJVMWxWUXV6anpuaTdFCmY1dVY0Mm02YW44NEhwQkE5T09saU5FWWIraXIvMFFOaThwOEZhUmJVOEk0aHgyMll5Qmdva1lVKzJMQitoOEsKRFNnQll3SWFURyt6aGV5NS85QnVTWjZZV2F2QWZsY1pFSHpqVWZPUmlvaXNzVU9ydXRlTktweDRKMWcyUTVHMgpERHhKbGsyVW5nQkdlMVNmV2MwQ0F3RUFBYU5aTUZjd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZEcHFaZW53b3k5RE9iNUtXbEpRKzVuL0V5Tk5NQlVHQTFVZEVRUU8KTUF5Q0NtdDFZbVZ5Ym1WMFpYTXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSGtRWEtBU082YlRDRnRDZmhWNApES0dONk56ZmRRWVY0TnB0SjdwNXBaU0hNNWtLWHlqL1NLL0JqUXdWVk5aS3hCWmRHdlBtd002ZjV3VnNrYjRJCnpFcmxwZHVuNkxPRG0wYXN5R25MSnowTVlJbldQUGVpSmt4RURtUGxUWVNtTUJ1WDJjMHNOeG81WEFHbWZsMysKb3YvRWNJeitBNmRBWC9pNzU4c1p3UjJ3Wm1zREd0RmoyalQwRzVGMUlkOGJsd2gvL0cwVUhvY3A5dzNnWTdHcgppZ0NNOC91SEhsUURoOFlkSWE4Qm1qRStVbmxKVG50RnRoMmRpZG9GOTBhb3MwUk02YTBZRURBdzlzLzN6bEVpClRHSHBJQWRoWUY3K0FhUUN2VEU4dWc0bGJpU2tQNStZNGNGWjNidU5HUUNLNXRTSGhkQ2tQMnkyamMxblZjRWEKUmc0PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
    server: https://192.168.17.110:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURJVENDQWdtZ0F3SUJBZ0lJZFpOdHhOa21ZLzR3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TkRBek1qWXdNVEEyTXpaYUZ3MHlOVEF6TWpZd01UQTJNemRhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQTFqTVJqd0o0REJBZ01rczUKL25qN1lxZ0VJd29la0NzSTdzZE9GeVovaC9VQVZlRnpKVHV5NFk4dnAyUWwrd21qNU1WWjlLT1J3OHJycmw5NApWb1NTTSt5TG9TWW12bkN3VXlNUGlxOGQweVNUOW9oY2VYTFZoWmN3TmFabXNvREgzK1hMM1h5S0JXS2o2QTFOClRVVzhySDNuR2NOSFpQdU5zRTBYa3NkTmtoa3A1NE03NXJQNXhwRnJqN2RIRjROUXpIOW44eTFOSXhhZ2g1MTIKZXpNdldDZkVZZFhPYzdFK1pKL0NCMHJLSlpTcFMrTGVHc3BITjdEelFpbXFacEI1QThRZk4yTWtBc1Yxb3FLUAo5ZncrQ0lkcmdvWGpnRVJ3eGpRNTFJeDBmQ3IzTHV1aXQ2ME94dlJkS1NCak9mMTByU01SaFhCemlTYzBzZWowCkNuZFZQd0lEQVFBQm8xWXdWREFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RBWURWUjBUQVFIL0JBSXdBREFmQmdOVkhTTUVHREFXZ0JRNmFtWHA4S012UXptK1NscFNVUHVaL3hNagpUVEFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBZUJuWllxMlhRQW9qMXB0bmtZQ3kyYXYvcWd1ODFNbFMvY0o2CkF1RDJVMzl2YUt0WnMwYUJUZllpVDVTUS92QUdJbGV5VXJZaXJiTE5HclUrNzV1ZzBGUHpDY1hhejA4cDJuT0MKdFExdmljcXdDelNwZlNIeStmSy9Wc25mMUpHL05sWDBaQjZPRFJ3aFRFNUVWQXlhM0dlUFpqbmNqS29FYTVNbwpjUXBrR2NHczN2c0NzYTJFeWFoR1JwczQ3aDVGSUFLSERoMVN3Skg5VUVJeFE2RXJnWjIrV1hSRHJzKzV3OW1LCkY3UHJVV3o4dUlDdE1LMlVmTG5IWDFlSjRPSlB0M1NwVDhhMXN6VE9TVmIvbHAvOUVsblAyeE9uRXNvNGxKZWEKNHY1L0QyZ0lsQjVGclQrMlptZ2tZUHFycmZzSmtSUzNsVFBRQk95ZEFsalBuemZ0QXc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
    client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBMWpNUmp3SjREQkFnTWtzNS9uajdZcWdFSXdvZWtDc0k3c2RPRnlaL2gvVUFWZUZ6CkpUdXk0WTh2cDJRbCt3bWo1TVZaOUtPUnc4cnJybDk0Vm9TU00reUxvU1ltdm5Dd1V5TVBpcThkMHlTVDlvaGMKZVhMVmhaY3dOYVptc29ESDMrWEwzWHlLQldLajZBMU5UVVc4ckgzbkdjTkhaUHVOc0UwWGtzZE5raGtwNTRNNwo1clA1eHBGcmo3ZEhGNE5Rekg5bjh5MU5JeGFnaDUxMmV6TXZXQ2ZFWWRYT2M3RStaSi9DQjByS0paU3BTK0xlCkdzcEhON0R6UWltcVpwQjVBOFFmTjJNa0FzVjFvcUtQOWZ3K0NJZHJnb1hqZ0VSd3hqUTUxSXgwZkNyM0x1dWkKdDYwT3h2UmRLU0JqT2YxMHJTTVJoWEJ6aVNjMHNlajBDbmRWUHdJREFRQUJBb0lCQURQOWN6NlY1OU50dXBMYQpoWG9KbldLbHkxTkI2b2N0bXQ1eUM3Yzh4ZW1YQXZ6Vld1Qm5yQlJwYjdTZWIwV09ZblJ0bmxidHVMeWdMVEpHCncrdWtBK1NNZnB1ZnFmbkJXbHJqZ0tzMXMvU0N4Vk1xWjkrbWlzTUJIbGQzU3lmNmNBa2RPcTFJeEN0b2RNWW4KTEdNY0VSNkE5SzNoSXh3VW5xQnpKY3lmaVdsek5uTjNVM0thSG1PaG5COW9OMVZ4cGlXc2dGODRVSDJvWXNIdQphZG1JT1hKQ2RUVjh2ditGR3pNaWY4TTJEYVBiRGFEdG9KU3VnV29ZODhKUWlHbCtGSEtReWV1N2lkV1VuK2E2Ck9qbVByYVd0WlRuV2JkQ21OeWliZ1BZUk5YQXdHQkNLam9Ma1JNdmpOU011TXR1SlVZb0NxR05nbmY4NDNJWDAKYXdaR1gxRUNnWUVBNXNBVnQrZWYzdUxSYzRHVGgzZ3BFSnlWSldVaytCVnBlOWp5VGhNNUIrdFF0VGEwN3Q0OApaeEg0U0pYeEp6RGQzSk9adFpKU2lrYThyZ0F0QzBrQklES05EU0l0Q3BaR0VNWStpNFE0djBHQWxtRURJb1NPCkZGSENydkIvbjRaanJVYzhaOHRiU1hSaXQyb1hZRnBvQklxK282d1B1NTJVbUlDbm5zS2poK2NDZ1lFQTdhTmEKQnhoM0RGeDNzbUxSZzhLTXBXMHNPZ2VidEpucTN4YTE2VzdaRU9jS05vemRmM3duMnFaOWhTbmRsd1FXbk9QaApDbjlmbkw2VFUwbDdVSGRHQnBXKzVHN2tyRWFHakVDU0tJZU9UWDVJZnVuK1c1dlh0Y2JoVFpUUm9iWTdpMTBECk5KZFZQR1ZxRnRBdmZZS3NRZWlNaHgyTXl1bkZ3bThCeis4MXZPa0NnWUVBeHFPNnpvcnRuREREdjl4ZkJQS1MKMzBMOFBhblpibHI0YUczMUFQTVpXRkRoTkc1NHlWeTB3TUcrYTdYd1dCMkFFQjliNWV1bGRIVzZmVXVYZXl5SQpkSkF2em91S0hLQUtodXd4OFdhTWQxQkxBcWxXeW9NejBCZ21NUFRGMkswVzU1YjRVQjNHWXZCMi9vK3N1Zng1CnFOZExqNWhTSHQ5amlQalAweUtaSmljQ2dZQVZtMy9KRzJGZnYxeW0zTE5lUHFkWk4xY0pJNzMxcXZVZk9jcHEKb2tpY2I5V081am9ScUhGYlFUNHlpSDc4aDBPakdsbFJBZ25vajYrSHFDdk5RanNjeUNybVRHc0FleDBxellnOApwUzY4UHhwS1orNVgyQkRDRjRaTzdwUXRGd3ZNL1RVWWFCWTQrcU90MVZvc0dHQ2ZVWXpOa0ZOSDgvK21VVCtoCjc0YzhXUUtCZ0FUMmV4Q2cvUytqa2ZmNXlUcmFpQkhVL29MNmZSV0I1WjBCTW9RNCtuZHNaby9pYWpQQW9wdFEKekxjbnh5b0phd1puUVVrR1ZycG5INVQ1MkNEcGVZM3VobzdUQzcyMmhNZWZRSU05ajllY3gzTTVPQVMwUzBsOAo5eGpaZ2NQczA3U1BmcVlrTnQ2R1JiNlArbnRoTU9nd2UrbmM4bGhvYlA1Z2RUb0RVVThXCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

案例1:创建只能访问某个 namespace 的 User

我们想要创建一个 User Account,只能访问 dev-project 这个命名空间,对应的用户信息如下所示:

username: dev-user
group: developer
1. 创建用户凭证

Kubernetes 没有 User Account 的 API 对象,不过要创建一个用户帐号的话也是挺简单的,可以使用 OpenSSL 命令创建 X509证书来创建一个 User。

① 生成私钥:

openssl genrsa -out dev-user.key 2048

② 生成CSR:

openssl req -new -key dev-user.key -out dev-user.csr -subj "/CN=dev-user/O=developer"

③ 签发证书:

如果是自签名证书,执行以下操作;对于非自签名证书(通常由受信任的证书颁发机构 CA 签发),将CSR文件发给 CA机构即可。

如果使用的是 kubeadm 安装的集群,CA 相关证书位于 /etc/kubernetes/pki/ 目录下面,我们会利用该目录下面的 ca.crtca.key两个文件来批准上面的证书请求。生成最终的证书文件,我们这里设置证书的有效期为 3650 天:

openssl x509 -req -in dev-user.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out dev-user.crt -days 3650

现在查看我们当前文件夹下面是否生成了一个证书文件:

[root@node-01 dev-project]# ls
dev-user.crt  dev-user.csr  dev-user.key
  • dev-user.crt:私钥文件
  • dev-user.csr:证书请求文件
  • dev-user.key:证书文件

④ 验证证书:

使用以下命令可以验证我们的证书是不是CA签发的

[root@node-01 dev-project]# openssl verify -CAfile  /etc/kubernetes/pki/ca.crt  dev-user.crt 
dev-user.crt: OK

⑤ 创建凭证和上下文

  • 先创建用户凭证:凭证用于身份验证,确保在向 Kubernetes API 服务器发起请求时,该用户身份的合法性。

  • 再设置上下文:上下文包含了连接到 Kubernetes 集群所需的所有信息,包括使用的集群、命名空间和用户。

  • 在创建上下文之前,通常需要先创建用户凭证,因为上下文需要引用这些凭证。

创建凭证:

kubectl config set-credentials dev-user --client-certificate=dev-user.crt --client-key=dev-user.key

创建上下文:

kubectl config set-context dev-user-context --cluster=kubernetes --namespace=dev-project --user=dev-user

到这里,我们的用户 dev-user 就已经创建成功了,现在我们使用当前的这个配置文件来操作 kubectl 命令的时候,应该会出现错误,因为我们还没有为该用户定义任何操作的权限呢:

[root@node-01 dev-project]# kubectl  get pods --context=dev-user-context
Error from server (Forbidden): pods is forbidden: User "dev-user" cannot list resource "pods" in API group "" in the namespace "dev-project"

注意事项:

  • 默认情况下,kubectl 编辑和使用的配置文件是 ~/.kube/config,可以通过 --kubeconfig 选项或 KUBECONFIG 环境变量来指定其他配置文件。
  • --embed-certs=true :当设置为 true 时,将提供的证书(如客户端证书、客户端密钥和 CA 证书)的内容直接嵌入到配置文件中,而不是仅仅保存这些证书文件的路径,可以避免外部依赖。

在没有使用 --embed-certs=true 的情况下,kubeconfig 文件中的证书条目可能如下所示:

users:
- name: dev-user
  user:
    client-certificate: /etc/k8s/client.crt
    client-key: /etc/k8s/client.key

而如果使用了 --embed-certs=true,则 kubeconfig 文件中相应的部分会变为:

users:
- name: dev-user
  user:
    client-certificate-data: LS0tLS1CR...
    client-key-data: LS0tLS1L...

在这里,client-certificate-dataclient-key-data 中包含的是证书的 Base64 编码内容,而不是文件路径。

2. 创建角色

用户创建完成后,接下来就需要给该用户添加操作权限,我们来定义一个 YAML 文件,创建一个允许用户操作 Deployment、Pod、ReplicaSets 的角色,如下定义:(dev-user-role.yaml)

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: dev-user-role
  namespace: dev-project
rules:
- apiGroups: ["", "apps"]
  resources: ["deployments", "replicasets", "pods"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 也可以使用['*']

其中 Pod 属于 core 这个 API Group,在 YAML 中用空字符就可以,而 Deployment 和 ReplicaSet 现在都属于 apps 这个 API Group(如果不知道则可以用 kubectl explain 命令查看),所以 rules 下面的 apiGroups 就综合了这几个资源的 API Group:["", "apps"],其中verbs 就是我们上面提到的可以对这些资源对象执行的操作,我们这里需要所有的操作方法,所以我们也可以使用['*']来代替。然后直接创建这个 Role:

[root@node-01 useraccount]# kubectl apply -f dev-user-role.yaml
role.rbac.authorization.k8s.io/dev-user-role created
3. 创建角色权限绑定

Role 创建完成了,但是很明显现在我们这个 Role 和我们的用户 dev-user 还没有任何关系,所以我们就需要创建一个 RoleBinding 对象,在 dev-project 这个命名空间下面将上面的 dev-user-role 角色和用户 dev-user 进行绑定:(dev-user-rolebinding.yaml)

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-user-rolebinding
  namespace: kube-system
subjects:
- kind: User
  name: dev-user
  apiGroup: ""
roleRef:
  kind: Role
  name: dev-user-role
  apiGroup: rbac.authorization.k8s.io

上面的 YAML 文件中我们看到了 subjects 字段,就是我们上面提到的用来操作集群的对象,对应上面的 User 帐号 dev-user,使用 kubectl 创建上面的资源对象:

[root@node-01 useraccount]# kubectl apply -f dev-user-rolebinding.yaml
rolebinding.rbac.authorization.k8s.io/dev-user-rolebinding created
4. 验证

现在我们可以使用 dev-user-context 上下文来操作集群了:

[root@node-01 17-security]# kubectl  -n dev-project  apply -f nginx-dep.yaml  --context=dev-user-context
deployment.apps/nginx-dep created

[root@node-01 17-security]#  kubectl  -n dev-project  get pods --context=dev-user-context
NAME                         READY   STATUS    RESTARTS   AGE
nginx-dep-79f77dd7b7-gbbb9   1/1     Running   0          50s
nginx-dep-79f77dd7b7-p4bln   1/1     Running   0          50s

[root@node-01 17-security]# kubectl  -n dev-project  get deployment,rs --context=dev-user-context
NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-dep   2/2     2            2           2m32s

NAME                                   DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-dep-79f77dd7b7   2         2         2       2m32s

如果去获取其他的资源对象呢,可以看到并没有权限获取,因为我们没有为当前操作用户指定其他对象资源的访问权限,是符合我们的预期的。这样我们就创建了一个只有单个命名空间访问权限的普通 User 。

[root@node-01 17-security]#  kubectl  -n dev-project  get cm --context=dev-user-context
Error from server (Forbidden): configmaps is forbidden: User "dev-user" cannot list resource "configmaps" in API group "" in the namespace "dev-project"
[root@node-01 17-security]# 
[root@node-01 17-security]#  kubectl  -n default  get cm --context=dev-user-context
Error from server (Forbidden): configmaps is forbidden: User "dev-user" cannot list resource "configmaps" in API group "" in the namespace "default"

案例2: 创建只能访问某个 namespace 的 SA

上面我们创建了一个只能访问某个命名空间下面的 User Account,我们前面也提到过 subjects 下面还有一种类型的主题资源:ServiceAccount,现在我们来创建一个集群内部的用户只能操作 default 这个命名空间下面的 pods 、deployments 和 replicasets 对象.

1. 首先来创建一个 SA
kubectl -n default create sa namespace-user

我们也可以定义成 YAML 文件的形式来创建:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: namespace-user 
  namespace: default 
2. 然后新建一个 Role
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: namespace-user-role
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list"]
- apiGroups: ["", "apps"]
  resources: ["deployments", "replicasets", "pods"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
kubectl apply -f namespace-user-role.yaml
3. 然后创建一个 RoleBinding

将上面的 namespace-user 和角色 namespace-user-role 进行绑定:

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: namespace-user-rolebinding
  namespace: default
subjects:
- kind: ServiceAccount
  name: namespace-user
roleRef:
  kind: Role
  name: namespace-user-role 
  apiGroup: rbac.authorization.k8s.io
4. 创建 config

①创建脚本

#!/bin/bash
# The script returns a kubeconfig for the service account given
# you need to have kubectl on PATH with the context set to the cluster you want to create the config for

# Cosmetics for the created config
clusterName=kubernetes				#kubernetes集群名
# your server address goes here get it via `kubectl cluster-info`
server=https://192.168.17.110:6443		#集群中api-server地址
# the Namespace and ServiceAccount name that is used for the config
namespace=default					#哪个命名空间
serviceAccount=xxhf					#为哪个sa生成

######################
# actual script starts
set -o errexit

secretName=$(kubectl --namespace $namespace get serviceAccount $serviceAccount -o jsonpath='{.secrets[0].name}')
ca=$(kubectl --namespace $namespace get secret/$secretName -o jsonpath='{.data.ca\.crt}')
token=$(kubectl --namespace $namespace get secret/$secretName -o jsonpath='{.data.token}' | base64 --decode)

echo "
---
apiVersion: v1
kind: Config
clusters:
  - name: ${clusterName}
    cluster:
      certificate-authority-data: ${ca}
      server: ${server}
contexts:
  - name: ${serviceAccount}@${clusterName}
    context:
      cluster: ${clusterName}
      namespace: ${namespace}
      user: ${serviceAccount}
users:
  - name: ${serviceAccount}
    user:
      token: ${token}
current-context: ${serviceAccount}@${clusterName}

脚本说明:使用脚本的时候按需求修改字段

②基于脚本创建 config

 ./sa-to-kubeconfig.sh >config
6. 验证
[root@node-01 .kube]# kubectl  --kubeconfig=config  get pods 
NAME                         READY   STATUS    RESTARTS   AGE
nginx-dep-587b6fd57c-dwn9g   1/1     Running   0          4d9h
redis-pv-sts-0               1/1     Running   0          4d6h
redis-pv-sts-1               1/1     Running   0          4d6h
[root@node-01 .kube]# 
[root@node-01 .kube]# 
[root@node-01 .kube]# kubectl  --kubeconfig=conifg  get cm
Error from server (Forbidden): configmaps is forbidden: User "system:serviceaccount:default:namespace-user" cannot list resource "configmaps" in API group "" in the namespace "default"
SA 和 User 的区别

在 Kubernetes 的 kubeconfig 文件中,users.user 字段的内容可以包含两种不同的身份验证方法:client-certificate-dataclient-key-data,以及 token。这两种方法的区别主要在于它们的身份验证机制和用途。下面详细解释这两者的区别:

①Client Certificate Authentication(user)

  • 字段:

    • client-certificate-data: 包含客户端证书的 Base64 编码数据。
    • client-key-data: 包含客户端证书私钥的 Base64 编码数据。
  • 用途:

    • 客户端证书身份验证是一种基于公钥的身份验证方法。Kubernetes 集群在接收到请求时,会验证请求者提供的证书是否有效。
    • 客户端证书一般是由受信任的证书颁发机构(CA)签发的。Kubernetes API 服务器会使用 CA 来验证客户端证书的有效性。
  • 优点:

    • 提供强身份验证,适用于对安全性要求较高的场景。
    • 不需要经常更新(除非证书到期),适合长期使用。
  • 配置示例:

    users:
      - name: my-user
        user:
          client-certificate-data: <Base64-encoded-client-cert>
          client-key-data: <Base64-encoded-client-key>
    

②Token Authentication(SA)

  • 字段:

    • token: 包含用于身份验证的令牌,通常是一个短字符串。
  • 用途:

    • Token 身份验证是一种简单而有效的身份验证方式。令牌通常与 Kubernetes 中的服务账户相关联,用于快速验证。
    • 服务账户的令牌是由 Kubernetes 自动生成并管理的,用户无需手动创建和更新。
  • 优点:

    • 简单易用,适合快速配置。
    • 通常用于服务账户和应用程序之间的身份验证。
  • 配置示例:

    users:
      - name: my-user
        user:
          token: <service-account-token>
    

③总结

  • 使用场景:

    • 使用 client certificate authentication 通常用于需要高安全性的场合,如管理员或需要进行敏感操作的用户。
    • 使用 token authentication 更适合自动化工具和服务账户的场景,因为它的配置和管理相对简单。
  • 安全性:

    • 客户端证书提供了更强的安全性,因为它基于公钥基础设施(PKI),并且可以使用更复杂的策略进行管理。
    • Token 在过期后可能需要更新,虽然 Kubernetes 会自动管理服务账户的令牌,但这可能在某些情况下成为管理负担。

选择使用哪种身份验证方式取决于具体的使用场景、管理策略和安全需求。

11.2 网络策略 Network Policy

11.2.1 网络策略是什么

在 Kubernetes 中部署应用时,通常会根据不同的项目、应用类型和部门划分不同的 Namespace,以实现应用的隔离。然而,这种隔离实际上是“软隔离”。例如,通过 Kubernetes 的 Service 名称结合 Namespace 名称,可以跨 Namespace 访问服务。同时,Pod 的 IP 地址也允许全局互访。

这种情况下,集群的服务安全性较低。如果某个服务被入侵,攻击者可能会利用各种手段进行全局扫描。因此,有效的访问控制显得尤为重要。在传统架构中,例如虚拟机和物理机,可以通过 iptables、firewalld 等工具进行访问控制。然而,在高度弹性和可扩展的 Kubernetes 平台上,这些方法已经无法满足需求。因此,Kubernetes 引入了网络策略(Network Policy)的概念,结合 CNI 网络插件实现细粒度的访问控制。

注意事项:在使用网络策略之前,集群中需要安装支持网络策略的插件,如 Calico 或 Weave,而 Flannel 则不支持该功能。

11.2.2 定义网络策略

以下是一个 Kubernetes 网络策略示例:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-np
  namespace: default
spec:
  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

与其他资源一样,NetworkPolicy 也需包含 apiVersionkindmetadata 字段,配置方式类似。NetworkPolicy 的策略从 spec 字段开始:

  • podSelector:指定策略适用的 Pod。示例中选择 role=db,意味着该策略作用于当前命名空间下符合该标签的 Pod。如果该字段为空,则适用于所有 Pod。
  • policyTypes:定义网络策略类型。支持入站(Ingress)和出站(Egress)规则。出站表示符合 podSelector 的 Pod 的出口流量限制,入站则是对符合条件的 Pod 的访问限制。如果未指定 policyTypes,则默认为 Ingress;如果未指定,但有出站规则,则会自动配置 Egress。
  • ingress:管理入口流量。每个 NetworkPolicy 可以包含一个 Ingress 白名单,每条规则允许匹配 fromports 部分的流量。其中,from 表示访问来源,可配置为 ipBlocknamespaceSelectorpodSelector。如果为空,则匹配所有来源。ports 表示可访问的端口列表,若为空则匹配所有端口。
    • ipBlock:指定匹配的 IP 块,可以是单个 IP 或网段,同时支持 IPv6 格式。except 为可选参数,用于排除某些地址。
    • namespaceSelector:匹配具有指定标签的 Namespace 下的所有 Pod。当前示例中,Ingress 的 from 配置了 namespaceSelector,表示允许来自 project=myproject 标签的 Namespace 下的所有 Pod。
  • egress:管理出口流量。NetworkPolicy 同样可以包含一个 Egress 白名单,其可配置参数为 toports。其中 ports 表示可访问的目标端口,to 表示访问的目标,可以配置为 ipBlocknamespaceSelectorpodSelector

根据上述概念,示例的含义如下:

  • 隔离 default 命名空间下具有 role=db 标签的 Pod。
  • 允许 IP 范围 172.17.0.0 ~ 172.17.255.255 访问 default 命名空间下的 role=db Pod 的 TCP 6379 端口。
  • 允许具有 project=myproject 标签的 Namespace 下的所有 Pod 访问 default 命名空间的 role=db Pod 的 TCP 6379 端口。
  • 允许 default 命名空间(与 NetworkPolicy 同一命名空间)下具有 role=frontend 标签的 Pod 访问 default 命名空间的 role=db Pod 的 TCP 6379 端口。
  • 允许带有 role=db 标签的 Pod 访问 10.0.0.0/24 网段的 TCP 5978 端口。

案例1:在线电商平台

项目架构
  • 前端服务(frontend):处理用户请求,显示商品。
  • 后端服务(backend):处理业务逻辑,与数据库交互。
  • 数据库服务(database):存储用户和商品数据。
1. 标签设置
  • 前端服务 Pod 标签:role: frontend
  • 后端服务 Pod 标签:role: backend
  • 数据库服务 Pod 标签:role: db
2. NetworkPolicy
# 允许后端访问数据库
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-db-access
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: backend
    ports:
    - protocol: TCP
      port: 6379  # 假设数据库监听的端口

---

# 允许前端访问后端
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-backend-access
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 8080  # 假设后端监听的端口

通过这两个网络策略:

  • 前端服务无法直接访问数据库,增加了安全性。
  • 只有后端服务可以与数据库进行交互,防止未授权访问。

这种网络策略确保了在线电商平台的服务之间的安全通信,增强了系统的安全性和可靠性。

0

评论区