NGINX.COM
Web Server Load Balancing with NGINX Plus

在如今勒索软件和机器人攻击如此常见的大环境下,保护应用和 API 变得至关重要 —— 我们已多次撰文强调这一点。除了 Web 应用防火墙(WAF)等机制之外,验证用户身份和实施授权控制也是业务应用防护的重要方式。

在应用中进行身份验证和授权是最直接的办法。但这种方法只适用于用户群较小且不需要频繁更新的应用,反之就行不通了。首先,由于每个应用都有不同的账户名和密码,他们在登录时经常会遇到“用户名或密码不正确”的问题,为了好记,他们会采用不安全的解决方案,例如容易被猜到的 “abc123” 密码。此外,我们都见过显示器上贴着密码提示便利贴的情形!

单点登录 (SSO) 技术利用一组凭证消除了单独设置各种用户名和密码的需要,从而在一定程度上解决了这些问题。借助身份提供商 (IdP),用户只需登录一次即可访问许多应用。但开发人员仍必须在应用中写入代码以便与 SSO 系统交互,这项工作非常具有挑战性,特别是在应用变得日益复杂的情况下。

随着企业规模不断扩大,要想满足不断增长的用户群的要求,将那些非应用本身特定需要的功能(例如身份验证和授权)从应用层卸载下来就变得至关重要。在 Kubernetes 中,Ingress controller 是进行集中式身份验证和授权的理想位置,因为它可以检查进入 Kubernetes 集群的所有流量,并将其路由到相应的服务。开发人员不仅可以摆脱构建、维护和复制身份验证逻辑的麻烦,而且还可以使用原生 Kubernetes API 即可在入口层轻松使用 SSO 技术。

本文将展示如何使用基于 NGINX Plus 的 NGINX Ingress Controller 实现完整的 SSO 解决方案。其中 NGINX Ingress Controller 可以作为中继方运行,利用 Okta(作为预配置身份提供商 (IdP))为 OIDC 授权代码流提供支持。

注:基于 NGINX 开源版的 NGINX Ingress Controller 不提供此功能。

前提条件

本文假设您拥有 Kubernetes 环境操作经验。此外,您还需要:

  • Kubernetes 环境 —— NGINX Ingress Controller 适用于 Vanilla Kubernetes 以及许多 Kubernetes 平台,包括 Amazon Elastic Kubernetes (EKS)、裸机、Google Kubernetes Engine (GKE)、Microsoft Azure Kubernetes Service (AKS)、Rancher Kubernetes Engine 及 Red Hat OpenShift。
  • 基于 NGINX Plus 的 NGINX Ingress Controller —— 必须拥有基于 NGINX Plus 版的 NGINX Ingress Controller 的有效许可。您可以先申请 30 天免费试用版许可。更多相关信息,请参阅我们的文档
  • Okta 开发者账号 —— 要将 Okta 配置为 IdP,请先注册一个开发者账号。作为替代方案,您也可以下载 Okta 命令行接口(CLI)并运行 okta register 命令,注册一个新账户。在撰写本文时,Okta CLI 尚处于测试阶段,因此不建议在生产环境中使用。

预配置 IdP

云服务必须清楚在哪里检索和验证用户身份,这就需要使用 IdP。IdP 能够安全地管理和存储数字身份,并确保攻击者无法窃取用户身份并冒充用户。

在本节中,我们使用 Okta CLI 将 Okta 预配置为 IdP,创建 Okta 中所说的 应用集成

  1. 运行 okta login 命令,验证 Okta 开发者账号的 Okta CLI。根据提示输入 Okta 域名和 API 令牌

    $ okta login 
    Okta Org URL: https://your-okta-domain
    Okta API token: your-api-token
  2. 创建应用集成:

    $ okta apps create --app-name=mywebapp --redirect-uri=http[s]://ingress-controller-hostname/_codexch

    其中,

    • --app-name 定义应用名称(此处为 mywebapp
    • --redirect-uri 定义将登录行为重定向到了哪个 URI(此处为 ingress-controller-hostname/_codexch)
  3. 指定响应提示的应用类型,首先用 1(表示一个 Web 应用),然后用 5(表示一个与列出的框架不同的框架)。

    Type of Application
    (The Okta CLI only supports a subset of application types and properties):
    > 1: Web
    > 2: Single Page App
    > 3: Native App (mobile)
    > 4: Service (Machine-to-Machine)
    Enter your choice [Web]: 1
    Type of Application
    > 1: Okta Spring Boot Starter
    > 2: Spring Boot
    > 3: JHipster
    > 4: Quarkus
    > 5: Other
    Enter your choice [Other]: 5
    Configuring a new OIDC Application, almost done:
    Created OIDC application, client-id: 0oa1mi...OrfQAg5d7

配置 NGINX Ingress Controller

将基于 NGINX Plus 的 NGINX Ingress Controller 配置为验证用户身份的中继方。

定义客户端凭证密钥

出于安全原因,系统不支持对 OIDC 策略对象中的客户端密码进行硬编码。因而,我们创建了一个 Kubernetes Secret 对象,其中包含客户机密的 base64 编码值的数据。

apiVersion: v1
kind: Secret
metadata:
  name: oidc-secret
type: nginx.org/oidc
data:
  client-secret: base64-encoded-value-of-client-secret 

然后应用包含 Secret 对象的 YAML 文件(此处为 client-secret.yaml):

$ kubectl apply –f client-secret.yaml

获取身份验证端点

使用 OAuth 2.0OpenID Connect API 获取有关 Okta 在其授权服务器上公开的端点的信息。

在本地设备上运行以下命令,以输出有关 Okta 端点的信息。注意输出示例中显示的 authorization_endpointtoken_endpointjwks_uri 的值。您在下一节中需要使用这些值。

$ curl -i https://your-okta-domain/.well-known/openid-configuration
{
    "authorization_endpoint": "https://your-okta-domain/oauth2/v1/authorize",
    ...
    "jwks_uri": "https://your-okta-domain/oauth2/v1/keys",
    ...
    "token_endpoint": "https://your-okta-domain/oauth2/v1/token",
 ...
 }

定义 NGINX Ingress OIDC 策略

NGINX Ingress Controller 1.10.0 中添加了对基于 OIDC 的身份验证的支持。

NGINX Ingress Controller 实现的 OIDC 身份验证的使用的是一个 Policy 对象,它是一个 Kubernetes 自定义资源,在 NGINX Ingress Controller 中定义了 OIDC 策略。

  1. 将上一节中获得的信息插入 Policy 对象的 authEndpointtokenEndpointjwksURI 字段。

    apiVersion: k8s.nginx.org/v1
    kind: Policy
    metadata:
      name: oidc-policy
    spec:
      oidc:
        clientID: client-id
        clientSecret: oidc-secret
        authEndpoint: https://your-okta-domain/oauth2/v1/authorize
        tokenEndpoint: https://your-okta-domain/oauth2/v1/token
        jwksURI: https://your-okta-domain/oauth2/v1/keys
  2. 应用策略(此处在 oidc.yaml 中进行定义):

    $ kubectl apply -f oidc.yaml
  3. (可选)检查策略的有效性:

    $ kubectl get policy 
    
    NAME          STATE   AGE
    oidc-policy   Valid   2m

定义 VirtualServer 对象

VirtualServer 和 VirtualServerRoute 是 NGINX Ingress 资源,它们制定了将入向流量路由到 Kubernetes 集群中后端应用的规则。必须在 VirtualServer 或 VirtualServerRoute 资源中引用 OIDC 策略才能使其生效。

  1. / 路径前缀下引用 OIDC 策略,以便在将请求代理到 app-server-payload 服务之前,对请求匹配该前缀的路径的用户进行身份验证。

    apiVersion: k8s.nginx.org/v1
    kind: VirtualServer
    metadata:
      name: app-ingress
    spec:
      host: unit-demo.linkpc.net
      upstreams:
      - name: app-server-payload
        service: app-server-svc
        port: 80
      routes:
      - path: /
        policies:
        - name: oidc-policy
        action:
          proxy: 
            upstream: app-server-payload
  2. 应用 VirtualServer 资源(此处在 app-virtual-server.yaml 中进行定义):

    $ kubectl apply -f app-virtual-server.yaml
  3. (可选)验证资源的有效性:

    $ kubectl get vs
    
    NAME          STATE   HOST                   IP    PORTS   AGE
    app-ingress   Valid   unit-demo.linkpc.net                 2m

测试环境

要测试 OIDC Okta 集成能否正常工作,请在浏览器的地址栏中输入 NGINX Ingress Controller 的主机名。您将被重定向到 Okta 登录门户,您可在该门户上输入 Okta 开发者账号的凭证以访问后端应用。

一旦通过身份验证,即可访问 app-server-payload 上游服务。

将用户添加到应用

在大多数情况下,企业的多个用户都需要访问应用。在 Okta 管理员控制台目录(Directory)类别下的人员(People)页面上添加每个用户。

为 SSO 创建多个应用集成

我们使用 Okta(作为 IdP)和 NGINX Ingress Controller(作为中继方)配置 SSO,从而卸载一个应用的身份验证流程。在实践中,您可能希望用户能够使用一组凭证访问多个应用。您可能还希望能够灵活地改变用户可以访问的应用。

您可以通过 集成 Okta 与其他应用定义其他 OIDC 策略并在 VirtualServer 资源中引用这些策略来实现这一点。在下图描述的示例中,有两个子域名:unit-demo.marketing.netunit-demo.engineering.net,它们解析为 NGINX Ingress Controller 的外部 IP 地址。NGINX Ingress Controller 根据子域名将请求路由到 营销(Marketing) 应用或 工程(Engineering)应用。如要授予用户访问权限,请在 Okta GUI 的 分配(Assignments) 选项卡上,将用户与每个适当的应用相关联。然后,Okta 向通过身份验证的用户颁发一个短暂的会话 cookie,以支持他们访问这些应用。

结语

通过将 NGINX Ingress Controller 配置为中继方,将 Okta 配置为 IdP,您可以在 Kubernetes 中实现基于 OIDC 的 SSO,并消除开发人员的身份验证和授权负担,让他们专注于优化应用中的业务逻辑。如欲试用基于 NGINX Plus 的 Ingress Controller,请立即申请 30 天免费试用版与我们联系以讨论您的用例

Hero image
Kubernetes:
从测试到生产

通过多种流量管理工具提升弹性、可视性和安全性

关于作者

Amir Rawdat

解决方案工程师

Amir Rawdat 是 NGINX 的技术营销工程师,专门负责各种技术内容的撰写。他在计算机网络、计算机编程、故障排除和内容撰写方面拥有深厚的背景。此前,Amir 是诺基亚(Nokia)的客户应用工程师。

关于 F5 NGINX

F5, Inc. 是备受欢迎的开源软件 NGINX 背后的商业公司。我们为现代应用的开发和交付提供一整套技术。我们的联合解决方案弥合了 NetOps 和 DevOps 之间的横沟,提供从代码到用户的多云应用服务。访问 nginx-cn.net 了解更多相关信息。