Вызвать Google Cloud Run от java - PullRequest
       60

Вызвать Google Cloud Run от java

0 голосов
/ 02 апреля 2020

Я хочу вызвать Cloud Run из внешнего приложения. Внешнее приложение написано в Kotlin (java) и работает на JDK JDK 11. Он аутентифицируется с использованием служебной учетной записи

ServiceAccountCredentials.fromStream(serviceAccount).createScoped("https://www.googleapis.com/auth/cloud-platform")

, где служебная учетная запись является действительным JSON файлом. Я проверил разрешения для запуска облачного запуска для учетной записи службы в облачной консоли Google.

Я не нашел официального API, поэтому использовал GoogleNetHttpTransport Google для запуска HTTP-запроса на публикацию. Для запуска облачного запуска я попытался использовать HttpCredentialsAdapter

transport.createRequestFactory(HttpCredentialsAdapter(googleCredentials))
   .buildPostRequest(GenericUrl(url), JsonHttpContent(JacksonFactory(), data))

Я пытался использовать токен доступа directy

val headers = HttpHeaders()
googleCredentials.refreshIfExpired()
headers.authorization = "Bearer " + googleCredentials.accessToken.tokenValue
postRequest.headers = headers

И я пытался использовать учетную запись службы Jet и использовать метаданные jwt запроса

val headers = HttpHeaders()
jwtCredentials = ServiceAccountJwtAccessCredentials.fromStream(serviceAccount)
jwtCredentials.getRequestMetadata(URI(url)).forEach {
    headers.set(it.key, it.value)
}
postRequest.headers = headers

Во всех этих случаях он возвращает эту ошибку

[20:35:00 WARN]: Exception in thread "TestThread" com.google.api.client.http.HttpResponseException: 401 Unauthorized
[20:35:00 WARN]:    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1113)
[20:35:00 WARN]:    at ***.CloudRun$invoke$3.invokeSuspend(CloudRun.kt:34)
[20:35:00 WARN]:    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
[20:35:00 WARN]:    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
[20:35:00 WARN]:    at java.base/java.lang.Thread.run(Thread.java:834)

Спасибо за вашу поддержку заранее

Ответы [ 2 ]

1 голос
/ 03 апреля 2020

Я потратил время на библиотеку OAuth2 Java, и проблема в следующем. Класс ServiceAccountCredentials добавляет AccessToken в качестве авторизации, а класс ServiceAccountJwtAccessCredentials добавляет самоподписанный identity token.

Я углублюсь на 1021 *, но На данный момент вы можете установить заголовок вручную

        String myUri = "https://.....";

        Credentials credentials =  ServiceAccountCredentials
                .fromStream(resourceLoader.getResource("classpath:./key.json")
                        .getInputStream()).createScoped("https://www.googleapis.com/auth/cloud-platform");

        String token = ((IdTokenProvider)credentials).idTokenWithAudience(myUri, Collections.EMPTY_LIST).getTokenValue();

        HttpRequestFactory factory = new NetHttpTransport().createRequestFactory();
        HttpRequest request = factory.buildGetRequest(new GenericUrl(myUri));
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization","Bearer " + token);
        request.setHeaders(headers);
        HttpResponse httpResponse = request.execute();
        System.out.println(CharStreams.toString(new InputStreamReader(httpResponse.getContent(), Charsets.UTF_8)));

Части здесь, но не работают вместе.

РЕДАКТИРОВАТЬ

После некоторого обмена на GitHub, Google предоставит мне решение. Теперь заголовок автоматически снабжен подписанным идентификатором Token

        Credentials credentials =  ServiceAccountCredentials
                .fromStream(resourceLoader.getResource("classpath:./key.json")
                        .getInputStream()).createScoped("https://www.googleapis.com/auth/cloud-platform");


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

        HttpRequestFactory factory = new NetHttpTransport().createRequestFactory(new HttpCredentialsAdapter(idTokenCredentials));
        HttpRequest request = factory.buildGetRequest(new GenericUrl(myUri));
        HttpResponse httpResponse = request.execute();
        System.out.println(CharStreams.toString(new InputStreamReader(httpResponse.getContent(), Charsets.UTF_8)));
0 голосов
/ 03 апреля 2020

Я не знаю Java SDK достаточно хорошо, но я думаю, что я заметил ошибку:

headers.authorization = "Bearer " + googleCredentials.accessToken.tokenValue
                                                      ^^^^^^^^^^^

Вы не должны посылать «токен доступа» GCP в приложение Cloud Run (например, https://*.run.app). Этот токен предназначен для вызова API Google; и приложения Cloud Run - это не то.

Вместо этого вам следует отправлять «токен идентификации», который в основном показывает, что вы владеете учетной записью службы, не выдавая никакого разрешения вызываемой службе (для используйте этот токен для вызова API GCP).

Вы не можете самостоятельно подписать «токен идентификации» локально, вам необходимо вызвать конечную точку.

Это объяснено на этой странице: https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials#sa -credentials-JWT

...