ASM中集成Keycloak实现网格内应用单点登录

本文介绍如何使用自建的Keycloak作为IdP来提供身份服务,实现网格内应用的单点登录。网格内应用无需实现认证、鉴权逻辑,通过配置ASM的自定义授权服务,即可通过OIDC协议使用Keycloak完成单点登录。鉴权通过后,请求将携带Keycloak中的用户信息一同发往应用。

前提条件

相关概念

概念

说明

IdP

Identity Provider的缩写,身份提供商。例如,您可以通过账号+密码的形式来验证您的身份。当您使用支付宝账号登录优酷,这个场景中支付宝即为IdP。

OIDC

OIDC是OpenID Connect的简称,是一个基于OAuth 2.0协议的身份认证标准协议。更多信息,请参见OpenID Connect

Scope

OIDC中的概念,每一个IdP同时也保存了用户的各种信息,例如Email、个人资料等,这些分类被称为Scope。在通过IdP进行Authentication(登录操作)时,一些IdP会要求选择允许访问用户的哪些资料,每一个类别都对应一个Scope。

操作步骤

步骤一: 部署演示应用和Keycloak

  1. 参照下方YAML,使用kubectl apply -n default -f xxx.yaml命令,将Httpbin应用部署至ACK集群的default命名空间。

    展开查看YAML

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: httpbin
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: httpbin
      labels:
        app: httpbin
        service: httpbin
    spec:
      ports:
      - name: http
        port: 8000
        targetPort: 80
      selector:
        app: httpbin
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: httpbin
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: httpbin
          version: v1
      template:
        metadata:
          labels:
            app: httpbin
            version: v1
        spec:
          serviceAccountName: httpbin
          containers:
          - image: docker.io/kennethreitz/httpbin
            imagePullPolicy: IfNotPresent
            name: httpbin
            ports:
            - containerPort: 80
  2. 参照下方YAML,使用kubectl apply -n default -f xxx.yaml命令,将Keycloak应用部署至ACK集群的default命名空间。

    展开查看YAML

    apiVersion: v1
    kind: Service
    metadata:
      name: keycloak
      labels:
        app: keycloak
    spec:
      ports:
      - name: http
        port: 8080
        targetPort: 8080
      selector:
        app: keycloak
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: keycloak
      labels:
        app: keycloak
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: keycloak
      template:
        metadata:
          labels:
            app: keycloak
        spec:
          containers:
          - name: keycloak
            image: quay.io/keycloak/keycloak:latest
            args: ["start-dev"]
            env:
            - name: KEYCLOAK_ADMIN
              value: "admin"
            - name: KEYCLOAK_ADMIN_PASSWORD
              value: "admin"
            - name: KC_PROXY
              value: "edge"
            ports:
            - name: http
              containerPort: 8080
            readinessProbe:
              httpGet:
                path: /realms/master
                port: 8080

步骤二:将演示应用和Keycloak通过ASM网关暴露至公网

本文示例使用HTTPS(端口:443)访问演示应用,使用HTTP(端口:80)访问Keycloak控制台。

  1. 为HTTPS服务创建证书,命名为myexample-credential。更多内容,请参见通过ASM网关启用HTTPS安全服务

  2. 使用如下YAML在ASM集群创建网关规则和虚拟服务,将Keycloak露出在公网。

    1. 使用如下YAML,在ASM控制台配置网关规则至对应的ASM实例。具体操作,请参见管理网关规则

      展开查看YAML

      apiVersion: networking.istio.io/v1beta1
      kind: Gateway
      metadata:
        name: ingressgateway
        namespace: istio-system
      spec:
        selector:
          app: istio-ingressgateway //需要确认该selector和当前已存在的网关是匹配的。
        servers:
          - hosts:
              - '*'
            port:
              name: http-httpbin //使用HTTPS(443端口)访问示例应用。
              number: 443
              protocol: HTTPS
            tls:
              credentialName: myexample-credential
              mode: SIMPLE
          - hosts:
              - '*'
            port:
              name: keycloak //使用HTTP(80端口)访问keycloak控制台。
              number: 80
              protocol: HTTP
                                      
    2. 使用如下YAML,将如下虚拟服务应用到ASM实例。具体操作,请参见管理虚拟服务

      展开查看YAML

      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: ingressgateway-vs
        namespace: istio-system
      spec:
        gateways:
          - ingressgateway
        hosts:
          - '*'
        http:
          - match:
              - port: 80
            name: keycloak
            route:
              - destination:
                  host: keycloak.default.svc.cluster.local
                  port:
                    number: 8080
          - name: httpbin
            route:
              - destination:
                  host: httpbin.default.svc.cluster.local
                  port:
                    number: 8000
  3. 使用http://${入口网关地址}在浏览器访问Keycloak应用。3

  4. 单击Administration Console,使用部署Keycloak时指定的Admin和PassWord进行登录。

步骤三:配置Keycloak

  1. 在Keycloak左侧导航栏,在Master下拉列表中单击Create Realm2

  2. 在新建Realm配置导航页面,如下图所示,创建新的Client。43

  3. 创建完成后,在Realm页面,按照下图,创建User。单击Save4

  4. User details页面,单击Credentials

  5. 在弹出的对话框,设置登录密码。单击Save设置登录密码

  6. 参照下图,创建一个Realm Role。单击SaveRole

  7. User details页面,选择Role mapping

  8. Role mapping页面,单击Assign role。将步骤六创建的Role分配给当前用户。5

  9. 参照下图,创建Client Scope。单击Save创建ClientScope

  10. Client Scope页面,单击mappers,参照下图,添加一个Mapper。单击Save13

  11. 单击scope,选中步骤六创建的Role左侧的复选框,单击Assign8

  12. 在Client设置界面,单击client scope,以default方式添加client scope。9

  13. 按照下图,添加集群oauth2-proxy的Valid redirect URls。单击Save10

说明

该操作步骤的示例里只有Keycloak服务使用HTTP协议,其余服务均使用HTTPS。所以redirect URI的格式为:https://${您的ASM网关地址}/oauth2/callback

至此,Keycloak已经全部设置好。您需要记录以下信息:

  • 新建Realm的ID:Test-oidc

  • Realm中创建的Client ID:oauth2proxy

  • Client设置中,Credentials子选项卡中的client secret

步骤四:启用ASM自定义授权,配置OIDC单点登录

  1. 登录ASM控制台,在左侧导航栏,选择服务网格 > 网格管理

  2. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择网格安全中心 > 自定义授权服务

  3. 自定义授权服务页面,单击关联自定义授权服务,选择OIDC身份认证授权服务。设置OIDC身份认证授权服务参数,单击创建

    关联外部授权服务

    请您根据之前创建的OIDC应用的相关信息,填写如上图中的字段,您可以使用ASM网关作为登录重定向地址。更多关于Cookie Secret,请参见Cookie Secret的生成

    • IdP OIDC Issuer URLhttp://${ASM网关地址}/realms/${keycloak中创建的realm}

    • ClientIDClient Secret:使用上一步骤中记录的参数。

    • Scopes:该参数中的OpenID为必填项,请您根据实际情况进行填写。

  4. 参照如下示例,创建VirtualService。

    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: oauth2-vs
      namespace: istio-system
    spec:
      gateways:
        - ingressgateway
      hosts:
        - '*'
      http:
        - match:
            - uri:
                prefix: /oauth2
          name: oauth2
          route:
            - destination:
                host: asm-oauth2proxy-httpextauth-oidc.istio-system.svc.cluster.local
                port:
                  number: 4180
    说明
    • route字段的host请您替换为您的ACK集群中istio-system namespace下对应的Oauth2Proxy的Service名称。

    • 为防止VirtualService冲突,请避免其他VirtualService匹配前缀为《/oauth2》的路径。

步骤五:创建授权策略

  1. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择网格安全中心 > 授权策略

  2. 在授权策略详情页面,单击使用YAML创建

  3. 创建页面,选择命名空间场景模版,配置如下YAML文件,然后单击创建

    apiVersion: security.istio.io/v1beta1
    kind: AuthorizationPolicy
    metadata:
      name: oidc
      namespace: istio-system
    spec:
      action: CUSTOM
      provider:
        name: httpextauth-oidc
      rules:
        - to:
            - operation:
                notPorts:
                  - '80'
      selector:
        matchLabels:
          istio: ingressgateway
    说明
    • AuthorizationPolicy指定了访问除了80以外的其它端口,均需要进行授权。

    • provider name填写您关联的自定义授权服务的名称,您可以在自定义授权服务的列表中进行查找。

步骤六:验证

  1. 在浏览器中访问${ASM网关外部IP:80}

    预期结果:1若您可以看到如上页面,则证明单点登录已经生效。

  2. 单击Sign in with OpenID Connect,在Keycloak的登录页面,请输入您在步骤一中创建的测试账号以及密码,单击登录

    预期结果:httpbin

  3. 单击Request inspection,选择/headers > try it out > Execute

    预期结果:11

  4. 请将上一步骤中Bearer之后请求携带的JWT在JWT Debugger中进行解析。更多关于JWT Debugger的内容,请参见JWT debugger

    预期结果:JWT解析成功后,您可以看到如下信息。其中附带Keycloak中存储的用户信息,并且当前的JWT已经经过了ASM的校验。