Skip to content

AWS4 Signer producing incorrect signature #4550

@tee

Description

@tee

Describe the bug

We are currently attempting to implement Workload Identity Federation to call GCP from our AWS instances as outlined in Googles documentation. Upon creating the request and signing that request with the correct host and x-goog-cloud-target-resource, we then are sending over the request to be signed. Once the request is sent over and we get a signed request to send to Google, we recieve the following error message:

This attempt was done using DefaultRequest and AWS4Signer.

{"error":"invalid_grant","error_description":"Received invalid AWS response of type SignatureDoesNotMatch with error message: 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."}

Expected Behavior

We would expect, given this script and the credentials that are being utilized here, specifically the access key and secret access key, that we would recieve a correctly signed request to pass to recieve an STS through WIF.

Current Behavior

We are seeing the error message: {"error":"invalid_grant","error_description":"Received invalid AWS response of type SignatureDoesNotMatch with error message: 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."}

Reproduction Steps

Please see additional context section for items we have ruled out.

public String generateSubjectToken(String projectNumber, String poolId, String providerId) {
        AWSCredentials credentials = new DefaultAWSCredentialsProviderChain().getCredentials();
        AWS4Signer signer = new AWS4Signer();

        Request<Void> request = new DefaultRequest<Void>("sts");
        request.setHttpMethod(HttpMethodName.POST);
        request.setEndpoint(URI.create("https://sts.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15"));
        
        Map<String, String> headers = new HashMap<>();
        headers.put("host", "sts.amazonaws.com");
        headers.put("x-goog-cloud-target-resource", "//iam.googleapis.com/projects/" + projectNumber + "/locations/global/workloadIdentityPools/" + poolId + "/providers/" + providerId);
        request.setHeaders(headers);

        System.out.println("Request is: " + request.toString());
        System.out.println("Headers are: " + headers.toString());

        signer.setServiceName("sts");
        signer.setRegionName("us-east-1");
        signer.sign(request, credentials);

        JSONObject token = new JSONObject();
        token.put("url", request.getEndpoint().toString());
        token.put("method", request.getHttpMethod().toString());
        JSONArray headersJsonArray = new JSONArray();
        for (Map.Entry<String, String> header : request.getHeaders().entrySet()) {
            JSONObject headerJson = new JSONObject();
            headerJson.put("key", header.getKey());
            headerJson.put("value", header.getValue());
            headersJsonArray.put(headerJson);
        }
        token.put("headers", headersJsonArray);

        String encodedToken = token.toString();
        try {
            encodedToken = URLEncoder.encode(encodedToken, "UTF-8");
            System.out.println("URL encoded token: " + encodedToken);
        } catch (UnsupportedEncodingException e) {
            System.err.println("Error encoding the token"); 
            e.printStackTrace(); 
        }

        System.out.println("Token: " + token.toString());
        System.out.println("URL encoded token: " + encodedToken);

        return encodedToken;
    }

Possible Solution

One of our theories here is that our secret currently have a / in it. With that being passed in to the signer, is it possible that this is not being escaped and thus causing a signature mismatch?

Additional Information/Context

Here is the code that is generating this signature. I have been able to confirm the following:

  • The access key is getting fetched from the environment from the DefaultAWSCredentialsProviderChain.
  • The secret key is also getting fetched from the DefaultAWSCredentialsProviderChain.
  • We have the correct service accounts in our GCP instance as well as the mappings properly established.

We have this working correctly using BOTO in a Python service and that service is using the same credentials. This seems to be specific to Java and the Signer is our biggest suspect at the moment.

AWS Java SDK version used

2.20.158

JDK version used

11.0.16

Operating System and version

Mac OS 13.4.1 (22F82)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis issue is a bug.needs-triageThis issue or PR still needs to be triaged.p2This is a standard priority issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions