0

I want to retrieve AWS SSM parameters in my R code, but R doesn't have an AWS SDK (to my knowledge). So I decided to use the AWS REST API, which is simple to use except for needing bespoke signatures calculated for all requests. Happily the package aws.signature generates these - but I couldn't find examples for how to use it.

My code successfully generated a signature with the package, but then gave me this:

InvalidSignatureException
The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.

Most of the examples online for the REST API refer to AWS S3, which also didn't help with debugging as those have a slightly different structure!

So my question is: how to debug this error?

mm689
  • 359
  • 2
  • 10

1 Answers1

2

First things first: a working example!

body <- '{"Names": ["/my/ssm/path"]}'
region <- Sys.getenv("AWS_REGION", unset = "eu-west-1")

headers <- list(
    "Host" = paste0("ssm.", region, ".amazonaws.com"),
    "Date" = format(Sys.time(), "%Y%m%dT%H%M%SZ", tz = "UTC"),
    "Content-Type" = "application/x-amz-json-1.1",
    "Content-Length" = as.character(nchar(body)),
    "X-Amz-Target" = "AmazonSSM.GetParameters"
)

# Use the headers to sign the request for AWS' validation.
headers$Authorization <- aws.signature::signature_v4_auth(
    canonical_headers = headers,
    datetime = headers$Date,
    request_body = body,
    region = region,
    verb = "POST",
    action = "/",
    service = "ssm"
)$SignatureHeader

# If we're using temporary credentials, we must provide an extra header.
security.token <- Sys.getenv('AWS_SESSION_TOKEN', unset = "")
if (security.token != "") {
    headers[["X-Amz-Security-Token"]] <- security.token
}

# Send the request.
handle <- curl::new_handle()
curl::handle_setopt(handle, post = TRUE, postfields = charToRaw(body))
do.call(curl::handle_setheaders, c(handle, headers))

And: a few tips.

  • The aws.signature function returns an object with all the intermediate steps like StringToSign. I ended up print()ing this and comparing it with a related AWS example.
  • Signatures are very case sensitive! For example, verb = "post" rather than POST will cause an invalid signature error.
  • action seems to be mostly used for AWS S3: other services seem to use /
mm689
  • 359
  • 2
  • 10