aws-sdk-js-v3 icon indicating copy to clipboard operation
aws-sdk-js-v3 copied to clipboard

sending GetApiKeyCommand with v3 APIGatewayClient from canary does not return the value

Open teijosol opened this issue 1 year ago • 5 comments

Checkboxes for prior research

Describe the bug

Hello

I am trying to get api key with v3 APIGatewayClient from a canary. The problem is that there is no value in the response. When using v2-version, this works as expected.

The canary runtime is Runtime.SYNTHETICS_NODEJS_PUPPETEER_6_2

SDK version number

@aws-sdk/[email protected]

Which JavaScript Runtime is this issue in?

Node.js

Details of the browser/Node.js/ReactNative version

node 18, the version that is used in canaries

Reproduction Steps

import { MediaType } from "@digitraffic/common/dist/aws/types/mediatypes";
import { APIGatewayClient, GetApiKeyCommand } from "@aws-sdk/client-api-gateway";

export const handler = async (): Promise<void> => {
    const client = new APIGatewayClient();
    const command = new GetApiKeyCommand({
        apiKey: "<keyId>",
        includeValue: true,
    });

    const response = await client.send(command);

    console.info("response " + JSON.stringify(response));
}

Observed Behavior

The response that gets printed, does not contain the actual key.

> {
    "$metadata": {
        "httpStatusCode": 200,
        "requestId": "<requestId>",
        "attempts": 1,
        "totalRetryDelay": 0
    }
}

Also, this gets printed:

Request: http://apigateway.eu-west-1.amazonaws.com/apikeys/<keyId>?includeValue=true

When using the v2, it's the same request but with https://

Expected Behavior

I expected this to work as in v2 and actually get the value of the api key.

Possible Solution

No response

Additional Information/Context

This looks like a similar problem: https://github.com/aws/aws-sdk-js-v3/issues/2352

teijosol avatar Mar 14 '24 11:03 teijosol

Hi @teijosol ,

Thanks for the reproduction steps.

I'm able to confirm that this is an issue. The part I'm also very curious about is that the request is sent via http when the SDK is actually sending the request as https.

I was able to confirm that the request sent by the SDK is actually https by doing the following:

Reproduction:

  1. Using a request middleware to intercept the request before its being sent:
const client = new APIGatewayClient({
    region: "us-east-1",
});

client.middlewareStack.add(next => async (args) => {
    console.info(args.request);
    const response = await next(args);
    return response;
}, { step: 'finalizeRequest' });

This will log the raw request as it being sent from the SDK, and will result in the following log:

INFO	HttpRequest {
  method: 'GET',
  hostname: 'apigateway.us-east-1.amazonaws.com',
  port: undefined,
  query: { includeValue: 'true' },
  headers: {
    accept: 'application/json',
    host: 'apigateway.us-east-1.amazonaws.com',
    'X-Amzn-Trace-Id': 'REDACTED,
    'x-amz-user-agent': 'aws-sdk-js/3.515.0',
    'user-agent': 'aws-sdk-js/3.515.0 ua/2.0 os/linux#4.14.255-336-277.563.amzn2.x86_64 lang/js md/nodejs#18.19.1 api/api-gateway#3.515.0 exec-env/AWS_Lambda_nodejs18.x',
    'amz-sdk-invocation-id': 'cff37ee7-94d8-4b35-8492-67eaf633f34f',
    'amz-sdk-request': 'attempt=1; max=3',
    'x-amz-date': '20240319T220336Z',
    'x-amz-security-token': 'REDACTED',
    'x-amz-content-sha256': 'REDACTED',
    authorization: 'AWS4-HMAC-SHA256 Credential=REDACTED/20240319/us-east-1/apigateway/aws4_request, SignedHeaders=accept;amz-sdk-invocation-id;amz-sdk-request;host;x-amz-content-sha256;x-amz-date;x-amz-security-token;x-amz-user-agent, Signature=REDACTED'
  },
  body: undefined,
  protocol: 'https:',    <-------- 
  path: '/apikeys/1cwlcueire',
  username: undefined,
  password: undefined,
  fragment: undefined
}
  1. Forcing the SDK to use a specific endpoint: in certain cases, the SDK endpoint resolution will result in some unexpected behavior, in those cases we can force the SDk to use an explicitly provided endpoint to ensure https:
const client = new APIGatewayClient({
    region: "us-east-1",
    endpoint: "https://apigateway.us-east-1.amazonaws.com"
});

But unfortunately this results in the same problem where the Canary sends the request using http, even though the request is sent by the SDK clearly as https.

More observations:

Sending this request locally, from a Node.JS application, results in the correct behavior without the need for any customization:

{
  '$metadata': {
    httpStatusCode: 200,
    requestId: 'REDACTED',
    extendedRequestId: undefined,
    cfId: undefined,
    attempts: 1,
    totalRetryDelay: 0
  },
  createdDate: 2024-03-19T19:19:17.000Z,
  enabled: true,
  id: '1cwlcueire',
  lastUpdatedDate: 2024-03-19T19:19:17.000Z,
  name: 'foo-apigw-key',
  stageKeys: [],
  tags: {},
  value: 'AVqfPdBADH3REDACTED'
}

Whereas forcing my local Node.JS application use an http endpoint, results in the application hanging until times out.

import { APIGatewayClient, GetApiKeyCommand }  from "@aws-sdk/client-api-gateway";

const client = new APIGatewayClient({
    region: "us-east-1",
    endpoint: "http://apigateway.us-east-1.amazonaws.com" // explicitly setting http protocol
});

    const command = new GetApiKeyCommand({
        apiKey: "1cwlcueire",
        includeValue: true,
    });

    const response = await client.send(command);
    console.info(response)

Conclusion: It seems to me that this is an issue with the Canary runtime itself, and not with the SDK because in isolation the SDK works fine.

Assigning to queue for further investigation.

Thanks, Ran~

RanVaknin avatar Mar 19 '24 22:03 RanVaknin

For what its worth, I'm seeing something similar for a call to cognito via the v3 sdk within a node canary runtime (7.0) - the reply indicates success (200 - OK) but the contents of the reply are missing - even though the cognito service does have the required changes applied indicating the command succeeded.

I have also seen evidence that this may have been around a long time : https://github.com/aws/aws-sdk-js-v3/issues/2352 which implies there is some other factor at play which is less obvious - otherwise more people between now and 2021 would have seen this issue.

elhedran avatar Jun 11 '24 01:06 elhedran

See also: https://github.com/aws/aws-sdk-js-v3/discussions/5299

elhedran avatar Jun 11 '24 01:06 elhedran

This work-around worked for me:

import { FetchHttpHandler } from '@smithy/fetch-http-handler'

// other code
    const cognitoIdentity = new CognitoIdentity({
        requestHandler: new FetchHttpHandler({})
    })

Basically: explicity forcing the SDK to use the web browser fetch handler rather than the http one. The underlying bug seems to be in an interaction between the AWS v3 SDK and Bun (specifically Bun's implementation of node:HTTP). This works around the issue by forcing use of fetch rather than node:http.

elhedran avatar Jun 11 '24 03:06 elhedran

I think I will have to try the work-around. It would be nice that this would be fixed, as V2 version is about to enter maintenance mode: https://aws.amazon.com/blogs/developer/announcing-end-of-support-for-aws-sdk-for-javascript-v2/

teijosol avatar Jun 25 '24 05:06 teijosol