Google cloud platform 使用用户帐户凭据访问私有云运行/云功能

Google cloud platform 使用用户帐户凭据访问私有云运行/云功能,google-cloud-platform,google-cloud-functions,google-cloud-run,google-iam,Google Cloud Platform,Google Cloud Functions,Google Cloud Run,Google Iam,这是我的用例 我已经在私有模式下部署了一个云运行服务。(与云功能相同) 我正在开发一个使用这种云运行的新服务。我使用应用程序中的默认凭据进行身份验证。它在计算引擎和云上运行,因为默认凭证是从元数据服务器获取的 但是,在我的本地环境中,我需要使用服务帐户密钥文件来实现这一点。(例如,当我设置GOOGLE_应用程序_凭证env var时) 但是,我无法使用我的用户帐户凭据。 在Java、Node或Go中,日志跟踪非常清晰:无法在用户凭证类型上生成标识令牌 所以 为什么谷歌认证库不允许这样做 为

这是我的用例

  • 我已经在私有模式下部署了一个云运行服务。(与云功能相同)
  • 我正在开发一个使用这种云运行的新服务。我使用应用程序中的默认凭据进行身份验证。它在计算引擎和云上运行,因为默认凭证是从元数据服务器获取的
但是,在我的本地环境中,我需要使用服务帐户密钥文件来实现这一点。(例如,当我设置GOOGLE_应用程序_凭证env var时)

但是,我无法使用我的用户帐户凭据。

在Java、Node或Go中,日志跟踪非常清晰:无法在用户凭证类型上生成标识令牌

所以

  • 为什么谷歌认证库不允许这样做
  • 为什么谷歌前端只接受谷歌签名的身份令牌
  • 是否存在继续使用用户帐户的变通方法
和一段上下文:我们希望避免使用服务帐户密钥文件。今天,它是我们的主要安全漏洞(文件被复制、通过电子邮件发送,甚至在Github上公开提交…)。 用户帐户默认凭据适用于所有Google Cloud API,但不适用于IAP和Cloud Run/Function

编辑

这里有一些错误的例子

爪哇

我这样做

        Credentials credentials = GoogleCredentials.getApplicationDefault().createScoped("https://www.googleapis.com/auth/cloud-platform");

        IdTokenCredentials idTokenCredentials = IdTokenCredentials.newBuilder()
                .setIdTokenProvider((IdTokenProvider) credentials)
                .setTargetAudience(myUri).build();

        HttpRequestFactory factory = new NetHttpTransport().createRequestFactory(new HttpCredentialsAdapter(idTokenCredentials));
并且我的用户凭据与
IdTokenProvider
接口不兼容


Caused by: java.lang.ClassCastException: class com.google.auth.oauth2.UserCredentials cannot be cast to class com.google.auth.oauth2.IdTokenProvider (com.google.auth.oauth2.UserCredentials and com.google.auth.oauth2.IdTokenProvider are in unnamed module of loader 'app')
节点

对于节点,此代码与服务帐户一起工作

    const {GoogleAuth} = require('google-auth-library');
    const auth = new GoogleAuth()
    const client = await auth.getIdTokenClient(url);
    const res = await client.request({url});
    console.log(res.data);
但我的用户帐户出现了这个错误

Error: Cannot fetch ID token in this environment, use GCE or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to a service account credentials JSON file.
    at GoogleAuth.getIdTokenClient(....)

gcloud auth activate service account——密钥文件
仅用于运行gcloud命令的“您”,它不会被需要
GOOGLE\u应用程序\u凭据的“应用程序”获取

从或中可以看到,您要么需要服务帐户的JSON密钥文件,要么必须在GCE/GKE/Cloud Run/App Engine/GCF实例中运行

为了在您的本地环境中工作,我建议使用
gcloud auth application default login
命令登录(此命令的工作方式类似于您在本地设置了
GOOGLE\u application\u凭据)。让我知道这是否有效

如果这不起作用,作为最后手段,您可以重构代码,在本地工作时从环境变量(如果设置)中提取标识令牌,例如:

$ export ID_TOKEN="$(gcloud auth print-identity-token -q)"
$ ./your-app
附录 根据Guillaume的请求“这
gcloud auth print identity token
如何与我的个人谷歌凭证配合使用”

以下是方法:

  • gcloud
    是一个向谷歌注册的OAuth客户端,要获得JWT令牌,您需要在GCE/GCF/GKE/GAE/CR环境中工作,或者使用OAuth应用程序

  • gcloud
    发出如下请求:

    POST https://www.googleapis.com/oauth2/v4/token
    
    附正文:

    grant_type=refresh_token&client_id=REDACTED.apps.googleusercontent.com&client_secret=REDACTED&refresh_token=REDACTED
    
    最有可能的是,
    client\u id
    client\u secret
    值对我们来说是相同的,因为它们是gcloud的。但是,它会将您的
    刷新\u令牌
    与新令牌交换

  • /token
    响应将包含
    access\u token
    id\u token
    。e、 g:

    {
    "access_token": ".....",
    "id_token": "eyJhbG....."
    "expires_in": 3599,
    "scope": "https://www.googleapis.com/auth/userinfo.email 
    https://www.googleapis.com/auth/appengine.admin 
    https://www.googleapis.com/auth/compute 
    https://www.googleapis.com/auth/cloud-platform 
    https://www.googleapis.com/auth/accounts.reauth openid",
    "token_type": "Bearer",
    }
    
  • 这就是
    gcloud
    为您打印身份令牌的方式

    如果您对代码如何使用JSON密钥文件感到好奇,您将看到非常类似的内容。例如,在Go中有一个包,如果您确实想为用户帐户而不是服务帐户获取身份令牌,您将看到一个。

    。您需要已经通过
    gcloud auth application default login
    进行身份验证,然后您可以执行以下操作:

    UserCredentials credentials = (UserCredentials) GoogleCredentials.getApplicationDefault();
    
    CloseableHttpClient client = HttpClients.createDefault();
    HttpPost httpPost = new HttpPost("https://accounts.google.com/o/oauth2/token");
    List<NameValuePair> params = new ArrayList<NameValuePair>();
    params.add(new BasicNameValuePair("grant_type", "refresh_token"));
    params.add(new BasicNameValuePair("client_id", credentials.getClientId()));
    params.add(new BasicNameValuePair("client_secret", credentials.getClientSecret()));
    params.add(new BasicNameValuePair("refresh_token", credentials.getRefreshToken()));
    httpPost.setEntity(new UrlEncodedFormEntity(params));
    
    String id_token = "";
    try (CloseableHttpClient c = HttpClientBuilder.create().disableRedirectHandling().build();
        CloseableHttpResponse response = c.execute(httpPost)) {
        String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
        JsonNode parent= new ObjectMapper().readTree(responseString);
        id_token = parent.path("id_token").asText();
    }
    return id_token;
    
    UserCredentials-credentials=(UserCredentials)GoogleCredentials.getApplicationDefault();
    CloseableHttpClient=HttpClients.createDefault();
    HttpPost HttpPost=新的HttpPost(“https://accounts.google.com/o/oauth2/token");
    List params=new ArrayList();
    添加参数(新的BasicNameValuePair(“授权类型”、“刷新令牌”);
    add(新的BasicNameValuePair(“client_id”,credentials.getClientId());
    add(新的BasicNameValuePair(“client_secret”,credentials.getClientSecret());
    添加(新的BasicNameValuePair(“刷新令牌”,credentials.getRefreshToken());
    setEntity(新的UrlEncodedFormEntity(参数));
    字符串id_token=“”;
    try(CloseableHttpClient c=HttpClientBuilder.create().disableRedirectHandling().build();
    CloseableHttpResponse响应=c.execute(httpPost)){
    字符串responseString=EntityUtils.toString(response.getEntity(),“UTF-8”);
    JsonNode parent=newObjectMapper().readTree(responseString);
    id_-token=parent.path(“id_-token”).asText();
    }
    返回id_令牌;
    
    重构代码的问题在于它不能在我的本地环境和GCP环境之间无缝工作。关于
    激活服务帐户
    ,您是正确的,凭证的env var仍然存在(我编辑了我的问题以纠正我的错误),我向您确认,
    gcloud auth应用程序默认登录名
    使用我的个人凭证,但它不起作用。是的,我担心在这种情况下,您实际上需要完整的凭证(即服务帐户JSON密钥)。好的,但在本例中,我想知道什么神奇的东西执行命令
    gcloud auth print identity token
    ,以使用我的用户帐户生成有效的令牌!这很复杂,我正在为问题添加附录。