针对Google IAP使用Salesforce命名凭证 [英] Using Salesforce Named Credentials Against Google IAP

查看:96
本文介绍了针对Google IAP使用Salesforce命名凭证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经建立了一个运行在Google App Engine上的REST API,受 Google Cloud IAP (身份识别代理).我的目标是使用服务帐户来从Salesforce向该API发出请求(使用外部服务功能).

I have built a REST API that is running on Google App Engine, protected by Google Cloud IAP (Identity Aware Proxy). My goal is to use a Service Account to make requests to this API from Salesforce (using the External Services feature).

感谢上一个问题,我了解我将需要使用 JWT令牌交换,以请求 OIDC 令牌.因此,下一步是了解如何填写Salesforce的命名凭据定义:

Thanks to a previous question, I understand that I will need to use JWT Token Exchange for this flow to request an OIDC token. So the next step is understanding how to fill out Salesforce's Named Credentials definition:

命名凭据的属性如下: :

  1. 证书::不适用于我的用例.
  2. 身份类型:是为每个访问Salesforce用户使用不同的凭据还是全面使用单个凭据.我将使用命名主体.
  3. 身份验证协议:我现在意识到需要进行JWT令牌交换.
  4. 令牌端点网址::为服务帐户下载的JSON指定https://oauth2.googleapis.com/token.
  5. 范围:我不确定此属性的正确值,也许应该是openid email?
  6. 颁发者:不知道这应该是什么.
  7. 指定的主要主题:我认为这应该是服务帐户中的 client_email 值.但是,此文档说为IAP保护的客户端ID请求OIDC令牌".这是否意味着我应该改用IAP Web应用程序的客户端ID 页中的客户端ID?
  8. 受众群体:我能找到的唯一合适的值是在GCP控制台的HTTPS资源部分中以/projects/NNNNN/apps/XXXXXXX形式出现的IAP签名标头JWT.
  9. 令牌有效期:,我认为应该是1个小时.
  10. JWT签名证书:服务帐户私钥.
  11. 生成授权标头:.应启用.
  1. Certificate: Not applicable to my use case.
  2. Identity Type: Whether to use different credentials for each accessing Salesforce user or a single credential across the board. I will be using Named Principal.
  3. Authentication Protocol: I now realize that JWT Token Exchange is required.
  4. Token Endpoint Url: The JSON downloaded for the Service Account specifies https://oauth2.googleapis.com/token.
  5. Scope: I am unsure of the correct value for this property, maybe it should be openid email?
  6. Issuer: No idea what this should be.
  7. Named Principal Subject: I think this should be the client_email value from the Service Account. However, this documentation says "Request an OIDC token for the IAP-secured client ID." Does that mean I should use the client ID from the IAP Client ID for Web application page instead?
  8. Audiences: The only value I can find that may be appropriate is from the IAP Signed Header JWT found in the HTTPS Resources section of the GCP Console in the form /projects/NNNNN/apps/XXXXXXX.
  9. Token Valid for: I believe this should be 1 hour.
  10. JWT Signing Certificate: The Service Account private key.
  11. Generate Authorization Header: Should be enabled.

问题:

  1. 任何人都可以确认我的理解并协助范围",发行人"和指定主要主题"字段吗?
  2. IAP文档讨论了JWT 其他声明 target_audience是必需的,那会在哪里结束?
  1. Can anyone confirm my understanding as well as assist with the Scope, Issuer, and Named Principal Subject fields?
  2. The IAP documentation talks about an JWT additional claim target_audience being required, where does that end up?

推荐答案

我认为target_audience云是位于IAP仪表板上的iapClientId.就像此处所述.

I think target_audience cloud be the iapClientId located on your IAP dashboard. Just like what mentioned here.

import google.auth
import google.auth.app_engine
import google.auth.compute_engine.credentials
import google.auth.iam
from google.auth.transport.requests import Request
import google.oauth2.credentials
import google.oauth2.service_account
import requests
import requests_toolbelt.adapters.appengine


IAM_SCOPE = 'https://www.googleapis.com/auth/iam'
OAUTH_TOKEN_URI = 'https://www.googleapis.com/oauth2/v4/token'


def make_iap_request(url, client_id, method='GET', **kwargs):
    """Makes a request to an application protected by Identity-Aware Proxy.

    Args:
      url: The Identity-Aware Proxy-protected URL to fetch.
      client_id: The client ID used by Identity-Aware Proxy.
      method: The request method to use
              ('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
      **kwargs: Any of the parameters defined for the request function:
                https://github.com/requests/requests/blob/master/requests/api.py
                If no timeout is provided, it is set to 90 by default.

    Returns:
      The page body, or raises an exception if the page couldn't be retrieved.
    """
    # Set the default timeout, if missing
    if 'timeout' not in kwargs:
        kwargs['timeout'] = 90

    # Figure out what environment we're running in and get some preliminary
    # information about the service account.
    bootstrap_credentials, _ = google.auth.default(
        scopes=[IAM_SCOPE])
    if isinstance(bootstrap_credentials,
                  google.oauth2.credentials.Credentials):
        raise Exception('make_iap_request is only supported for service '
                        'accounts.')
    elif isinstance(bootstrap_credentials,
                    google.auth.app_engine.Credentials):
        requests_toolbelt.adapters.appengine.monkeypatch()

    # For service account's using the Compute Engine metadata service,
    # service_account_email isn't available until refresh is called.
    bootstrap_credentials.refresh(Request())

    signer_email = bootstrap_credentials.service_account_email
    if isinstance(bootstrap_credentials,
                  google.auth.compute_engine.credentials.Credentials):
        # Since the Compute Engine metadata service doesn't expose the service
        # account key, we use the IAM signBlob API to sign instead.
        # In order for this to work:
        #
        # 1. Your VM needs the https://www.googleapis.com/auth/iam scope.
        #    You can specify this specific scope when creating a VM
        #    through the API or gcloud. When using Cloud Console,
        #    you'll need to specify the "full access to all Cloud APIs"
        #    scope. A VM's scopes can only be specified at creation time.
        #
        # 2. The VM's default service account needs the "Service Account Actor"
        #    role. This can be found under the "Project" category in Cloud
        #    Console, or roles/iam.serviceAccountActor in gcloud.
        signer = google.auth.iam.Signer(
            Request(), bootstrap_credentials, signer_email)
    else:
        # A Signer object can sign a JWT using the service account's key.
        signer = bootstrap_credentials.signer

    # Construct OAuth 2.0 service account credentials using the signer
    # and email acquired from the bootstrap credentials.
    service_account_credentials = google.oauth2.service_account.Credentials(
        signer, signer_email, token_uri=OAUTH_TOKEN_URI, additional_claims={
            'target_audience': client_id
        })

    # service_account_credentials gives us a JWT signed by the service
    # account. Next, we use that to obtain an OpenID Connect token,
    # which is a JWT signed by Google.
    google_open_id_connect_token = get_google_open_id_connect_token(
        service_account_credentials)

    # Fetch the Identity-Aware Proxy-protected URL, including an
    # Authorization header containing "Bearer " followed by a
    # Google-issued OpenID Connect token for the service account.
    resp = requests.request(
        method, url,
        headers={'Authorization': 'Bearer {}'.format(
            google_open_id_connect_token)}, **kwargs)
    if resp.status_code == 403:
        raise Exception('Service account {} does not have permission to '
                        'access the IAP-protected application.'.format(
                            signer_email))
    elif resp.status_code != 200:
        raise Exception(
            'Bad response from application: {!r} / {!r} / {!r}'.format(
                resp.status_code, resp.headers, resp.text))
    else:
        return resp.text


def get_google_open_id_connect_token(service_account_credentials):
    """Get an OpenID Connect token issued by Google for the service account.

    This function:

      1. Generates a JWT signed with the service account's private key
         containing a special "target_audience" claim.

      2. Sends it to the OAUTH_TOKEN_URI endpoint. Because the JWT in #1
         has a target_audience claim, that endpoint will respond with
         an OpenID Connect token for the service account -- in other words,
         a JWT signed by *Google*. The aud claim in this JWT will be
         set to the value from the target_audience claim in #1.

    For more information, see
    https://developers.google.com/identity/protocols/OAuth2ServiceAccount .
    The HTTP/REST example on that page describes the JWT structure and
    demonstrates how to call the token endpoint. (The example on that page
    shows how to get an OAuth2 access token; this code is using a
    modified version of it to get an OpenID Connect token.)
    """

    service_account_jwt = (
        service_account_credentials._make_authorization_grant_assertion())
    request = google.auth.transport.requests.Request()
    body = {
        'assertion': service_account_jwt,
        'grant_type': google.oauth2._client._JWT_GRANT_TYPE,
    }
    token_response = google.oauth2._client._token_endpoint_request(
        request, OAUTH_TOKEN_URI, body)
    return token_response['id_token']

这篇关于针对Google IAP使用Salesforce命名凭证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆