Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(apigatewayv2): grant permissions for sending messages to a WebSocket #14828

Closed
2 tasks
adam-nielsen opened this issue May 21, 2021 · 5 comments · Fixed by #16872
Closed
2 tasks

(apigatewayv2): grant permissions for sending messages to a WebSocket #14828

adam-nielsen opened this issue May 21, 2021 · 5 comments · Fixed by #16872
Labels
@aws-cdk/aws-apigatewayv2 Related to Amazon API Gateway v2 effort/small Small work item – less than a day of effort feature-request A feature should be added or improved. p2

Comments

@adam-nielsen
Copy link

I have a Lambda function and I want it to be able to post messages to a WebSocket. There doesn't seem to be a websocket.grantPost(lambda.role) or equivalent like there is for other resources like S3 buckets, so my Lambda always fails with 403 Forbidden when I try to send messages to the WebSocket.

Use Case

I have a Lambda that is invoked via other means not related to the WebSocket, but I want to grant it permission to send messages to clients connected to the WebSocket.

Proposed Solution

Add a grantPost() or similar function to the WebSocketApi class, to provide functionality equivalent to S3.Bucket.grantPut(), DynamoDB.Table.grantReadWriteData(), etc. but for granting permission to post messages to WebSockets.

  • 👋 I may be able to implement this feature request
  • ⚠️ This feature might incur a breaking change

This is a 🚀 Feature Request

@adam-nielsen adam-nielsen added feature-request A feature should be added or improved. needs-triage This issue or PR still needs to be triaged. labels May 21, 2021
@github-actions github-actions bot added the @aws-cdk/aws-apigatewayv2 Related to Amazon API Gateway v2 label May 21, 2021
@nija-at
Copy link
Contributor

nija-at commented May 24, 2021

@adam-nielsen - what exact permissions would such a method add to the Principal?
It would be useful if you can describe or point to documentation.

@nija-at nija-at added the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label May 24, 2021
@adam-nielsen
Copy link
Author

@nija-at Thanks for your quick response! It looks like the permissions are described here:

https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-control-access-iam.html

If I grant this permission then my Lambda function is able to send messages to the WebSocket:

const cdkApiGateway = require('@aws-cdk/aws-apigatewayv2');
const webSocketApi = new cdkApiGateway.WebSocketApi(this, ...);
const webSocketStage = new cdkApiGateway.WebSocketStage(this, 'ws-stage', { webSocketApi });

myLambda.addToRolePolicy(new cdkIAM.PolicyStatement({
	resources: [
		`arn:aws:execute-api:*:*:${webSocketApi.apiId}/${webSocketStage.stageName}/*/*`
	],
	actions: [
		'execute-api:ManageConnections',
	],
}));

Since the API ID is randomly generated, it needs to retrieve the API ID from the WebSocketApi instance as it will change each time the stack is deployed to a new environment. It also uses the stage name from the WebSocketStage instance just for the sake of granting the minimum permissions required. I believe you can access the WebSocketApi object from within WebSocketStage, so presumably something like WebSocketStage.grantPostToConnection(Role) would have access to the needed information.

This permission is required in order to send a PostToConnectionCommand from @aws-sdk/client-apigatewaymanagementapi.

You can also test the permission from the command line with:

aws apigatewaymanagementapi post-to-connection --connection-id 12345 --data "Test" --endpoint-url https://<api-id>.execute-api.ap-southeast-2.amazonaws.com/<stage>

You should get back a 'Gone' or 'NotFound' error (since the connection ID is invalid) however without the above permission you will get an Access Denied error instead.

@nija-at
Copy link
Contributor

nija-at commented May 24, 2021

Awesome. Thanks for all the details @adam-nielsen.

I'm marking this issue as a p2 since you have a workaround for this, and shouldn't be blocking anyone. We are unable to work on p2 issues at the moment and this will be filed into our backlog.

We're accepting pull requests if you or anyone else is interested in implementing this.

@nija-at nija-at added effort/small Small work item – less than a day of effort p2 and removed needs-triage This issue or PR still needs to be triaged. response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. labels May 24, 2021
@nija-at nija-at changed the title (apigatewayv2): no way of granting permissions for sending messages to a WebSocket (apigatewayv2): grant permissions for sending messages to a WebSocket May 24, 2021
@douglasnaphas
Copy link
Contributor

I'm working on a PR to implement this feature.

@mergify mergify bot closed this as completed in #16872 Nov 9, 2021
mergify bot pushed a commit that referenced this issue Nov 9, 2021
closes #14828

By this PR, we can allow access to management API by the following code.

```ts
    const api = new WebSocketApi(stack, 'Api');
    const defaultStage = new WebSocketStage(stack, 'Stage', {
      webSocketApi: api,
      stageName: 'dev',
    });
    const principal = new User(stack, 'User');

    api.grantManagementApiAccess(principal); // allow access to the management API for all the stage
    defaultStage.grantManagementApiAccess(principal); // allow access to the management API for a specific stage
```

We use WebSocket API Management API to send messages to a WebSocket API. [(doc)](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-how-to-call-websocket-api-connections.html) To use the API, we must set IAM statement as below [(doc)](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-control-access-iam.html):

```json
    {
      "Effect": "Allow",
      "Action": [
        "execute-api:ManageConnections"           
      ],
      "Resource": [
        "arn:aws:execute-api:us-east-1:account-id:api-id/stage-name/POST/@connections/*"
      ]
    }
``` 

We need `/*` at the end of resource ARN because there will be arbitrary strings (`connectionId`).
i.e. `{apiArn}/{stageName}/POST/@connections/{connectionId}`

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
@github-actions
Copy link

github-actions bot commented Nov 9, 2021

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

TikiTDO pushed a commit to TikiTDO/aws-cdk that referenced this issue Feb 21, 2022
closes aws#14828

By this PR, we can allow access to management API by the following code.

```ts
    const api = new WebSocketApi(stack, 'Api');
    const defaultStage = new WebSocketStage(stack, 'Stage', {
      webSocketApi: api,
      stageName: 'dev',
    });
    const principal = new User(stack, 'User');

    api.grantManagementApiAccess(principal); // allow access to the management API for all the stage
    defaultStage.grantManagementApiAccess(principal); // allow access to the management API for a specific stage
```

We use WebSocket API Management API to send messages to a WebSocket API. [(doc)](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-how-to-call-websocket-api-connections.html) To use the API, we must set IAM statement as below [(doc)](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-control-access-iam.html):

```json
    {
      "Effect": "Allow",
      "Action": [
        "execute-api:ManageConnections"           
      ],
      "Resource": [
        "arn:aws:execute-api:us-east-1:account-id:api-id/stage-name/POST/@connections/*"
      ]
    }
``` 

We need `/*` at the end of resource ARN because there will be arbitrary strings (`connectionId`).
i.e. `{apiArn}/{stageName}/POST/@connections/{connectionId}`

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-apigatewayv2 Related to Amazon API Gateway v2 effort/small Small work item – less than a day of effort feature-request A feature should be added or improved. p2
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants