Skip to content

apigateway: Missing authorization on imported/referenced API Gateway #33053

Open
@ryancormack

Description

@ryancormack

Describe the bug

When 'importing' or referencing an existing Rest API Gateway using the fromRestApiAttributes method, the referenced Gateway is missing at least the default method authorization options.

When you define default method options

    const rootGateway = new api.RestApi(this, "api", {
      restApiName: "api",
      defaultMethodOptions: {
        authorizationType: api.AuthorizationType.COGNITO,
        authorizer: cognitoAuthorizer,
      },
    });

each route and method under that gateway, when in the same CF Stack will inherit these properties. In this example, if I wanted a public method, I would now have to explicitly make the route and method public.

But when referencing this Gateway via fromRestApiAttributes in a different CF Stack, and new route and method I make are public by default.

    const apiRoot = api.RestApi.fromRestApiAttributes(this, "RootGateway",
        {
          restApiId: ssm.StringParameter.valueForStringParameter(this, apiIdSsmKey),
          rootResourceId: ssm.StringParameter.valueForStringParameter(this, apiRootIdSsmKey),
        }
      );

Any method added to apiRoot is now public. This is different behaviour from adding a method/root in rootGateway.

In scenarios where people are building directly against an IRestApi it's not always obvious if it was referenced/imported or created as part of the same stack. This then requires people to specifically add an authorizer at each child set of routes. This is likely (possibly?) undesired behaviour when a Gateway team may own the central gateway and authorization logic and allow other teams to add their own routes to it.

If a team broken an existing API out into multiple stacks for any number of reasons, referencing the parent gateway would now cause a change to the authorization/authentication logic which wouldn't be desirable.

Regression Issue

  • Select this option if this issue appears to be a regression.

Last Known Working CDK Version

No response

Expected Behavior

The IRestApi returned from RestApi.fromRestApiAttributes across stacks has the same behaviour and properties as the IRestApi created in the same stack. All default options should be inherited by the new child providing consistent behavior regardless of where the gateway was first defined.

Current Behavior

The IRestApi returned from RestApi.fromRestApiAttributes is missing at least the authentication properties from the parent gateway. This results API Methods added to an IRestApi having different behaviour depending on where the IRestApi comes from

Reproduction Steps

Repo with repro CF Stacks https://github.com/ryancormack/cdk-api-gw-auth-bug

Current behaviour:

Method on root stack:
Image

Method on 'child' stack

Image

Both of these routes get created with the same code

private const IRestApi api;

this.api.addResource("should-be-private") //could be any route
      .addMethod(
        "ANY",
        new api.MockIntegration({
          integrationResponses: [{ statusCode: "200" }],
          passthroughBehavior: api.PassthroughBehavior.NEVER,
          requestTemplates: { "application/json": '{ "statusCode": 200 }' },
        }),
        { methodResponses: [{ statusCode: "200" }] }
      );

Possible Solution

I think the issue may originate from https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/aws-apigateway/lib/restapi.ts#L798

  /**
   * Import an existing RestApi that can be configured with additional Methods and Resources.
   */
  public static fromRestApiAttributes(scope: Construct, id: string, attrs: RestApiAttributes): IRestApi {
    class Import extends RestApiBase {
      public readonly restApiId = attrs.restApiId;
      public readonly restApiName = attrs.restApiName ?? id;
      public readonly restApiRootResourceId = attrs.rootResourceId;
      public readonly root: IResource = new RootResource(this, {}, this.restApiRootResourceId);
    }

    return new Import(scope, id);
  }

The second value passed to the RootResource is the ResourceOptions which then get used to populate things like the MethodOptions

//rest
  constructor(api: RestApiBase, props: ResourceOptions, resourceId: string) {
    super(api, 'Default');

    this.parentResource = undefined;
    this.defaultIntegration = props.defaultIntegration;
    this.defaultMethodOptions = props.defaultMethodOptions;
    this.defaultCorsPreflightOptions = props.defaultCorsPreflightOptions;
    this.api = api;
    this.resourceId = resourceId;
    this.path = '/';

//rest

As a solution, fromRestApiAttributes could be extended to be able to pass these props through, or take a value to "inherit default options" from a parent gateway

Additional Information/Context

No response

CDK CLI Version

2.173.2

Framework Version

No response

Node.js Version

22

OS

OSx latest

Language

TypeScript

Language Version

No response

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    @aws-cdk/aws-apigatewayRelated to Amazon API GatewaybugThis issue is a bug.effort/mediumMedium work item – several days of effortp2

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions