【发布时间】:2021-07-20 19:34:43
【问题描述】:
我要做的是生成一个 JWT,用于在我部署的 GCP 云函数上调用 HTTP 触发器。 我已经使用“allUsers”部署了我的函数并验证了它是否有效,但我希望它更安全,因此我需要将 JWT 附加到我的 HTTP 请求中。 我正在关注this code,以下 sn-ps 主要来自于此。 我想我已经很接近了,但还不是很接近。在下面的所有示例等中,我已将项目名称更改为 PROJECT_NAME。
首先,我创建了一个名为 testharness-sa 的服务帐户并下载了它的密钥文件。当我运行测试时,我有一个 env var GOOGLE_APPLICATION_CREDENTIALS 指向该文件。然后我运行以下命令:
gcloud functions add-iam-policy-binding gopubsub \
--member='serviceAccount:testharness-sa@PROJECT_NAME.iam.gserviceaccount.com' \
--role='roles/cloudfunctions.invoker'
这给了我一个确认,列出了我的云函数上的所有当前绑定,包括 testharness-sa。
我的代码的核心是这样的:
private String getSignedJwt() {
GoogleCredentials credentials = GoogleCredentials
.getApplicationDefault()
.createScoped(Collections.singleton(IAM_SCOPE));
long now = System.currentTimeMillis();
RSAPrivateKey privateKey = (RSAPrivateKey) credentials.getPrivateKey();
Algorithm algorithm = Algorithm.RSA256(null, privateKey);
return JWT.create()
.withKeyId(credentials.getPrivateKeyId())
.withIssuer(credentials.getClientEmail())
.withSubject(credentials.getClientEmail())
.withAudience(OAUTH_TOKEN_AUDIENCE)
.withIssuedAt(new Date(now))
.withExpiresAt(new Date(now + EXPIRATION_TIME_IN_MILLIS))
.withClaim("target_audience", clientId)
.sign(algorithm);
}
这给了我一个签名的 JWT。据我了解,这用于调用 GCP 以获取可用于调用云函数的最终 JWT。
生成签名的 JWT 后,我会像这样使用它:
String jwt = getSignedJwt();
final GenericData tokenRequest = new GenericData()
.set("grant_type", JWT_BEARER_TOKEN_GRANT_TYPE)
.set("assertion", jwt);
final UrlEncodedContent content = new UrlEncodedContent(tokenRequest);
final HttpRequestFactory requestFactory = httpTransport.createRequestFactory();
final HttpRequest request = requestFactory
.buildPostRequest(new GenericUrl(OAUTH_TOKEN_URI), content)
.setParser(new JsonObjectParser(JacksonFactory.getDefaultInstance()));
HttpResponse response = request.execute();
...
所以它获取了签名的 JWT 并提出了获取最终 JWT 的请求,然后......失败了。错误是“无效的 JWT:观众检查失败” 看起来我的参数不好,所以让我们看看我的参数(它们实际上是常量,而不是参数):
private static final String IAM_SCOPE = "https://www.googleapis.com/auth/iam";
//"https://www.googleapis.com/auth/cloud-platform";
private static final String OAUTH_TOKEN_URI = "https://oauth2.googleapis.com/token";
//"https://www.googleapis.com/oauth2/v4/token";
private static final String OAUTH_TOKEN_AUDIENCE = "https://us-central1-PROJECT_NAME.cloudfunctions.net/gopubsub";
//"https://www.googleapis.com/token";
private static final String JWT_BEARER_TOKEN_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer";
private static final long EXPIRATION_TIME_IN_MILLIS = 3600 * 1000L;
我已经添加了其他变体作为针对常量的 cmets。
根据错误消息,我使用的受众价值似乎是错误的。 This page 建议受众应该是服务帐户电子邮件,我想我在其他地方看到它应该是云功能的 URL,但这些都不适合我。
我知道这可以工作,因为我可以发出这个命令:
gcloud auth print-identity-token
这给了我最终的 JWT(只要我有 GOOGLE_APPLICATION_CREDENTIALS 指向我的 json 文件)。 我可以将该 JWT 粘贴到 curl 命令中并成功调用 HTTP 触发器,如果我将 JWT 留在外面,它会失败,所以我知道 JWT 正在被检查。 但到目前为止,我不知道如何从我的 Java 代码中执行相当于 gcloud auth print-identity-token 的操作。 有人知道吗?
【问题讨论】:
-
您是否尝试过在没有 IAM_SCOPE 的情况下生成 jwt,如来自 link 的示例所示?
-
我现在有 :) 是的,它似乎没有任何区别,但是我发现问题与范围无关。请参阅下面的答案。
标签: java jwt google-cloud-functions