Я пытаюсь создать JWT для вызова триггера HTTP в развернутой облачной функции GCP. Я уже развернул свою функцию с помощью allUsers и убедился, что она работает, но я хочу, чтобы она была более безопасной, поэтому мне нужно присоединить JWT к моему HTTP-запросу. Я следую этому коду , и следующие фрагменты в основном из этого. Я думаю, что я близко, но еще не совсем там. Во всех приведенных ниже примерах et c я изменил имя своего проекта на 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;
Я добавил другие варианты как комментарии к константам.
Судя по сообщению об ошибке, похоже, что значение аудитории, которое я использую, неверно. На этой странице предлагается, чтобы аудитория представляла собой адрес электронной почты учетной записи службы, и я думаю, что в другом месте я видел, что это должен быть URL-адрес функции облака, но ни один из них не работает для меня.
Я знаю, что это может работать, потому что я могу выполнить эту команду:
gcloud auth print-identity-token
, которая дает мне окончательный JWT (если у меня есть GOOGLE_APPLICATION_CREDENTIALS, указывающая на мой json файл). Я могу вставить этот JWT в команду curl и успешно вызвать триггер HTTP, и если я пропущу JWT, он завершится неудачно, поэтому я знаю, что JWT проверяется. Но до сих пор я не знаю, как сделать эквивалент gcloud auth print-identity-token из моего Java кода. Кто-нибудь знает?