Kubernetes 中的安全基础知识:身份验证、授权、审计

Kubernetes 中的安全基础知识:身份验证、授权、审计

在任何系统的运行中,迟早都会出现安全问题:确保身份验证、权限分离、审计和其他任务。 已经为 Kubernetes 创建了 许多解决方案,即使在非常苛刻的环境中,您也可以实现符合标准...相同的材料专门介绍了 K8s 内置机制中实现的安全性的基本方面。 首先,它对于那些开始熟悉 Kubernetes 的人来说非常有用——作为研究安全相关问题的起点。

认证

Kubernetes 中有两种类型的用户:

  • 服务帐号 — 由 Kubernetes API 管理的帐户;
  • 用户 — 由外部独立服务管理的“普通”用户。

这些类型之间的主要区别在于,对于服务帐户,Kubernetes API 中有特殊对象(它们被称为 - ServiceAccounts),它们与命名空间和存储在集群中 Secrets 类型的对象中的一组授权数据相关联。 此类用户(服务帐户)主要用于管理 Kubernetes 集群中运行的进程对 Kubernetes API 的访问权限。

普通用户在 Kubernetes API 中没有条目:它们必须由外部机制管理。 它们适用于生活在集群外部的人员或进程。

每个 API 请求都与一个服务帐户、一个用户相关联,或者被视为匿名。

用户认证数据包括:

  • 用户名 — 用户名(区分大小写!);
  • UID - 机器可读的用户识别字符串,“比用户名更一致和唯一”;
  • 组别 — 用户所属组的列表;
  • 追求卓越 — 授权机制可以使用的附加字段。

Kubernetes 可以使用大量的身份验证机制:X509 证书、承载令牌、身份验证代理、HTTP 基本身份验证。 使用这些机制,您可以实现大量授权方案:从带有密码的静态文件到 OpenID OAuth2。

此外,可以同时使用多种授权方案。 默认情况下,集群使用:

  • 服务帐户令牌 - 用于服务帐户;
  • X509 - 对于用户。

有关管理 ServiceAccounts 的问题超出了本文的范围,但对于那些想要更详细地熟悉此问题的人,我建议从 官方文档页面。 我们将仔细研究 X509 证书如何工作的问题。

用户证书 (X.509)

使用证书的经典方法包括:

  • 密钥生成:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • 生成证书请求:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • 使用 Kubernetes 集群 CA 密钥处理证书请求,获取用户证书(要获取证书,您必须使用有权访问 Kubernetes 集群 CA 密钥的帐户,默认情况下位于 /etc/kubernetes/pki/ca.key):
    openssl x509 -req -in ~/.certs/mynewuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ~/.certs/mynewuser.crt -days 500
  • 创建配置文件:
    • 集群描述(指定特定集群安装的 CA 证书文件的地址和位置):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • 或如何 没有推荐选项 - 您不必指定根证书(然后 kubectl 将不会检查集群 api-server 的正确性):
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • 在配置文件中添加用户:
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt  --client-key=.certs/mynewuser.key
    • 添加上下文:
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • 默认上下文分配:
      kubectl config use-context mynewuser-context

经过上述操作后,在文件中 .kube/config 将创建这样的配置:

apiVersion: v1
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/pki/ca.crt
    server: https://192.168.100.200:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    namespace: target-namespace
    user: mynewuser
  name: mynewuser-context
current-context: mynewuser-context
kind: Config
preferences: {}
users:
- name: mynewuser
  user:
    client-certificate: /home/mynewuser/.certs/mynewuser.crt
    client-key: /home/mynewuser/.certs/mynewuser.key

为了更轻松地在帐户和服务器之间传输配置,编辑以下键的值很有用:

  • certificate-authority
  • client-certificate
  • client-key

为此,您可以使用 base64 对其中指定的文件进行编码,并将它们注册到配置中,将后缀添加到键的名称中 -data, IE。 已收到 certificate-authority-data 等等

kubeadm 的证书

随着发布 库伯内斯 1.15 由于 alpha 版本的支持,使用证书变得更加容易 kubeadm 实用程序。 例如,使用用户密钥生成配置文件现在可能如下所示:

kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200

NB: 必需的 广告地址 可以在 api-server 配置中找到,默认情况下位于 /etc/kubernetes/manifests/kube-apiserver.yaml.

生成的配置将输出到 stdout。 需要保存在 ~/.kube/config 用户帐户或环境变量中指定的文件 KUBECONFIG.

深入挖掘

对于那些想要更彻底地理解所描述的问题的人:

授权

默认授权账户没有集群操作权限。 为了授予权限,Kubernetes 实现了授权机制。

在 1.6 版本之前,Kubernetes 使用一种称为 ABAC (基于属性的访问控制)。 有关它的详细信息可以在 官方文档。 此方法目前被认为是遗留方法,但您仍然可以将其与其他身份验证类型一起使用。

当前(并且更灵活)划分集群访问权限的方式称为 RBAC (基于角色的访问控制)。 自版本起已宣布稳定 库伯内斯 1.8。 RBAC 实现了一种权限模型,其中所有未明确允许的内容都被禁止。
启用 RBAC,需要使用参数启动 Kubernetes api-server --authorization-mode=RBAC。 这些参数在清单中使用 api-server 配置进行设置,默认情况下位于路径上 /etc/kubernetes/manifests/kube-apiserver.yaml,在部分 command。 但是,RBAC 默认情况下已启用,因此您很可能不必担心:您可以通过值验证这一点 authorization-mode (在已经提到的 kube-apiserver.yaml)。 顺便说一句,其含义中可能还有其他类型的授权(node, webhook, always allow),但我们会将他们的考虑留在材料的范围之外。

顺便说一句,我们已经发布了 文章 对使用 RBAC 的原理和功能进行了相当详细的描述,因此我将仅简要列出基础知识和示例。

以下 API 实体用于通过 RBAC 控制 Kubernetes 中的访问:

  • Role и ClusterRole — 用于描述访问权限的角色:
  • Role 允许您描述名称空间内的权限;
  • ClusterRole - 集群内,包括特定于集群的对象,例如节点、非资源 url(即与 Kubernetes 资源无关 - 例如, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - 用于绑定 Role и ClusterRole 到用户、用户组或 ServiceAccount。

Role 和 RoleBinding 实体受命名空间限制,即必须位于同一命名空间内。 但是,RoleBinding 可以引用 ClusterRole,这允许您创建一组通用权限并使用它们控制访问。

角色使用规则集描述权利,其中包含:

  • API 组 - 请参阅 官方文档 通过 apiGroups 和输出 kubectl api-resources;
  • 资源 (资源: pod, namespace, deployment 等等。);
  • 动词 (动词: set, update 等等)。
  • 资源名称(resourceNames) - 适用于您需要提供对特定资源而不是所有此类资源的访问权限的情况。

Kubernetes中授权的更详细的分析可以在页面找到 官方文档。 相反(或者更确切地说,除此之外),我将举一些例子来说明她的工作。

RBAC 实体示例

简单 Role,它允许您获取 Pod 的列表和状态并在命名空间中监视它们 target-namespace:

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

例子 ClusterRole,它允许您获取 Pod 的列表和状态并在整个集群中监控它们:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # секции "namespace" нет, так как ClusterRole задействует весь кластер
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

例子 RoleBinding,这允许用户 mynewuser “读取”命名空间中的 Pod my-namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: target-namespace
subjects:
- kind: User
  name: mynewuser # имя пользователя зависимо от регистра!
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role # здесь должно быть “Role” или “ClusterRole”
  name: pod-reader # имя Role, что находится в том же namespace,
                   # или имя ClusterRole, использование которой
                   # хотим разрешить пользователю
  apiGroup: rbac.authorization.k8s.io

事件审核

概括地说,Kubernetes 架构可以表示如下:

Kubernetes 中的安全基础知识:身份验证、授权、审计

负责处理请求的关键 Kubernetes 组件是 api服务器。 集群上的所有操作都要经过它。 您可以在文章“中阅读有关这些内部机制的更多信息”当您运行 kubectl run 时,Kubernetes 中会发生什么?“。

系统审计是 Kubernetes 中一个有趣的功能,默认情况下处于禁用状态。 它允许您记录对 Kubernetes API 的所有调用。 正如您可能猜到的,与监视和更改集群状态相关的所有操作都是通过此 API 执行的。 其功能的详细描述(像往常一样)可以在以下位置找到: 官方文档 K8s。 接下来,我将尝试用更简单的语言来表达这个主题。

因此, 启用审计,我们需要向 api-server 中的容器传递三个必需的参数,下面详细介绍:

  • --audit-policy-file=/etc/kubernetes/policies/audit-policy.yaml
  • --audit-log-path=/var/log/kube-audit/audit.log
  • --audit-log-format=json

除了这三个必要的参数之外,还有许多与审核相关的附加设置:从日志轮换到 Webhook 描述。 日志轮转参数示例:

  • --audit-log-maxbackup=10
  • --audit-log-maxsize=100
  • --audit-log-maxage=7

但我们不会更详细地讨论它们 - 您可以在以下位置找到所有详细信息 kube-apiserver 文档.

如前所述,所有参数均在清单中使用 api-server 配置进行设置(默认情况下 /etc/kubernetes/manifests/kube-apiserver.yaml),在部分 command。 我们回到3个必填参数来分析一下:

  1. audit-policy-file — 描述审核策略的 YAML 文件的路径。 我们稍后会返回到它的内容,但现在我会注意到该文件必须可由 api 服务器进程读取。 因此,有必要将其挂载到容器内,为此您可以将以下代码添加到配置的相应部分:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path — 日志文件的路径。 该路径也必须可供 api-server 进程访问,因此我们以相同的方式描述其挂载:
      volumeMounts:
        - mountPath: /var/log/kube-audit
          name: logs
          readOnly: false
      volumes:
      - hostPath:
          path: /var/log/kube-audit
          type: DirectoryOrCreate
        name: logs
  3. audit-log-format — 审核日志格式。 默认为 json,但旧版文本格式也可用(legacy).

审核政策

现在关于描述日志记录策略的上述文件。 审计政策的第一个概念是 level, 记录级别。 它们如下:

  • None - 不记录;
  • Metadata — 日志请求元数据:用户、请求时间、目标资源(pod、命名空间等)、操作类型(动词)等;
  • Request — 记录元数据和请求正文;
  • RequestResponse — 日志元数据、请求正文和响应正文。

最后两级(Request и RequestResponse)不记录未访问资源的请求(访问所谓的非资源 url)。

所有请求也都会通过 几个阶段:

  • RequestReceived ——请求被处理器接收并且尚未沿着处理器链进一步传输的阶段;
  • ResponseStarted — 发送响应标头,但在发送响应正文之前。 为长时间运行的查询生成(例如, watch);
  • ResponseComplete — 响应正文已发送,不再发送任何信息;
  • Panic — 当检测到异常情况时生成事件。

要跳过您可以使用的任何步骤 omitStages.

在策略文件中,我们可以描述具有不同日志记录级别的多个部分。 将应用策略描述中找到的第一个匹配规则。

kubelet 守护进程使用 api-server 配置监视清单中的更改,如果检测到任何更改,则使用 api-server 重新启动容器。 但有一个重要的细节: 策略文件中的更改将被忽略。 更改策略文件后,您需要手动重新启动 api-server。 由于 api-server 启动为 静态吊舱, 团队 kubectl delete 不会导致它重新启动。 你必须手动完成 docker stop 在 kube-masters 上,审计策略已更改:

docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')

启用审核时,请务必记住 kube-apiserver 上的负载增加。 特别是,用于存储请求上下文的内存消耗增加。 仅在发送响应标头后才开始记录。 负载还取决于审核策略配置。

政策示例

让我们通过示例来了解策略文件的结构。

这是一个简单的文件 policy记录该级别的所有内容 Metadata:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata

在策略中,您可以指定用户列表(Users и ServiceAccounts)和用户组。 例如,这就是我们如何忽略系统用户,但在该级别记录其他所有内容 Request:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: None
    userGroups:
      - "system:serviceaccounts"
      - "system:nodes"
    users:
      - "system:anonymous"
      - "system:apiserver"
      - "system:kube-controller-manager"
      - "system:kube-scheduler"
  - level: Request

也可以描述目标:

  • 命名空间(namespaces);
  • 动词 (动词: get, update, delete 和别的);
  • 资源 (资源具体情况如下: pod, configmaps 等)和资源组(apiGroups).

注意! 可以使用以下命令获取资源和资源组(API 组,即 apiGroups)及其在集群中安装的版本:

kubectl api-resources
kubectl api-versions

提供以下审计政策作为最佳实践的演示 阿里云文档:

apiVersion: audit.k8s.io/v1beta1
kind: Policy
# Не логировать стадию RequestReceived
omitStages:
  - "RequestReceived"
rules:
  # Не логировать события, считающиеся малозначительными и не опасными:
  - level: None
    users: ["system:kube-proxy"]
    verbs: ["watch"]
    resources:
      - group: "" # это api group с пустым именем, к которому относятся
                  # базовые ресурсы Kubernetes, называемые “core”
        resources: ["endpoints", "services"]
  - level: None
    users: ["system:unsecured"]
    namespaces: ["kube-system"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["configmaps"]
  - level: None
    users: ["kubelet"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["nodes"]
  - level: None
    userGroups: ["system:nodes"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["nodes"]
  - level: None
    users:
      - system:kube-controller-manager
      - system:kube-scheduler
      - system:serviceaccount:kube-system:endpoint-controller
    verbs: ["get", "update"]
    namespaces: ["kube-system"]
    resources:
      - group: "" # core
        resources: ["endpoints"]
  - level: None
    users: ["system:apiserver"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["namespaces"]
  # Не логировать обращения к read-only URLs:
  - level: None
    nonResourceURLs:
      - /healthz*
      - /version
      - /swagger*
  # Не логировать сообщения, относящиеся к типу ресурсов “события”:
  - level: None
    resources:
      - group: "" # core
        resources: ["events"]
  # Ресурсы типа Secret, ConfigMap и TokenReview могут содержать  секретные данные,
  # поэтому логируем только метаданные связанных с ними запросов
  - level: Metadata
    resources:
      - group: "" # core
        resources: ["secrets", "configmaps"]
      - group: authentication.k8s.io
        resources: ["tokenreviews"]
  # Действия типа get, list и watch могут быть ресурсоёмкими; не логируем их
  - level: Request
    verbs: ["get", "list", "watch"]
    resources:
      - group: "" # core
      - group: "admissionregistration.k8s.io"
      - group: "apps"
      - group: "authentication.k8s.io"
      - group: "authorization.k8s.io"
      - group: "autoscaling"
      - group: "batch"
      - group: "certificates.k8s.io"
      - group: "extensions"
      - group: "networking.k8s.io"
      - group: "policy"
      - group: "rbac.authorization.k8s.io"
      - group: "settings.k8s.io"
      - group: "storage.k8s.io"
  # Уровень логирования по умолчанию для стандартных ресурсов API
  - level: RequestResponse
    resources:
      - group: "" # core
      - group: "admissionregistration.k8s.io"
      - group: "apps"
      - group: "authentication.k8s.io"
      - group: "authorization.k8s.io"
      - group: "autoscaling"
      - group: "batch"
      - group: "certificates.k8s.io"
      - group: "extensions"
      - group: "networking.k8s.io"
      - group: "policy"
      - group: "rbac.authorization.k8s.io"
      - group: "settings.k8s.io"
      - group: "storage.k8s.io"
  # Уровень логирования по умолчанию для всех остальных запросов
  - level: Metadata

审计政策的另一个很好的例子是 GCE 中使用的配置文件.

为了快速响应审计事件,可以 描述网络钩子。 这个问题包含在 官方文档,我将把它排除在本文的讨论范围之外。

结果

本文概述了 Kubernetes 集群中的基本安全机制,允许您创建个性化的用户帐户、分离他们的权限并记录他们的操作。 我希望它对那些在理论上或实践中面临此类问题的人有用。 我还建议您阅读“PS”中给出的有关 Kubernetes 安全性主题的其他材料列表 - 也许您会在其中找到与您相关的问题的必要详细信息。

PS

另请阅读我们的博客:

来源: habr.com

添加评论