How to call Cloud Run from out side of Cloud Run/GCP?
Asked Answered
M

1

0

I have a simple Spring Boot service 'say-hi' to take GET request under /say-hi and return 'hello'. It's deployed in managed Cloud Run. Suppose I don't want to open it to the general public. Now I wanted to do two things: 1. allow developer (I myself) to access 'say-hi' 2. allow another Spring Boot service outside of Cloud Run be able to make the call to 'say-hi'

For my goal 1:

Weird thing is that curl command doesn't work, but Insomnia works fine. Basically, I followed the doc, I added my google account to roles/run.invoker, but the curl command says Network is unrechable:
curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" http://say-hi-0-1-0-q6g2cgbzna-ew.a.run.app:8080/say-hi -v Errors:

*   Trying 216.239.36.53...
*   Trying 2001:4860:4802:36::35...
* Immediate connect fail for 2001:4860:4802:36::35: Network is unreachable
*   Trying 2001:4860:4802:36::35...
* Immediate connect fail for 2001:4860:4802:36::35: Network is unreachable
*   Trying 2001:4860:4802:36::35...
* Immediate connect fail for 2001:4860:4802:36::35: Network is unreachable

However, if I run gcloud auth print-identity-token separately to get the token first and then sent the GET request from Insomnia client, it works... I'm wondering why...

For my goal 2 I assume the right session to look at it here. Does this mean if I wanted to access 'say-hi' from outside of Cloud Run manged (both from my own laptop and from other GKE instances), I need to have IAP enable for my project? if yes, how to integrate cloud run with IAP?

Monserratemonsieur answered 4/5, 2020 at 20:52 Comment(0)
M
3

After a long day of searching and reading. Finally get a working version. The given doc of service-to-service authentication given by Google Cloud Run was really misleading me towards IAP, and the code here left a few places unclarified. Turned out to call Cloud Run service, I didn't need IAP at all. Big thanks to this blog where I grabbed the solution from.

  @PostMapping(value="/call-say-hi")
  public ResponseEntity<String> callSayHi() throws URISyntaxException, IOException {

    ServiceAccountCredentials serviceAccountCredentials =
        ServiceAccountCredentials.fromStream(new FileInputStream(SERVICE_ACCOUNT_JSON_KEY_PATH));
    serviceAccountCredentials.createScoped(IAM_SCOPE);
    IdTokenCredentials idTokenCredentials = IdTokenCredentials.newBuilder()
                                            .setIdTokenProvider(serviceAccountCredentials)
                                            .setTargetAudience(TARGET_AUDIENCE)
                                            .build();
    GenericUrl genericUrl = new GenericUrl(TARGET_AUDIENCE+"/say-hi");
    HttpCredentialsAdapter adapter = new HttpCredentialsAdapter(idTokenCredentials);
    HttpRequest request = httpTransport.createRequestFactory(adapter).buildGetRequest(genericUrl);
    request.setThrowExceptionOnExecuteError(false);
    HttpResponse response = request.execute();
    String r = response.parseAsString();
    System.out.println(r);
    return ResponseEntity.status(HttpStatus.OK).body(r);
  }

Where the TARGET_AUDIENCE is the deployed Cloud Run service URL

Monserratemonsieur answered 5/5, 2020 at 3:1 Comment(4)
The #createScoped call seems superfluous. Also, for comparison, I'm using GOOGLE_APPLICATION_CREDENTIALS=service_account_creds.json and "(IdTokenProvider) GoogleCredentials.getApplicationDefault()" instead of loading them myself. This then also automatically works in cloud run->cloud run.Estes
@Estes the scope is a separate thing than the credential I believe. the scope doesn't give you any permission is the service account credential is missing. But your way of getting the service account is definitely preferred.Monserratemonsieur
Your code snippet doesn't use the result of createScoped so I doubt that has any effect.Estes
It saved my lots of time. Really helpful.Terrijo

© 2022 - 2024 — McMap. All rights reserved.