aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.59k stars 3.89k forks source link

aws-apigatewayv2-authorizers: Expose the node or HttpAuthorizer resource for dependency management #28061

Open WilliamABradley opened 10 months ago

WilliamABradley commented 10 months ago

Describe the feature

Expose the Node construct of the Authorizer for HttpJwtAuthorizer and the other authorizers in the @aws-cdk/aws-apigatewayv2-authorizers-alpha package.

Use Case

This is only really an issue for the JWT authorizer resources, and if you are self exposing the openid configuration via the same API Gateway, as at creation time, it calls the /.well-known/openid-configuration endpoint, and you get the following error:

Error: Invalid issuer: https://{DOMAIN}. Issuer must have a valid discovery endpoint ended with '/.well-known/openid-configuration'

There is a workaround:

  const certificate = new aws_certificatemanager.Certificate(
    stack,
    "Certificate",
    {
      domainName: fqdn,
      certificateName: fqdn,
      validation: aws_certificatemanager.CertificateValidation.fromDns(zone),
    }
  );

  const domain = new aws_apigatewayv2.DomainName(stack, "Domain", {
    domainName: fqdn,
    certificate,
  });

  const api = new aws_apigatewayv2.HttpApi(stack, "Api", {
    apiName: fqdn,
    defaultDomainMapping: {
      domainName: domain,
    },
    corsPreflight: {
      allowMethods: [
        aws_apigatewayv2.CorsHttpMethod.GET,
        aws_apigatewayv2.CorsHttpMethod.POST,
        aws_apigatewayv2.CorsHttpMethod.OPTIONS,
      ],
      allowOrigins: [
        `https://dashboard.${zone.zoneName}`,
        "http://localhost:5173",
      ],
      allowHeaders: ["content-type"],
      maxAge: Duration.days(10),
    },
  });
  const dnsRecord = new aws_route53.ARecord(stack, "ARecord", {
    zone,
    recordName: fqdn,
    target: aws_route53.RecordTarget.fromAlias(
      new aws_route53_targets.ApiGatewayv2DomainProperties(
        domain.regionalDomainName,
        domain.regionalHostedZoneId
      )
    ),
  });

  const integration = new aws_apigatewayv2_integrations.HttpLambdaIntegration(
    "ApiIntegration",
    apiLambda,
    {
      payloadFormatVersion: aws_apigatewayv2.PayloadFormatVersion.VERSION_2_0,
    }
  );

  const [openIdRoute] = api.addRoutes({
    path: "/.well-known/openid-configuration",
    methods: [aws_apigatewayv2.HttpMethod.GET],
    integration,
  });
  const [jwksRoute] = api.addRoutes({
    path: "/.well-known/jwks.json",
    methods: [aws_apigatewayv2.HttpMethod.GET],
    integration,
  });

  // Routes for Authentication, no auth required
  api.addRoutes({
    path: "/auth/rpc",
    methods: [aws_apigatewayv2.HttpMethod.POST],
    integration,
  });

  // Authenticated Routes, requires JWT Bearer token
  const authorizer = new aws_apigatewayv2_authorizers.HttpJwtAuthorizer(
    "Authorizer",
    authUrl,
    {
      authorizerName: "jwt-authorizer",
      jwtAudience: [authUrl],
      identitySource: ["$request.header.Authorization"],
    }
  );
  api.addRoutes({
    path: "/rpc",
    methods: [aws_apigatewayv2.HttpMethod.POST],
    integration,
    authorizer,
    authorizationScopes: ["authorized"],
  });

  // We can't create the authorized routes until the config routes are created
  // This doesn't exist until used in a route, which is created via bind().
  const authorizerResource: aws_apigatewayv2.HttpAuthorizer =
    // @ts-expect-error Not exposed for dependency
    authorizer.authorizer;

  // We need the lambda to be reachable before creating the JWT Authorizer
  authorizerResource.node.addDependency(dnsRecord, openIdRoute, jwksRoute);

Proposed Solution

No response

Other Information

No response

Acknowledgements

CDK version used

2.110.0 + @aws-cdk/aws-apigatewayv2-*: ^2.110.0-alpha.0

Environment details (OS name and version, etc.)

Windows 11 Pro Insider 25992

pahud commented 10 months ago

Thank you for this workaround.