Signed URL on GCO with cloud run

Hi @dchiesa1, Thank you for explanation and screencast of signed URL(https://github.com/DinoChiesa/Apigee-Java-GoogleUrlSigner)

We are trying to do something similar, Instead of having the v4 signing java code or JAR files in ApigeeX. We want the signing logic in cloud run and an apigee proxy will call it. The cloud run will sign the URL and send it to the client.

The issue we are facing is trying to reverse engineer the java code from the above github link. I run into mutiple issue of dependencies not being available from our org.  I found these solutions online and trying to implement this - https://github.com/salrashid123/gcs_signedurl/blob/main/java/src/main/java/com/test/TestApp.java

https://stackoverflow.com/questions/64811461/gcp-storage-signing-key-not-provided

will keep you updated but do you see any issues in the design, or any limitation that I should be aware of in cloud run for signedURL logic 

 

2 7 190
7 REPLIES 7

No I see no limitations. You should be able to create a signedurl within a Cloud Run container, pretty easily.  

The dependencies all get resolved with the pom file. If you know maven you should be able to sort that out.

There's probably more complexity in the java callout class than you need - with all the configuration stuff.  You could make that much simpler if you were just embedding this into a cloud run service. 

We want the signing logic in cloud run and an apigee proxy will call it.

Why would you do that?

The cloud run will sign the URL and send it to the client.

The Cloud Run service cannot reply directly to the client, if the Apigee proxy is calling Cloud Run.

Maybe you want the client to call CLoud Run directly, and you're not actually using Apigee in this flow?

We want the signing logic in cloud run and an apigee proxy will call it. (Why would you do that?) - I was told they architect team didn't want any private key info stored in Apigee and they felt its secure to do it in the cloud run. 

The cloud run will sign the URL and send it to the client.(The Cloud Run service cannot reply directly to the client, if the Apigee proxy is calling Cloud Run.) - yes you are right, Sorry for the wrong wording.
Client <-> Apigee <-> Cloud Run , client will call apigee, apigee will call cloud run and cloud run responds to apigee and apigee responds to client. 

 

OK you want to use Java and it needs to be a service.  Can you produce a "hello world" Cloud Run service using Java?  I would start by solving that problem.  I like using a very lightweight framework like javalin (https://javalin.io/) or  java-express ( https://github.com/masecla22/java-express) but you can use Spring or whatever you like.  It should accept at least a "GET /" and produce a response.

After solving that,  you need to modify that "Hello world" service to accept a POST with some input. The input is not going to be the same as the API call sent into Apigee, but instead, a special request with all the parameters associated to the desired signed URL.  That would include: 

  • verb
  • resource (bucket + object path)
  • desired expiry
  • signing key
  • payload
  • additional headers and query params

With that you should be able to generate the signed url. 

If I were doing that I would pass the inputs as JSON, and have my lightweight Java service parse from JSON with something like the Gson library. 

And then just... follow the logic in the existing Java callout.  The result should just be a URL, which you send back to the caller. 

You can test this locally without any Apigee, just by sending a request to it, like this: 

 

curl 0:8080/sign -H content-type:application/json -d '{
  "verb": "GET",
  "expires-in": "60s",
  "bucket": "unique-bucket-name",
  "object": "cute-kittens.png",
  "service-account-key": {
    "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEug...ZvJPUIoRSMY=\n-----END PRIVATE KEY-----\n",
    "client_email": "my-sa-@my-gcp-project.iam.gserviceaccount.com",
  }
}'

 

In the service, that JSON blob takes the place of the set of properties that you would provide to the callout.

Rather than transmitting the secret like this from Apigee to the service, You may want the Java service to retrieve the signing key from the SecretManager in GCP.  But that's a flourish you can add later. 

 

Thank you for guidance and putting the things together for me @dchiesa1 , One change is we don't want to send the private key as the input payload to the cloudrun service. Is there any way we use sign blob or a google API call from cloud run to sign the URL? It will use the Service account creds that cloud run is deployed with ?? 

Is there any way we use sign blob or a google API call from cloud run to sign the URL? It will use the Service account creds that cloud run is deployed with ??

Ah, yes, signBlob is the right way to do this.

I updated the example to use signBlob. Get the latest version. 

With that approach, You must provide some sort of access restriction on the cloud run service. If the cloud run service is authorized to generate signatures on behalf of other service accounts, then... that means any system that can send a "please generate a signed url" request to the cloud run service , and knows the email of a valid service account, has access to the google cloud storage bucket. So you would need to authenticate requests, and verify that the caller (in your case, Apigee) is authorized to call, and is authorized to request THAT particular cloud storage bucket and object and SA. That is beyond the scope of the example I shared. Those are problems you would need to solve.

Working on getting some security pieces approved internally...will update the post accordingly once I have the updates