paws-r / paws

Paws, a package for Amazon Web Services in R
https://www.paws-r-sdk.com
Other
319 stars 37 forks source link

Expose signing functionality? #428

Open jennybc opened 3 years ago

jennybc commented 3 years ago

I have implemented an auth method called workload identity federation in the gargle R package, which handles various matters related to calling Google APIs. Specifically, I have implemented this flow for AWS, i.e. for applications running on AWS that need to make authenticated calls to Google Cloud services. https://github.com/r-lib/gargle/pull/178

As part of this token exchange ping pong, I have to craft a notional request to the AWS GetCallerIdentity() method. VERY IMPORTANTLY, I do not (can not) actual make this request. I need to marshal all the info, including the x-amz-date and x-amz-security-token headers, and generate a signature. Then I insert the signature into the headers, re-package the headers, serialize the whole request in a very specific way, and send it as part of a request to Google endpoint.

Here's the code:

https://github.com/r-lib/gargle/blob/0a2e7fd088c2ed52e088fe0d386f3d7adeac7d77/R/credentials_external_account.R#L264-L358

Currently I'm using aws.signature::signature_v4_auth() for generating the V4 signature. It's a bit awkward, but workable.

But I've realized that, across various R packages maintained by RStudio folks, paws is a more common choice for AWS functionality. Therefore, for "meta" reasons, it makes sense for me to use paws as well.

However, I can't easily see that paws (paws.common?) exposes the signature functionality that I need. I can see it's here, for internal use.

Is there a way for me to do what I need with paws?

davidkretch commented 3 years ago

Hello! Sorry for the delayed response. Currently you're right -- that functionality is not exported. But I agree it should be, in the paws.common package.

Unfortunately I probably won't have time to add this until maybe later this month sadly. If you have time and want to address it before then, I'd be happy to accept it.

I think maybe a wrapper around sign_with_body would work. The signer and request parameters expect a signer object with credentials, and an HTTP request with the URL. Here is an example invocation.

Since you also need the instance region, there is also get_instance_metadata, which might work for you? Currently this is also not exported.

jennybc commented 3 years ago

OK glad to hear I read the situation correctly and that you think it's reasonable for paws.common to export such functionality.

Thanks for the pointers about how this might look. Not sure if I'll take a crack at a PR, but I might.

Yeah, I do also need to know the instance region.

jennybc commented 3 years ago

To provide additional color for whoever implements this in the end, here are some observations about what's awkward about the current approach using aws.signature::signature_v4_auth(). I am restating observations made in comments in the code I link to above.

The notional request must include the x-amz-date and x-amz-security-token headers. They both need to be among the signed headers. I would like to not precompute those 2 headers (although I understand why it needs to be possible to pass them in), but post hoc I also need access to the values that were ultimately constructed and signed. I'm not familiar with patterns already in use in paws, but one idea is to allow these to be passed in but also honour a sentinel TRUE value which means "please figure this out for me, include it, and give me the result too". This would also seem to be the natural default behaviour.

Basically, I would like the future requesting-signing function to return something that includes the entire set of signed headers, presumably the union of those I passed in and those computed internally, in the exact form used in the canonical request (post whitespace-trimming, ordering, etc.).