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?

foxwendy
  • 2,819
  • 2
  • 28
  • 50

1 Answers1

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

foxwendy
  • 2,819
  • 2
  • 28
  • 50
  • 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. – mernst May 08 '20 at 07:41
  • @mernst 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. – foxwendy May 13 '20 at 20:51
  • Your code snippet doesn't use the result of createScoped so I doubt that has any effect. – mernst May 15 '20 at 07:01
  • It saved my lots of time. Really helpful. – Soumik Das Aug 12 '21 at 20:03