Problem with cross-account IAM-authorized HTTP API Gateway

0

I have created, as per the CDK example at this link, an HTTP API Gateway protected by IAM authorizers. However, I cannot get any requests to pass through it.

The producer lambda function simply returns a Harry Potter title and is omitted for brevity.

Here is the CDK code deployed to the producer account:

const authorizer = new authorizers.HttpIamAuthorizer();

    const booksFunction = new lambda.Function(this, "BooksFunction", {
      runtime: lambda.Runtime.NODEJS_18_X,
      code: lambda.Code.fromAsset(
        path.join(__dirname, "..", "handlers", "books")
      ),
      handler: "books.handler",
    });

    const booksIntegration = new integrations.HttpLambdaIntegration(
      "LambdaIntegration",
      booksFunction
    );

    const principal = new iam.AccountPrincipal("CONSUMER_ACCOUNT_ID");

    const httpApi = new apigwv2.HttpApi(this, "HttpProxyApi", {
      createDefaultStage: true,
      defaultAuthorizer: authorizer,
    });

    const routes = httpApi.addRoutes({
      integration: booksIntegration,
      methods: [apigwv2.HttpMethod.GET],
      path: "/books",
      // authorizer,
    });

    routes[0].grantInvoke(principal);

I tried adding a stage and CORS options to it, but no difference.

My lambda on the consumer account has the required privileges to invoke our API gateway. Here's the CDK code:

    const lambdaRole = new iam.Role(this, "Role", {
      roleName: "example-role",
      assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
    });

    lambdaRole.addToPolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: ["execute-api:Invoke"],
        resources: [
          this.formatArn({
            account: "PRODUCER_ACCOUNT_ID",
            service: "execute-api",
            resource: "API_NAME",
            resourceName: "*",
          }),
        ],
      })
    );

    const booksFunction = new nodejs.NodejsFunction(this, "GetBookFunction", {
      runtime: lambda.Runtime.NODEJS_18_X,
      entry: path.join(__dirname, "..", "handlers", "get_book", "get_book.ts"),
      handler: "handler",
      role: lambdaRole,
      bundling: {
        nodeModules: ["@aws-crypto/sha256-js", "url"],
      },
    });
  }

The consumer function signs requests with v4 signatures:

const v4 = new SignatureV4({
  service: "execute-api",
  region: process.env.AWS_DEFAULT_REGION || "",
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID || "",
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || "",
    sessionToken: process.env.AWS_SESSION_TOKEN || "",
  },
  sha256: Sha256,
});

const signRequest = async (request: HttpRequest): Promise<HttpRequest> => {
  const signedRequest = await v4.sign(request);
  return signedRequest;
};

export const handler = async (event, context) => {
  const url = new URL(
    "https://API_ID.execute-api.us-east-1.amazonaws.com/books"
  );
  const request = new HttpRequest({
    hostname: url.host,
    method: "GET",
    headers: {
      host: url.host,
    },
    path: url.pathname,
  });
  const results: Record<string, any> = {
    error: {},
    response: {},
  };
  try {
    const signedRequest = await signRequest(request);
    const response = await fetch(url.href, signedRequest);
    const responseJson = await response.json();
    results.response = responseJson;
  } catch (e) {
    results.error = e;
  }
  return results;
};

Calling producer's API Gateway from the consumer lambda returns:

{
  "error": {},
  "response": {
    "message": "Forbidden"
  }
}

This message means an exception didn't occur.

I can also confirm via logging that the API Gateway is being hit, but it returns a 403 forbidden error.

What am I doing wrong here? I'm at my wits' end.

1개 답변
0

It seems as if you try to use the consumer Lambda execution directly to invoke the API. This is possible in REST APIs (with according permissions in the API Gateway's resource policy), but doesn't work for HTTP APIs. Here, you need to assume a role in your producer account to fulfill the requirements of your IAM authorizer.

You can find a step-by-step guide in this knowledge base article. Hope that helps!

profile pictureAWS
Michael
답변함 5달 전

로그인하지 않았습니다. 로그인해야 답변을 게시할 수 있습니다.

좋은 답변은 질문에 명확하게 답하고 건설적인 피드백을 제공하며 질문자의 전문적인 성장을 장려합니다.

질문 답변하기에 대한 가이드라인