注意:

使用 Nginx 入站控制器、OAuth2 代理和 Oracle 身份域保护 Kubernetes Web 服务

简介

保护 Kubernetes 托管的 Web 服务应该很容易。无论您的应用缺乏对外部身份提供者 (IdP) 集成的内置支持,还是需要单点登录 (SSO) 解决方案来简化管理并减少对每个服务使用单个身份验证机制的需求,OAuth2 代理都可以灵活地将任何应用连接到几乎任何身份提供者 (IdP)。

OAuth2 代理充当位于 Kubernetes 服务前面的反向代理。它拦截流量,将用户重定向到外部授权服务器(如 Okta 或 GitHub)进行登录,并在将请求转发到后端服务之前验证访问令牌。

目标

先决条件

任务 1:创建 OKE 集群

  1. 登录到 OCI 控制台,导航到 Oracle Container Engine for Kubernetes ,然后单击创建

  2. 创建集群向导中,单击快速创建

    快速创建

  3. 输入以下信息,然后单击下一步

    • 名称:输入群集名称。
    • Kubernetes 版本:选择要使用的版本。
    • Kubernetes API 端点:选择公共端点
    • 节点类型:选择托管
    • Kubernetes worker 节点:选择专用 worker
    • 节点计数: 1

    创建集群

  4. 复查并单击创建集群。等待集群变为可用。

  5. 更新与服务子网关联的安全列表。

    1. 单击服务子网

      服务子网

    2. 单击安全列表并添加以下规则。

      • 入站:

        安全列表入站规则

      • 出站:

        安全列表出站规则

  6. 更新与 worker 节点子网关联的安全列表,以允许来自负载平衡器的连接。

    1. 单击 VCN 名称。

      OKE 集群 VCN

    2. 资源下,选择安全列表并单击节点安全列表。

      安全列表

    3. 将以下入站规则添加到节点安全列表中。

      节点安全列表入站

    4. 单击添加入站规则

任务 2:设置 Nginx 入站控制器

  1. 集群可用后,您可以使用 OCI Cloud Shell 访问集群。单击访问集群,然后在 OCI Cloud Shell 中复制并运行以下命令。

    访问集群

  2. 运行 kubectl get node 命令以获取可用节点的列表。

    获取节点

  3. 添加 Nginx 入站控制器 helm 系统信息库。有关更多信息,请参见 Overview of Ingress NGINX Controllerhelm

    helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
    helm repo update
    
  4. 创建 values-override.yaml 文件。

    controller:
      allowSnippetAnnotations: true
      service:
        annotations:
          oci.oraclecloud.com/load-balancer-type: "lb"
          service.beta.kubernetes.io/oci-load-balancer-backend-protocol: "TCP"
          service.beta.kubernetes.io/oci-load-balancer-shape: "flexible"
          service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: "10"
          service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: "10"
    
  5. 部署 Nginx 入站控制器。

    helm install ingress-nginx ingress-nginx/ingress-nginx -f values-override.yaml
    
  6. 保存名为 application.yaml 的以下 yaml 文件。

    ---
    # Create ClusterIP service
    apiVersion: v1
    kind: Service
    metadata:
      name: httpbin
      labels:
        app: httpbin
    spec:
      ports:
      - port: 5000
        targetPort: 5000
      selector:
        app: httpbin
    ---
    # Deployment of a sample web application
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: httpbin
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: httpbin
          version: v1
      template:
        metadata:
          labels:
            app: httpbin
            version: v1
        spec:
          containers:
          - image: mendhak/http-https-echo
            imagePullPolicy: IfNotPresent
            name: httpbin
            ports:
            - containerPort: 5000
            env:
            - name: HTTP_PORT
              value: "5000"
    
  7. 创建应用程序资源。

    kubectl apply -f application.yaml
    
  8. 为与负载平衡器关联的公共 IP 地址创建 DNS 记录。

    • 获取负载平衡器的公共 IP 地址。

      $ kubectl get svc ingress-nginx-controller
      NAME                       TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)                      AGE
      ingress-nginx-controller   LoadBalancer   10.96.152.30   158.180.61.74   80:31957/TCP,443:30838/TCP   32s
      
    • 创建 DNS 记录。如果您没有 DNS 服务器,我们将使用免费的通配符 DNS 服务 nip.io

    在这种情况下, FQDN158-180-61-74.nip.io

  9. 保存名为 ingress.yaml 的以下 yaml 文件。

    注:请确保使用您的 FQDN 更新主机条目。

    ---
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: httpbin-ingress-nginx
    spec:
      ingressClassName: nginx
      tls:
      - hosts:
          - "<YOUR-FQDN>"
      rules:
        - host: "<YOUR-FQDN>"
          http:
            paths:
              - pathType: Prefix
                path: "/"
                backend:
                  service:
                    name: httpbin
                    port:
                      number: 5000
    
  10. 运行以下命令以创建入站资源。

    kubectl apply -f ingress.yaml
    
  11. 测试与服务的连接。

    $ curl -k https://<YOUR-FQDN> 
    {
      "path": "/",
      "headers": {
        "host": "158-180-61-74.nip.io",
        "x-request-id": "b0320217391a922acecbfe10758b3ffe",
        "x-real-ip": "10.0.10.167",
        "x-forwarded-for": "10.0.10.167",
        "x-forwarded-host": "158-180-61-74.nip.io",
        "x-forwarded-port": "443",
        "x-forwarded-proto": "https",
        "x-forwarded-scheme": "https",
        "x-scheme": "https",
        "user-agent": "curl/7.87.0",
        "accept": "*/*"
      },
      "method": "GET",
      "body": "",
      "fresh": false,
      "hostname": "158-180-61-74.nip.io",
      "ip": "10.0.10.167",
      "ips": [
        "10.0.10.167"
      ],
      "protocol": "https",
      "query": {},
      "subdomains": [
        "158-180-61-74"
      ],
      "xhr": false,
      "os": {
        "hostname": "httpbin-644874bcdb-ll4mb"
      },
      "connection": {}
    }
    

任务 3:在 Oracle 身份域中设置机密应用程序

  1. 在 OCI 控制台中导航到 Oracle Identity Domains ,然后单击 OracleIdentityCloudService 域。

  2. 从左侧菜单中选择 Integrated Applications ,然后单击 Add application(添加应用程序)

  3. 选择 Confidential Application(机密应用程序),然后单击 Launch workflow(启动工作流)

    新建机密应用程序

  4. 输入应用程序的名称说明,然后单击下一步

    应用程序详细资料

  5. 配置应用程序 oAuth 参数。

    1. Authorization(授权)部分中,选择 Authorization code(授权代码)

    2. 输入以下 URL 并单击下一步

      • 重定向 URL:https://<YOUR-FQDN>/oauth2/callback
      • 注销后重定向 URL:https://<YOUR-FQDN>
      • 注销 URL:https://<YOUR-FQDN>/oauth2/sign_out

    应用程序 oauth 参数

  6. Web 层策略中,选择跳过并稍后执行,然后单击完成

    Web-tier-policy

  7. 单击激活启用应用程序。

    激活应用程序

  8. 导航到左侧菜单中的,并将允许验证的用户组与此应用程序关联。

    将用户组与应用程序关联

  9. 记录客户端 ID客户端密钥

    应用程序客户端 ID 和密钥

  10. 单击 OracleIdentityCloudService 域并展开域 URL

    身份域 URL

    例如:身份域 URL 将为 https://idcs-01234567890abcdef.identity.oraclecloud.com(我们删除端口号)。

任务 4:部署 OAuth2 代理

我们使用 OAuth2 代理来处理 OAuth2 或 OpenID Connect (OIDC) 的复杂性,并确保转发给应用程序的所有请求都经过验证。

  1. 保存名为 oauth2-proxy.yaml 的以下 yaml 文件,并将占位符替换为适用值。

    注:

    • <Identity Domain URL>: https://idcs-01234567890abcdef.identity.oraclecloud.com/

    • <Identity Domain FQDN>: idcs-01234567890abcdef.identity.oraclecloud.com

    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        k8s-app: oauth2-proxy
      name: oauth2-proxy
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: oauth2-proxy
      template:
        metadata:
          labels:
            k8s-app: oauth2-proxy
        spec:
          containers:
          - args:
            - --provider=oidc
            - --provider-display-name="Oracle Identity Domains"
            - --oidc-issuer-url=<Identity Domain URL>
            - --redirect-url=https://<YOUR-FQDN>/oauth2/callback
            - --upstream=file:///dev/null
            - --http-address=0.0.0.0:4180
            - --email-domain=*
            - --set-xauthrequest=true
            - --session-cookie-minimal=true
            - --whitelist-domain=<Identity Domain FQDN>
            env:
            - name: OAUTH2_PROXY_CLIENT_ID
              value: "<APPLICATION_CLIENT_ID>"
            - name: OAUTH2_PROXY_CLIENT_SECRET
              value: "<APPLICATION_CLIENT_SECRET>"
            # docker run -ti --rm python:3-alpine python -c 'import secrets,base64; print(base64.b64encode(base64.b64encode(secrets.token_bytes(16))));'     
            - name: OAUTH2_PROXY_COOKIE_SECRET
              value: "<OUTPUT_OF_THE_ABOVE_DOCKER_COMMAND>"
            image: quay.io/oauth2-proxy/oauth2-proxy:latest
            imagePullPolicy: Always
            name: oauth2-proxy
            ports:
            - containerPort: 4180
              protocol: TCP
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        k8s-app: oauth2-proxy
      name: oauth2-proxy
    spec:
      ports:
      - name: http
        port: 4180
        protocol: TCP
        targetPort: 4180
      selector:
        k8s-app: oauth2-proxy
    ---
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: oauth2-proxy
      annotations:
        nginx.ingress.kubernetes.io/configuration-snippet: |
          set $xheader "";
          if ( $request_uri = "/oauth2/sign_out" ){
            set $xheader "https://<Identity Domain FQDN>/oauth2/v1/userlogout;
          }
          proxy_set_header X-Auth-Request-Redirect ${xheader};
    spec:
      ingressClassName: nginx
      rules:
      - host: <YOUR-FQDN>
        http:
          paths:
          - path: /oauth2
            pathType: Prefix
            backend:
              service:
                name: oauth2-proxy
                port:
                  number: 4180
      tls:
      - hosts:
        - <YOUR-FQDN>
    
  2. 将 OAuth2 代理部署到 OKE。

    kubectl apply -f oauth2-proxy.yaml
    

    确认 pod 正在运行。

    kubectl get pods -l k8s-app=oauth2-proxy
    
  3. 配置 Nginx 以使用 OAuth2 代理进行请求验证。

    使用授权注释更新 ingress.yaml 文件。

    ---
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: httpbin-ingress-nginx
      annotations:
        nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
        nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
        nginx.ingress.kubernetes.io/auth-response-headers: "x-auth-request-user, x-auth-request-email"
    spec:
      ingressClassName: nginx
      tls:
      - hosts:
          - "<YOUR-FQDN>"
      rules:
        - host: "<YOUR-FQDN>"
          http:
            paths:
              - pathType: Prefix
                path: "/"
                backend:
                  service:
                    name: httpbin
                    port:
                      number: 5000
    
  4. 尝试连接到您的应用程序。您应重定向到 Oracle 验证页。验证成功后,应将您重定向到您的应用程序。

    “验证”页面

    有两个标头用于标识已验证的用户。

    "x-auth-request-user": "xxxx@oracle.com"
    "x-auth-request-email": "xxxx@oracle.com"
    
  5. 要从应用程序注销,可以转到页面上的 /oauth2/sign_out

    https://<YOUR-FQDN>/oauth2/sign_out
    

    已知问题:注销后重定向不起作用。此处跟踪此问题:向 OIDC 提供程序的注销提供程序 URL 添加 id_token_hint 参数

任务 5:清除资源

  1. 运行以下命令以删除所有 Kubernetes 部署的资源。

    kubectl delete -f oauth2-proxy.yaml -f ingress.yaml -f application.yaml
    helm uninstall ingress-nginx
    
  2. 从 Oracle 身份域中删除应用程序。

  3. 删除 OKE 集群。

  4. 删除为 OKE 集群创建的 VCN。

    注:

    • 您需要等待 OKE 群集和节点池删除结束。

    • VCN 名称包含 OKE 集群的名称:oke-vcn-quick-<oke-cluster-name>-<random-string>

确认

更多学习资源

浏览 docs.oracle.com/learn 上的其他实验室,或者通过 Oracle Learning YouTube 频道访问更多免费学习内容。此外,请访问 education.oracle.com/learning-explorer 以成为 Oracle Learning Explorer。

有关产品文档,请访问 Oracle 帮助中心