当前位置: 首页 > 知识库问答 >
问题:

如何验证谷歌云功能访问安全的应用程序引擎endpoint

阮雅达
2023-03-14

Google Cloud Platform已经引入了身份感知代理,以保护应用引擎灵活环境实例免受公共访问。

然而,尚不完全清楚这是否可以或应该从访问GAE托管APIendpoint的谷歌云函数中使用。

文档(包括Python和Java示例)显示了一个IAP身份验证工作流,包括1)生成JWT令牌,2)创建OpenID令牌,3)然后使用授权:承载令牌头向Google App Engine提交请求

如果每次调用函数时都必须进行授权,那么对于运行云函数来说,这似乎相当复杂。

谷歌云功能是否还有其他方法可以访问安全的GAEendpoint?

共有3个答案

柳宏深
2023-03-14

Python示例:

from google.auth.transport.requests import Request as google_request
from google.oauth2 import id_token

open_id_connect_token = id_token.fetch_id_token(google_request(), client_id)

其中client_id是字符串。导航到API

当您想向安全的IAP服务发出请求时,只需添加到头

{'Authorization': 'Bearer your_open_id_connect_token'}

资料来源:https://cloud.google.com/iap/docs/authentication-howto

盖晋
2023-03-14

对于那些仍在关注2020年及以后的人来说,谷歌让这一切变得非常简单。

他们的文档中有一个例子,说明了如何验证在云功能中非常有效的IAP:

// const url = 'https://some.iap.url';
// const targetAudience = 'IAP_CLIENT_ID.apps.googleusercontent.com';

const {GoogleAuth} = require('google-auth-library');
const auth = new GoogleAuth();

async function request() {
  console.info(`request IAP ${url} with target audience ${targetAudience}`);
  const client = await auth.getIdTokenClient(targetAudience);
  const res = await client.request({url});
  console.info(res.data);
}
樊胜
2023-03-14

如果你想从GCF呼叫受IAP保护的应用程序,你确实应该使用ID令牌。Nodejs中没有示例,所以我用它作为参考(风格可能是错误的,因为这是我第一次接触Nodejs)。与常规的JWT声明集不同,它不应该包含范围,并且有目标受众。

/**
 * Make IAP request
 *
 */
exports.CfToIAP = function CfToIAP (req, res) {
  var crypto = require('crypto'),
      request = require('request');
  var token_URL = "https://www.googleapis.com/oauth2/v4/token";
  // service account private key (copied from service_account.json)
  var key = "-----BEGIN PRIVATE KEY-----\nMIIEvQexsQ1DBNe12345GRwAZM=\n-----END PRIVATE KEY-----\n";

  // craft JWT
  var JWT_header = new Buffer(JSON.stringify({ alg: "RS256", typ: "JWT" })).toString('base64');
  // prepare claims set
  var iss = "12345@12345.iam.gserviceaccount.com";  // service account email address (copied from service_account.json)
  var aud = "https://www.googleapis.com/oauth2/v4/token";
  var iat = Math.floor(new Date().getTime() / 1000);
  var exp = iat + 120; // no need for a long linved token since it's not cached
  var target_audience = "12345.apps.googleusercontent.com"; // this is the IAP client ID that can be obtained by clicking 3 dots -> Edit OAuth Client in IAP configuration page
  var claims = {
    iss: iss,
    aud: aud,
    iat: iat,
    exp: exp,
    target_audience: target_audience
  };
  var JWT_claimset = new Buffer(JSON.stringify(claims)).toString('base64');
  // concatenate header and claimset
  var unsignedJWT = [JWT_header, JWT_claimset].join('.');
  // sign JWT
  var JWT_signature = crypto.createSign('RSA-SHA256').update(unsignedJWT).sign(key, 'base64');
  var signedJWT = [unsignedJWT, JWT_signature].join('.');
  // get id_token and make IAP request
  request.post({url:token_URL, form: {grant_type:'urn:ietf:params:oauth:grant-type:jwt-bearer', assertion:signedJWT}}, function(err,res,body){
    var data = JSON.parse(body);
    var bearer = ['Bearer', data.id_token].join(' ');
    var options = {
      url: 'https://1234.appspot.com/', // IAP protected GAE app
      headers: {
        'User-Agent': 'cf2IAP',
        'Authorization': bearer
      }
    };
    request(options, function (err, res, body) {
      console.log('error:', err);
    });
  });
  res.send('done');
};

/**
 * package.json
 *
 */

{
  "name": "IAP-test",
  "version": "0.0.1",
  "dependencies": {
    "request": ">=2.83"
  }
}

更新:不推荐捆绑服务号密钥,因此更好的选择是使用元数据服务器。为了让下面的示例正常工作,应该启用谷歌身份和访问管理(IAM)应用编程接口,应用引擎默认服务号应该具有服务帐户角色(默认编辑器是不够的):

/**
 * Make request from CF to a GAE app behind IAP:
 * 1) get access token from the metadata server.
 * 2) prepare JWT and use IAM APIs projects.serviceAccounts.signBlob method to avoid bundling service account key.
 * 3) 'exchange' JWT for ID token.
 * 4) make request with ID token.
 *
 */
exports.CfToIAP = function CfToIAP (req, res) {
  // imports and constants
  const request = require('request');
  const user_agent = '<user_agent_to_identify_your_CF_call>';
  const token_URL = "https://www.googleapis.com/oauth2/v4/token";
  const project_id = '<project_ID_where_CF_is_deployed>';
  const service_account = [project_id,
                           '@appspot.gserviceaccount.com'].join(''); // app default service account for CF project
  const target_audience = '<IAP_client_ID>';
  const IAP_GAE_app = '<IAP_protected_GAE_app_URL>';

  // prepare request options and make metadata server access token request
  var meta_req_opts = {
    url: ['http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/',
          service_account,
          '/token'].join(''),
    headers: {
      'User-Agent': user_agent,
      'Metadata-Flavor': 'Google'
    }
  };
  request(meta_req_opts, function (err, res, body) {
    // get access token from response
    var meta_resp_data = JSON.parse(body);
    var access_token = meta_resp_data.access_token;

    // prepare JWT that is {Base64url encoded header}.{Base64url encoded claim set}.{Base64url encoded signature}
    // https://developers.google.com/identity/protocols/OAuth2ServiceAccount for more info
    var JWT_header = new Buffer(JSON.stringify({ alg: "RS256", typ: "JWT" })).toString('base64');
    var iat = Math.floor(new Date().getTime() / 1000);
    // prepare claims set and base64 encode it
    var claims = {
      iss: service_account,
      aud: token_URL,
      iat: iat,
      exp: iat + 60, // no need for a long lived token since it's not cached
      target_audience: target_audience
    };
    var JWT_claimset = new Buffer(JSON.stringify(claims)).toString('base64');

    // concatenate JWT header and claims set and get signature usign IAM APIs projects.serviceAccounts.signBlob method
    var to_sign = [JWT_header, JWT_claimset].join('.');    
    // sign JWT using IAM APIs projects.serviceAccounts.signBlob method
    var signature_req_opts = {
      url: ['https://iam.googleapis.com/v1/projects/',
            project_id,
            '/serviceAccounts/',
            service_account,
            ':signBlob'].join(''),
      method: "POST",
      json: {
        "bytesToSign": new Buffer(to_sign).toString('base64')
      },
      headers: {
        'User-Agent': user_agent,
        'Authorization': ['Bearer', access_token].join(' ')
      }
    };
    request(signature_req_opts, function (err, res, body) {
      // get signature from response and form JWT
      var JWT_signature = body.signature;
      var JWT = [JWT_header, JWT_claimset, JWT_signature].join('.');

      // obtain ID token
      request.post({url:token_URL, form: {grant_type:'urn:ietf:params:oauth:grant-type:jwt-bearer', assertion:JWT}}, function(err, res, body){
        // use ID token to make a request to the IAP protected GAE app
        var ID_token_resp_data = JSON.parse(body);
        var ID_token = ID_token_resp_data.id_token;
        var IAP_req_opts = {
          url: IAP_GAE_app,
          headers: {
            'User-Agent': user_agent,
            'Authorization': ['Bearer', ID_token].join(' ')
          }
        };
        request(IAP_req_opts, function (err, res, body) {
          console.log('error:', err);
        });
      });
    });
  });
  res.send('done');
};
 类似资料:
  • 我有一个应用引擎项目。 我也有谷歌云功能。 我想从App Engine项目中调用谷歌云功能。我就是没法让它发挥作用。 是的,如果我将函数完全公开(即将云函数设置为“允许所有流量”,并为“所有用户”创建一个允许调用函数的规则),它就可以工作。但是如果我限制这两个设置中的任何一个,它会立即停止工作,我得到403。 应用程序和函数在同一个项目中,所以我至少假设将函数设置为“仅允许内部流量”应该可以正常工

  • 谷歌云的功能似乎非常有趣,因为它是无服务器和零维护的解决方案。但是,什么时候在谷歌应用程序引擎上使用谷歌云功能合适呢?

  • 我想能够从谷歌云功能中调用谷歌应用程序引擎,有可能吗?找不到任何解决办法

  • 对于这个问题,这里可能是错误的地方,所以如果有必要,请重新指示我。 我使用Google Cloud函数部署了几个简单的函数,它们可以实现以下功能: 从AWS读取文件并写入云SQL 我将这些函数作为单独的函数,因为(1)通常需要比云函数最大超时更长的时间。正因为如此,我正在考虑将这一切作为一项服务转移到App Engine。关于应用程序引擎标准,我的问题是: 请求超时是什么意思?如果我运行这个服务,

  • 我有一个通过谷歌云托管的API。API的主要入口点是一个应用引擎实例(standard),它需要能够调用各种云函数来执行其任务。 为了使云功能安全,我想将入口控件设置为“仅允许内部”。 我已经将云函数和应用引擎部署在同一个区域(us-Central al1)中,但是每次应用引擎实例试图调用云函数时,都会出现403错误。我尝试为应用引擎设置VPC连接器,但这没有帮助。 这是应用程序。yaml文件:

  • 我正在App Engine上评估一个Quarkus应用程序。该应用程序需要一个基于Cloud SQL的Postgres DB,我将该实例命名为“quarkus”。 但是我遇到了这些访问错误:无权访问实例:addlogic-foodiefnf-1:quarkus Service account:addlogic-foodiefnf-1 @ app spot . gserviceaccount . c