本文主要介绍身份认证和访问控制包含的两部分基本功能:认证和授权。认证即判断用户是否为能够访问集群的合法用户,授权负责管理指定用户身份对集群资源的访问权限。

ACK集群的认证和授权

Kubernetes使用X.509证书、Bearer Tokens、身份验证代理或者OIDC认证等方式来对API请求进行身份验证。关于ACK原生、访问ACK集群的两种方式,请参见客户端证书服务账户令牌

客户端证书Kubeconfig可以通过阿里云控制台、ACK的Openapi接口等获取。更多信息,请参见获取集群kubeconfig接口使用ServiceAccount Token访问Kubernetes集群

容器服务授权包含RAM授权和RBAC授权两部分。当您需要对集群进行可见性、扩缩容、添加节点等操作时,需要进行自定义RAM授权策略。目前RAM主要支持RAM系统策略授权和RAM自定义策略授权两种授权方式。当RAM用户需要操作指定集群内K8s资源时(例如,获取集群Pod和Node信息),需要在容器服务管理控制台的授权管理页面对指定RAM用户进行数据平面资源的RBAC授权。更多信息,请参见授权概述

  • 使用临时Kubeconfig和Apiserver认证

    ACK默认返回的集群访问凭证Kubeconfig中的证书有效期是3年,若Kubeconfig发生泄露,攻击者可以直接获得集群Apiserver的访问权限,默认的ServiceAccount Token同样是一种长期有效的静态凭据,如果泄露攻击者同样可以获得该ServiceAccount绑定的集群访问权限,直到该ServiceAccount被删除。

    因此请您及时吊销可能发生泄露的已下发Kubeconfig凭证。具体操作,请参见吊销集群的KubeConfig凭证。关于ACK集群的访问凭证,请参见生成临时的KubeConfig

  • 遵循权限最小化原则访问阿里云资源

    如果某个用户需要访问ACK集群,无需为用户分配访问其他云产品资源的权限,保证用户访问云产品资源权限最小化。可以通过配置RAM和RBAC为该用户授予访问ACK集群的权限。

  • 在创建RoleBindings和ClusterRoleBindings时使用最低访问权限

    和授予访问云资源的权限一样,在创建RoleBindingsClusterRoleBindings时,同样需要遵循权限最小化原则。应该尽量避免在创建RoleClusterRole时使用["*"],应该明确到具体的Verbs。如果您不确定要分配哪些权限,请考虑使用类似audit2rbac之类的工具,根据Kubernetes审计日志中观察到的API调用自动生成角色和绑定。

  • 控制ACK集群Endpoint的访问范围

    默认情况下,当您配置ACK集群时,集群的Apiserver Endpoint仅为内网访问,即仅可以集群和VPC内部访问。关于创建出来的Service能够实现公网访问并控制Endpoint的访问范围,请参见通过Annotation配置负载均衡

  • 定期对集群的访问权限进行审计

    对集群的访问权限可能会随着时间的推移而改变。需要集群的安全管理运维人员定期审核RAM配置和配置RAM用户RBAC权限来查看指定RAM用户是否被分配了合适的权限。或关于使用开源工具来检查绑定到特定服务帐户、用户或组的RBAC权限,并及时收敛不符合需要的过大权限配置。请参见kubectl-who-canrbac-lookup

Pods认证

在Kubernetes集群中运行的某些应用程序需要调用Kubernetes API的权限才能正常运行。ACK CCM组件需要对Nodes资源进行增删改查权限。

  • Kubernetes Service Accounts

    服务帐户(Service Accounts)是一种特殊类型的对象,允许您将Kubernetes RBAC角色分配给Pod。K8s会为集群中的每个命名空间自动创建一个默认服务帐户。当您在不引用特定服务帐户的情况下将Pod部署到命名空间时,该命名空间的默认服务帐户将自动分配给Pod和Secret,即该服务帐户的服务帐户 (JWT) 令牌,将挂载到Pod作为一个卷位于/var/run/secrets/kubernetes.io/serviceaccount。解码该目录中的服务帐户令牌将显示以下元数据:

    {
      "iss": "kubernetes/serviceaccount",
      "kubernetes.io/serviceaccount/namespace": "default",
      "kubernetes.io/serviceaccount/secret.name": "default-token-vpc2x",
      "kubernetes.io/serviceaccount/service-account.name": "default",
      "kubernetes.io/serviceaccount/service-account.uid": "1d059c50-0818-4b15-905d-bbf05e1d****",
      "sub": "system:serviceaccount:default:default"
    }

    默认服务帐户对Kubernetes API具有以下权限:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      annotations:
        rbac.authorization.kubernetes.io/autoupdate: "true"
      labels:
        kubernetes.io/bootstrapping: rbac-defaults
      name: system:discovery
    rules:
    - nonResourceURLs:
      - /api
      - /api/*
      - /apis
      - /apis/*
      - /healthz
      - /openapi
      - /openapi/*
      - /version
      - /version/
      verbs:
      - get

    此角色授予未经身份验证和经过身份验证的用户读取API信息,并被视为可公开访问的安全角色。

    当在Pod中运行的应用程序调用Kubernetes API时,需要为Pod分配一个服务帐户,明确授予其调用API的权限。绑定到服务帐户的Role或 ClusterRole应仅限于应用程序运行所需的API资源和方法,遵循权限最小化原则。要使用非默认服务帐户,只需将Pod的spec.serviceAccountName字段设置为您希望使用的服务帐户。有关创建服务帐户的其他信息,请参见ServiceAccount permissions

  • 部署服务账户令牌卷投影

    您可以在容器服务ACK中开启服务账户令牌卷投影功能以降低在Pod中使用ServiceAccount遇到的安全性问题,此功能可使得Kubelet支持基于Pod粒度的Token签发,并且支持Token audience和过期时间的配置。当Token即将过期(过期时间的80%或者Token存在大于24小时),Kubelet支持对Token的自动刷新。具体操作,请参见部署服务账户令牌卷投影

  • 限制节点对实例元数据API的访问

    ECS实例元数据概述包含了ECS实例在阿里云系统中的信息,您可以在运行中的实例内方便地查看实例元数据,并基于实例元数据配置或管理实例。实例元数据中能够查询到用户使用的云资源和用户数据等敏感信息,若不加限制的暴露给节点,在多租等场景下很容易被攻击者利用。因此,需要限制Pod对于meta-server的访问,可以通过Network Policy限制Pod对于meta-server的访问。可以通过如下规则使用podSelector控制指定Pod对meta-server的访问:

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: allow-metadata-access
      namespace: example
    spec:
      podSelector:
        matchLabels:
          app: myapp
      policyTypes:
      - Egress
      egress:
      - to:
        - ipBlock:
            cidr: 100.100.100.200/32

    更多信息,请参见使用网络策略Network Policy

  • 禁止Pod对Service Account令牌的自动挂载

    可通过以下两种方式取消Pod对Service Account令牌的自动挂载。

    方式一:通过修改YAML将应用程序PodSpec字段中的automountServiceAccountToken属性设置为false
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    spec:
      serviceAccountName: build-robot
      automountServiceAccountToken: false
      ...

    方式二:执行以下命令,patch命名空间中的默认服务帐户,将automountServiceAccountToken属性设置为false

    kubectl patch serviceaccount default -p $'automountServiceAccountToken: false'
  • 为每个应用分配独立的Service Account

    每个应用程序都应该有自己专用的服务帐户,便于不同应用之间的授权管理,实现应用维度的细粒度权限隔离。关于为应用分配独立的服务账户,请参见为Pod配置服务账户

  • 以非root用户运行应用

    默认情况下,容器以root身份运行。这允许容器中的进程对容器中的文件进行任意的读取和写入,但以root身份运行容器并不是最佳安全实践。作为替代方案,请考虑将spec.securityContext.runAsUser属性添加到PodSpecrunAsUser的值为任意值。

    在以下示例中,Pod中的所有进程都将在runAsUser字段中指定的用户ID下运行。

    apiVersion: v1
    kind: Pod
    metadata:
      name: security-test
    spec:
      securityContext:
        runAsUser: 1000
        runAsGroup: 3000
      containers:
      - name: sec-test
        image: busybox
        command: [ "sh", "-c", "sleep 1h" ]

    此时,对于容器中需要root权限才能访问的文件,容器中的进程则无法访问。如果您更新容器的securityContext以包含fsgroup=65534 [Nobody],将允许读取容器中的文件。

    spec:
      securityContext:
        fsGroup: 65534
  • 遵循权限最小化原则分配应用对云上阿里云资源的访问权限

    避免为应用所在节点分配不必要的RAM权限,遵循权限最小化原则细粒度定制应用所需的RAM策略,避免在权限策略中出现["*"]等可能扩大访问权限的配置。