sst / ion

❍ — a new engine for SST
https://ion.sst.dev
MIT License
1.09k stars 128 forks source link

sst.aws.ApiGatewayWebSocket seems to be missing a way to inject the managementEndpoint into the handlers, and also lacks AWS permissions to invoke it #411

Closed XaeroDegreaz closed 1 month ago

XaeroDegreaz commented 1 month ago

sst: ion (3.0.15)

I have an ApiGatewayWebSocket component defined:

const api = new sst.aws.ApiGatewayWebSocket( "MyApi")
api.route( "$connect", "lambda/handler.connect" );
api.route( "$disconnect", "lambda/handler.disconnect" );
api.route( "$default", "lambda/handler.defaultHandler" );

And a default handler:

export const defaultHandler: APIGatewayProxyHandler = async ( event ) => {
  const id = event.requestContext.connectionId;
  console.log( `Default: id:${id}` )

  //# I had to capture the management endpoint in the console output in order to statically place it here
  const api = new ApiGatewayManagementApi( {endpoint: "https://****.execute-api.us-east-1.amazonaws.com/$default"} )

  //# This fails because the ApiGatewayWebSocket is missing AWS permissions for 'execute-api:ManageConnections'
  await api.postToConnection( {ConnectionId: id, Data: JSON.stringify( {text: "received", timestamp: Date.now()} )} )
  return {
    statusCode: 200,
    body: "OK!"
  }
}
  1. There should be a way for the Lambda handlers to get access to their managementEndpoint. Simply using Resource.MyApi.managementResource inside the handler doesn't work because the componenent isn't 'linked' with itself.
  2. When creating the API gateway resources, the lambda should have the execute-api:ManageConnections permission so that it can send messages to clients.

I had to manually define the $default handler to include the permission, as well as an environment variable pointing to the managementEndpoint:

const api = new sst.aws.ApiGatewayWebSocket( "MyApi");
api.route( "$connect", "lambda/handler.connect" );
api.route( "$disconnect", "lambda/handler.disconnect" );
api.route( "$default", {
  handler: "lambda/handler.defaultHandler",
  permissions: [
    {
      actions: ['execute-api:ManageConnections'],
      //# It would be nice to be able to lock this down better...
      resources: ['arn:aws:execute-api:us-east-1:*']
    }
  ],
  environment: {
    MANAGEMENT_ENDPOINT: api.managementEndpoint
  }
} );

Documentation for the managementEndpoint does not seem to be correct:

image

I always get the error:

|  Error       
|  "MyApi" is not linked

in my terminal when running npm run dev

thdxr commented 1 month ago

you can specify the lambda handlers like this

api.route( "$connect", { handler: "lambda/handler.connect", link: [api] } );
XaeroDegreaz commented 1 month ago

I tried that before, and it still said the function was unlinked when attempting to access Resources.MyApi.managementEndpoint.

XaeroDegreaz commented 1 month ago

@thdxr

sst.config.ts

image

handler.ts

image

Error:

image
thdxr commented 1 month ago

i'm not sure yet - i implemented this exact thing a few days ago and it worked

XaeroDegreaz commented 1 month ago

Is there some special directory structure required in order for resources to be able to be passed, and a link recognized?