跳转到主要内容

热门内容

今日:


总体:


最近浏览:


Chinese, Simplified

category

Kubernetes(k8s)集群包括称为节点的工作机器和由API服务器、调度器等组成的控制平面、控制器管理器,以及在PaaS(平台即服务)的情况下的云控制器管理器。部署到集群的容器在工作节点上的pod中运行。同时,控制平面负责调度、响应请求和管理集群。

当您使用kubectl、客户端库或像KDash这样的工具与Kubernetes集群通信时,您主要是与Kubernet API服务器交互。API服务器负责管理集群,并负责处理来自客户端的请求。

  1. 为什么要保护API服务器?
  2. 为什么选择OpenID Connect?
  3. 使用Okta作为OIDC提供商来保护API服务器的安全
    1. 您需要开始的内容
    2. 设置Okta OIDC应用程序和授权服务器
      1. 设置Terraform
      2. 创建组
      3. 将用户分配到组
      4. 创建OIDC应用程序
      5. 创建授权服务器
      6. 将声明添加到授权服务器
      7. 将策略和规则添加到授权服务器
      8. 使用Terraform创建Okta配置
  4. 为OIDC准备群集
    1. 创建启用OIDC的群集
      1. kubeadm
      2. kOps
      3. k3d
    2. 正在更新现有群集以启用OIDC
  5. 配置RBAC
  6. 使用kubectl连接到集群
  7. 了解有关将OIDC与Kubernetes一起使用的更多信息


为什么要保护API服务器?


API服务器具有多层安全性。默认情况下,与API服务器的所有通信都使用TLS。身份验证使用服务帐户令牌、承载令牌、基本身份验证、代理或客户端证书来完成,具体取决于平台。在像Amazon EKS、AKS和GKE这样的PaaS的情况下,也可以使用自定义身份验证机制来完成。一旦对请求进行了身份验证,API服务器就可以使用几种授权机制中的一种来控制对资源的访问,如基于属性的访问控制(ABAC)或基于角色的存取控制(RBAC)。最后,还有可以被配置为控制资源修改的准入控制模块。

由于API服务器是Kubernetes集群中客户端可以访问的唯一部分,因此必须确保API服务器的安全。未经授权访问API服务器可能会导致整个群集被劫持,这也会让攻击者访问运行在其上的服务可访问的所有机密和数据。因此,正确配置用户和角色是确保群集安全的必要条件,尤其是在多个用户可以访问群集的组织中。

为什么选择OpenID Connect?


OpenIDConnect是建立在OAuth2.0之上的身份验证标准。它添加了一个称为ID令牌的附加令牌。OpenID Connect还标准化了OAuth 2.0可供选择的领域,如作用域、端点发现和客户端的动态注册。

虽然Kubernetes API服务器的默认身份验证机制对于简单的用例来说已经足够了,因为只有少数人管理集群,但它不能扩展到更大的组织。此外,默认方式肯定不是最安全的方式,因为Kubernetes不处理用户管理,而是希望在外部进行。这就是OpenID Connect(OIDC)的用武之地。OIDC可以管理用户和组,这与Kubernetes RBAC配合得很好,可以非常精细地控制谁可以访问集群内部的内容。

通过OIDC集成,您可以在现有基础设施中使用用于SSO的相同OIDC提供程序来访问Kubernetes集群,如Okta或Key斗篷。

使用Okta作为OIDC提供商来保护API服务器的安全


Okta提供云软件,帮助公司管理和保护应用程序中的用户身份验证,并使开发人员能够在应用程序、网站、web服务和设备中构建身份控制。Okta是经过认证的OpenID Connect提供商。

让我们看看如何使用Okta作为OIDC提供程序来保护Kubernetes API服务器,并使用RBAC从Okta管理控制台控制访问。如果您正在使用Amazon EKS,请查看本教程,了解如何将Okta OIDC与EKS一起使用。

您需要开始的内容


在尝试此操作之前,请确保您可以访问以下内容。

Okta账户。您可以注册一个免费的Okta帐户。或者,您可以使用另一个OIDC提供程序或Dex,步骤应该类似。
一个Kubernetes集群。我正在使用k3d来运行本地k3s集群。您可以使用任何Kubernetes发行版,包括托管的PaaS,如Amazon EKS、AKS和GKE等。
kubectl安装在您的机器上。
Terraform安装在您的机器上。如果您通过Okta管理控制台GUI进行Okta配置,则不需要执行此操作。
 

设置Okta OIDC应用程序和授权服务器


通过使用Okta CLI或管理控制台使用Okta创建一个简单的OIDC应用程序,可以实现集群的OIDC登录。但是,仅使用OIDC应用程序,就必须使用客户端机密从kubectl或任何其他客户端库进行身份验证。使用客户端机密进行身份验证不会扩展,也不会比默认的k8s身份验证机制更好,因为您无法对用户和角色进行细粒度控制。为了获得更有用的设置,我们需要一个OIDC应用程序和一个为Kubernetes定制声明和策略的授权服务器。这样,我们也可以使用Okta来管理用户和权限。

有多种方法可以在Okta中设置OIDC应用程序和授权服务器。如果您更喜欢通过GUI进行操作,请按照前面提到的文章**配置您的Okta组织**部分中的步骤,通过Okta管理控制台进行操作。

在本教程中,我们将使用Terraform来配置Okta部分,以便您可以重用代码进行任何所需的自动化。让我们深入了解所需的每一步。

设置Terraform


您可以在这个GitHub repo中找到本文的完整Terraform源代码

首先,我们需要配置Okta Terraform提供程序。创建一个新的Terraform文件,比如okta.main.tf,并添加以下内容:

variable "base_url" {
 description = "The Okta base URL. Example: okta.com, oktapreview.com, etc. This is the domain part of your Okta org URL"
}
variable "org_name" {
 description = "The Okta org name. This is the part before the domain in your Okta org URL"
}
variable "api_token" {
 type        = string
 description = "The Okta API token, this will be read from environment variable (TF_VAR_api_token) for security"
 sensitive   = true
}
# Enable and configure the Okta provider
terraform {
 required_providers {
   okta = {
     source  = "okta/okta"
     version = "~> 3.15"
   }
 }
}
provider "okta" {
 org_name  = var.org_name
 base_url  = var.base_url
 api_token = var.api_token
}


您需要提供输入变量org_name、base_url和api_token。在名为okta.config.auto.tfvars的文件中更新这些值。名称中的.auto很重要;否则,Terraform将不会自动拾取它。例如,如果您的Okta实例的地址是dev-1234.Okta.com,那么您的组织名称将是dev-1234,base_url将是组织名称(例如Okta.com)之后的所有内容。

接下来,您将需要生成api_token值。以超级用户身份登录Okta管理员控制台,然后从导航菜单中选择安全>API>令牌(选项卡)。接下来,单击Create Token按钮,为您的令牌命名,单击Create Token,然后复制新生成的令牌。将其保存在从Git中排除的单独secret.auto.tfvars文件中,或保存在名为TF_VAR_api_token的环境变量中。

Okta提供程序现在已配置并准备就绪。

创建组


现在,我们需要一些组来区分和映射想要访问我们集群的不同类型的用户。假设我们有一组对集群具有完全访问权限的管理员和另一组访问权限有限的用户。根据您的需要,您可以有任意数量的组。下面的配置将创建两个组。该组的权限将使用集群上的Kubernetes RBAC策略来定义,我们稍后会这样做。

# Set up OKTA groups
resource "okta_group" "k8s_admin" {
 name        = "k8s-admins"
 description = "Users who can access k8s cluster as admins"
}
resource "okta_group" "k8s_restricted_users" {
 name        = "k8s-restricted-users"
 description = "Users who can only view pods and services in default namespace"
}


将用户分配到组


下面的代码段查找现有用户并将他们添加到组中。在此阶段,您可以添加任意数量的用户,也可以跳过添加用户,稍后通过Okta管理控制台进行添加。在本练习中,我将获取现有用户。您还可以使用okta_user资源创建新用户。

# Assign users to the groups
data "okta_user" "admin" {
 search {
   name  = "profile.email"
   value = "<your_admin_user_email>"
 }
}
resource "okta_group_memberships" "admin_user" {
 group_id = okta_group.k8s_admin.id
 users = [
   data.okta_user.admin.id
 ]
}
data "okta_user" "restricted_user" {
 search {
   name  = "profile.email"
   value = "<another_user_email>"
 }
}
resource "okta_group_memberships" "restricted_user" {
 group_id = okta_group.k8s_restricted_users.id
 users = [
   data.okta_user.restricted_user.id
 ]
}


创建OIDC应用程序

现在我们的小组已经就位,让我们创建一个OIDC应用程序。我们将应用程序类型设置为本机,并使用PKCE作为客户端身份验证,这比使用客户端机密要安全得多。我们还将重定向URI设置为localhost:8000,以便在本地使用kubectl。我们还应该在此处将之前创建的组分配给此应用程序。最后,我们可以使用输出变量捕获创建的应用程序的客户端ID。

# Create an OIDC application
resource "okta_app_oauth" "k8s_oidc" {
 label                      = "k8s OIDC"
 type                       = "native" # this is important
 token_endpoint_auth_method = "none"   # this sets the client authentication to PKCE
 grant_types = [
   "authorization_code"
 ]
 response_types = ["code"]
 redirect_uris = [
   "http://localhost:8000",
 ]
 post_logout_redirect_uris = [
   "http://localhost:8000",
 ]
 lifecycle {
   ignore_changes = [groups]
 }
}
# Assign groups to the OIDC application
resource "okta_app_group_assignments" "k8s_oidc_group" {
 app_id = okta_app_oauth.k8s_oidc.id
 group {
   id = okta_group.k8s_admin.id
 }
 group {
   id = okta_group.k8s_restricted_users.id
 }
}
output "k8s_oidc_client_id" {
 value = okta_app_oauth.k8s_oidc.client_id
}


创建授权服务器


接下来,我们需要一个授权服务器,以便定义策略和声明。我们还将在输出变量中捕获颁发者URL。

# Create an authorization server
resource "okta_auth_server" "oidc_auth_server" {
 name      = "k8s-auth"
 audiences = ["http:://localhost:8000"]
}
output "k8s_oidc_issuer_url" {
 value = okta_auth_server.oidc_auth_server.issuer
}


将声明添加到授权服务器


让我们向授权服务器添加一个声明,以便在用户进行身份验证时在id_token中添加用户组。我们需要在Kubernetes端执行RBAC。另外,请注意,我们只是在声明中添加前缀为k8s-的组。这是为了避免添加与Kubernetes无关的组。

# Add claims to the authorization server
resource "okta_auth_server_claim" "auth_claim" {
 name                    = "groups"
 auth_server_id          = okta_auth_server.oidc_auth_server.id
 always_include_in_token = true
 claim_type              = "IDENTITY"
 group_filter_type       = "STARTS_WITH"
 value                   = "k8s-"
 value_type              = "GROUPS"
}


将策略和规则添加到授权服务器


现在我们需要为授权服务器创建策略和规则。下面的策略定义了它将被分配给哪些OIDC应用程序。然后我们为该策略创建一个规则,该规则将定义PKCE令牌的生存期和刷新间隔。为此,我们将保留默认值,即1小时的使用寿命和无限的刷新间隔,但您可以根据需要更改它们。

# Add policy and rules to the authorization server
resource "okta_auth_server_policy" "auth_policy" {
 name             = "k8s_policy"
 auth_server_id   = okta_auth_server.oidc_auth_server.id
 description      = "Policy for allowed clients"
 priority         = 1
 client_whitelist = [okta_app_oauth.k8s_oidc.id]
}
resource "okta_auth_server_policy_rule" "auth_policy_rule" {
 name           = "AuthCode + PKCE"
 auth_server_id = okta_auth_server.oidc_auth_server.id
 policy_id      = okta_auth_server_policy.auth_policy.id
 priority       = 1
 grant_type_whitelist = [
   "authorization_code"
 ]
 scope_whitelist = ["*"]
 group_whitelist = ["EVERYONE"]
}


使用Terraform创建Okta配置


现在Terraform代码已经准备好了,让我们应用它。首先,运行Terraform计划来查看将要进行的更改。验证计划提出的更改是否对要修改的资源进行了所需的更改。然后运行terraform apply并键入yes以应用更改。您应该看到类似的输出。您也可以登录Okta管理控制台以验证更改。

复制输出值,因为我们将在下一步中需要它们。

okta_group.k8s_admin: Creating...
okta_group.k8s_restricted_users: Creating...
okta_auth_server.oidc_auth_server: Creating...
okta_app_oauth.k8s_oidc: Creating...
okta_group.k8s_admin: Creation complete after 0s [id=00g2b0rmupxo1C1HW5d7]
okta_group.k8s_restricted_users: Creation complete after 0s [id=00g2b0q4zejpq6hbi5d7]
okta_group_memberships.restricted_user: Creating...
okta_group_memberships.admin_user: Creating...
okta_auth_server.oidc_auth_server: Creation complete after 1s [id=aus2b0ql0ihgilIh95d7]
okta_auth_server_claim.auth_claim: Creating...
okta_group_memberships.admin_user: Creation complete after 1s [id=00g2b0rmupxo1C1HW5d7]
okta_group_memberships.restricted_user: Creation complete after 1s [id=00g2b0q4zejpq6hbi5d7]
okta_app_oauth.k8s_oidc: Creation complete after 1s [id=0oa2b0qc0x38Xjxbk5d7]
okta_app_group_assignments.k8s_oidc_group: Creating...
okta_auth_server_policy.auth_policy: Creating...
okta_auth_server_claim.auth_claim: Creation complete after 0s [id=ocl2b0rc6ejmIO4KR5d7]
okta_app_group_assignments.k8s_oidc_group: Creation complete after 1s [id=0oa2b0qc0x38Xjxbk5d7]
okta_auth_server_policy.auth_policy: Creation complete after 1s [id=00p2b0qjjxsSz0Mya5d7]
okta_auth_server_policy_rule.auth_policy_rule: Creating...
okta_auth_server_policy_rule.auth_policy_rule: Creation complete after 1s [id=0pr2b0rgnfxjyu6cy5d7]
Apply complete! Resources: 10 added, 0 changed, 0 destroyed.
Outputs:
k8s_oidc_client_id = "0oa2b0qc0x38Xjxbk5d7"
k8s_oidc_issuer_url = "https://dev-xxxxxx.okta.com/oauth2/aus2b0ql0ihgilIh95d7"


如果需要,您可以运行地形破坏来恢复更改。

提示:您可以使用terraform import<resource_name.id>命令从Okta实例导入数据和配置。有关更多信息,请参阅这些Okta Terraform提供商文档。

为OIDC准备群集


现在,我们需要为集群与OIDC合作做好准备。为此,我们需要更新以下API服务器标志:

  • oidc颁发者url:这将是Okta授权服务器上的颁发者url
  • oidc客户端id:这是Okta oidc应用程序的客户端id
  • oidc用户名声明:这是将用于识别用户的声明。在这种情况下,它是电子邮件。
  • oidc组声明:这是将用于识别组的声明。在这种情况下,它是组。
  • oidc-ca文件:这是用于验证oidc服务器的ca文件。如果您使用Okta作为OIDC提供商,则无需设置此项。


注意:如果您遇到OIDC组/用户与Kubernetes组/用户冲突的问题,您也可以设置OIDC组前缀和OIDC用户名前缀标志。

可以在创建集群时设置标志,也可以通过SSH修补API服务器来设置标志,如下所述。

创建启用OIDC的群集


以下是如何使用不同的工具创建启用OIDC的新k8s集群。执行您正在使用的工具的命令。请确保将<k8s_oidc_issuer_url>和<k8s_oidc_client_id>替换为Terraform步骤输出的值。对于任何其他工具,请参阅它们关于如何更新API服务器标志的文档。

kubeadm


如果您正在使用kubeadm,请将以下标志添加到集群配置中,并将它们传递给kubeadminit命令。

apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
apiServer:
  extraArgs:
    oidc-issuer-url: <k8s_oidc_issuer_url>
    oidc-client-id: <k8s_oidc_client_id>
    oidc-username-claim: email
    oidc-groups-claim: groups


kOps


对于kOps,使用所需的配置创建一个集群。例如,下面的代码将在AWS中创建一个集群。

kops create cluster \
--authorization RBAC \
--name $CLUSTER_NAME \
--cloud aws \
--state $S3_STATE_STORE


现在编辑集群配置并添加OIDC数据。

kops edit cluster $CLUSTER_NAME --state $S3_STATE_STORE


将此YAML添加到kubeAPIServer规范中。


kubeAPIServer:
 authorizationRbacSuperUser: admin
 oidcIssuerURL: <k8s_oidc_issuer_url>
 oidcClientID: <k8s_oidc_client_id>
 oidcUsernameClaim: email
 oidcGroupsClaim: groups


k3d


要使用k3d创建k3s集群,请运行以下命令。

# k3d v5.0.0+
k3d cluster create $CLUSTER_NAME \
--k3s-arg "--kube-apiserver-arg=oidc-issuer-url=<k8s_oidc_issuer_url>@server:0" \
--k3s-arg "--kube-apiserver-arg=oidc-client-id=<k8s_oidc_client_id>@server:0" \
--k3s-arg "--kube-apiserver-arg=oidc-username-claim=email@server:0" \
--k3s-arg "--kube-apiserver-arg=oidc-groups-claim=groups@server:0"


正在更新现有群集以启用OIDC


如果您已经有一个现有的集群,您可以使用root用户通过SSH连接到它,并使用以下命令修补API服务器。

ssh root@master-node-ip
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
...
   command:
   - /hyperkube
   - apiserver
   - --advertise-address=x.x.x.x
...
   - --oidc-issuer-url=<k8s_oidc_issuer_url> # <-- 🔴 update this
   - --oidc-client-id=<k8s_oidc_client_id> # <-- 🔴 update this
   - --oidc-username-claim=email # <-- 🔴 update this
   - --oidc-groups-claim=groups # <-- 🔴 update this
...


如果您使用的是像EKS或GKE这样的托管服务,请按照它们的说明更新API服务器。

配置RBAC


基于角色的访问控制允许您控制谁可以访问集群内部的内容。这是一个非常强大的功能,可用于控制对特定资源的访问。使用OIDC的好处在于,我们可以将其与RBAC一起使用,以实现对资源的细粒度控制。

大多数Kubernetes发行版默认启用了RBAC。如果没有,请确保在继续操作之前启用它。在创建或修补集群时,可以使用API服务器的--authorization-mode标志来设置它。例如,--authorization mode=RBAC,anotherMethod。

在这个练习中,我们将使用我们在Okta中创建的两个组。在集群级别,我们将管理员访问权限限制在将通过OIDC提供商(在本例中为Okta)控制的特定组。

让我们通过kubectl应用下面的YAML来创建集群角色绑定。这绑定到称为集群管理员的内置集群角色,并限制Okta中k8s管理员组中的用户访问。现在,添加到组中的任何用户都将有权访问集群,从组中删除某人就足以删除他们的访问权限。

kubectl apply -f - <<EOF
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: oidc-cluster-admin
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: ClusterRole
 name: cluster-admin
subjects:
- kind: Group
 name: k8s-admins
EOF


在实际用例中,您可能希望进一步限制组对特定资源类型或命名空间的访问,添加具有不同权限的多个组,等等。有关不同的可能性,请参阅此部分。

现在,让我们创建一个k8s角色,该角色只能查看默认命名空间中的pod和服务。

kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
 namespace: default
 name: restricted-user
rules:
- apiGroups: [""] # "" indicates the core API group
 resources: ["pods", "services"]
 verbs: ["get", "watch", "list"]
EOF


现在我们可以将角色绑定到我们在Okta中创建的第二个组。

kubectl apply -f - <<EOF
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: oidc-cluster-user
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: Role
 name: restricted-user
subjects:
- kind: Group
 name: k8s-restricted-users
EOF


就是这样!集群现在已准备好执行某些OIDC操作。

使用kubectl连接到集群


在我们进行测试之前,我们需要对kubectl进行一些设置,以便它知道如何进行OIDC身份验证。我们需要为此安装kubelogin插件。继续使用以下任意命令进行安装。

# Homebrew (macOS and Linux)
brew install int128/kubelogin/kubelogin
# Krew (macOS, Linux, Windows and ARM)
kubectl krew install oidc-login



该插件为kubectl启用OIDC登录功能。让我们先测试一下。运行以下命令,确保将k8s_oidc_issuer_url和k8s_oidc_client_id替换为之前在Okta设置期间保存的内容。

kubectl oidc-login setup --oidc-issuer-url=<k8s_oidc_issuer_url> --oidc-client-id=<k8s_oidc_client_id>


这应该会产生如下输出:

authentication in progress...
Opening in existing browser session.
## 2. Verify authentication
You got a token with the following claims:
{
 "sub": "00u28lpcoheT48W5A5d7",
 "ver": 1,
 "iss": "<k8s_oidc_issuer_url>",
 "aud": "<k8s_oidc_client_id>",
 "iat": 1634657188,
 "exp": 1634660788,
 "jti": "ID.AmO7M7Z4xh_rSN4IHVuQEfJ4QuoADOWHSrVHuNyn9so",
 "amr": [
   "pwd"
 ],
 "idp": "0oa28lrldhsBglcC35d7",
 "nonce": "2Rsv7E84vo_K14J6qm9IgKjNsCUxb4Hc16qgzx9CKlk",
 "auth_time": 1634649927,
 "at_hash": "veXQkvqTjCl70OkZnKZVyA",
 "groups": [
   "k8s-admins"
 ]
}

现在让我们更新kubectl配置以添加OIDC用户:

kubectl config set-credentials oidc-user \
--exec-api-version=client.authentication.k8s.io/v1beta1 \
--exec-command=kubectl \
--exec-arg=oidc-login \
--exec-arg=get-token \
--exec-arg=--oidc-issuer-url=<k8s_oidc_issuer_url> \
--exec-arg=--oidc-client-id=<k8s_oidc_client_id> \
--exec-arg=--oidc-extra-scope="email offline_access profile openid"


现在我们可以使用这个用户通过kubectl向集群进行身份验证。

kubectl get pods --user=oidc-user -n default


这应该会打开一个浏览器窗口来验证您的身份。您可以使用您的Okta帐户凭据登录。

通过与不同组中的不同用户一起玩来测试这种RBAC配置。不在Okta的k8s管理员组中的用户应该无法访问任何资源。仅在受限用户组中的用户应该只能看到pod和服务。

您可以使用以下命令将该用户设置为当前kubectl上下文的默认用户。

kubectl config set-context --current --user=oidc-user


了解有关将OIDC与Kubernetes一起使用的更多信息


使用OIDC是保护Kubernetes集群安全的好方法,尤其是在更大的团队中。它比任何默认的Kubernetes身份验证机制都更安全。除此之外,它还允许您管理集群中的用户及其角色和权限,甚至为集群添加多因素身份验证。

虽然本练习向您展示了Okta的实现,但其他OIDC提供商的过程将非常相似。查看Okta Terraform提供商文档,了解通过Terraform还可以实现哪些自动化。您还可以使用Kubernetes terraform提供程序,通过terraform实现Kubernete部件的自动化。

如果您想了解更多关于Kubernetes、OIDC或将OIDC与Kubernete一起使用的信息,请查看这些额外的资源。


你可以在GitHub上找到本教程的代码https://github.com/oktadev/okta-k8s-oidc-terraform-example.

 

本文地址
最后修改
星期三, June 5, 2024 - 18:46
Article