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

feat(apigatewayv2): add aws service integration -- step functions #14498

Closed
wants to merge 1 commit into from

Conversation

zxkane
Copy link
Contributor

@zxkane zxkane commented May 3, 2021

  • general changes for supporting aws integration
  • add StepFunctions StartExecution and StartSyncExecution implementation

closes #11947


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@gitpod-io
Copy link

gitpod-io bot commented May 3, 2021

@github-actions github-actions bot added @aws-cdk/aws-apigatewayv2 Related to Amazon API Gateway v2 @aws-cdk/aws-stepfunctions Related to AWS StepFunctions labels May 3, 2021
@nija-at nija-at added effort/medium Medium work item – several days of effort p2 and removed @aws-cdk/aws-stepfunctions Related to AWS StepFunctions labels May 10, 2021
@nija-at
Copy link
Contributor

nija-at commented May 10, 2021

Thanks so much for submitting this pull request. I am marking this pull request as p2, which means that we are unable to work on it immediately, but it's definitely still on our radar.

We use +1s to help prioritize our work, and are happy to revaluate this pull request based on community feedback. You can reach out to the cdk.dev community on Slack to solicit support for reprioritization.

@saqibdhuka
Copy link
Contributor

This is a good feature.

I was testing it out with a EXPRESS Synchronous State Machine and the following bug was found:

Environment
Testing it on Linux OS
Software: Visual Studo Code
Language: Typescript

Steps to reproduce the bug

  1. Set up the State Machine to be of type EXPRESS and set it as a Pass State Machine with result value: "Hello"
  2. Use StepFunctionsStartSyncExecutionIntegration within api.addRoutes()
  3. Set input parameter within the integration to be '{"test":"out"}' (with single quotations)
  4. Deploy the CDK Stack
  5. Ue "curl -X POST <invoke URL>/start" (without quotations)

Code to reproduce the bug
`

const passTask2 = new sfn.Pass(this, 'passTask2', {
  result: { value: "Hello" },
});

const handler: sfn.IStateMachine = new sfn.StateMachine(this, 'handler', {
  definition: passTask2,
  stateMachineType: sfn.StateMachineType.EXPRESS,
});

//Step Functions IAM Role
const stepFunctionRole = new iam.Role(this, "sfnRole", {
  assumedBy: new iam.ServicePrincipal("apigateway.amazonaws.com"),
  inlinePolicies: {
    AllowSFNExec: new iam.PolicyDocument({
      statements: [
        new iam.PolicyStatement({
          actions: ["states:StartSyncExecution"],
          effect: iam.Effect.ALLOW,
          resources: [handler.stateMachineArn]
        })
      ]
    })
  }
});

const api = new apigwv2.HttpApi(this, 'HttpApiEndpoint');

api.addRoutes({
  path: '/start',
  methods: [ apigwv2.HttpMethod.POST ],
  integration: new StepFunctionsStartSyncExecutionIntegration({
    stateMachine: handler,
    input: '{"test":"out"}',
  }),
});

`

Expected Output
The expected output is to have state machine output ("Hello) along with billing details and other information

Actual Result
Permission Error: Access Denied Exception
{"__type":"com.amazon.coral.service#AccessDeniedException","Message":"User: arn:aws:sts::123456789102:assumed-role/DemoCdkStack-HttpApiEndpointPOSTstartRoleF1234567-xxxxxxxx/xxxxxxx is not authorized to perform: states:StartSyncExecution on resource: arn:aws:states:us-west-2:123456789102:stateMachine:handlerExxxxxxx-xxxxxxxx because no identity-based policy allows the states:StartSyncExecution action"}%

Visual Proof
Screen Shot 2021-09-27 at 11 24 53 AM

Severity
Medium - EXPRESS State Machine invocation is not working with StartSyncExecution

Fix
I was able to fix the bug by doing the following:

  1. From your stack, pass stack into the StepFunctionsStartSyncExecutionIntegration as the Construct.
  2. Edit the StepFunctionsStartSyncExecutionIntegration cosntructor to accept a Construct ( private readonly _scope: Construct )
  3. Change the _fulfillRole function implementation to do the following:
    - Change 'this._props.stateMachine.grantStartExecution' to 'this._props.stateMachine.grantExecution(credentialsRole.grantPrincipal, 'states:StartSyncExecution')'
    - Next use credentialsRole.attachInlinePolicy() and add IAM Policy with PolicyStatement (with 'states:StartSyncExecution' as the actions) along with other parameters. You will need to pass the Construct (_scope) into the attachInlinePolicy().

This should fix the bug.

I would suggest looking into StepFunctionsStartExecutionIntegration implementation too as I dd not see any attached policy and I'm not sure if it works correctly or not.

@zxkane
Copy link
Contributor Author

zxkane commented Sep 28, 2021

This is a good feature.

I was testing it out with a EXPRESS Synchronous State Machine and the following bug was found:

Environment
Testing it on Linux OS
Software: Visual Studo Code
Language: Typescript

Steps to reproduce the bug

  1. Set up the State Machine to be of type EXPRESS and set it as a Pass State Machine with result value: "Hello"
  2. Use StepFunctionsStartSyncExecutionIntegration within api.addRoutes()
  3. Set input parameter within the integration to be '{"test":"out"}' (with single quotations)
  4. Deploy the CDK Stack
  5. Ue "curl -X POST /start" (without quotations)

Code to reproduce the bug
`

const passTask2 = new sfn.Pass(this, 'passTask2', {
  result: { value: "Hello" },
});

const handler: sfn.IStateMachine = new sfn.StateMachine(this, 'handler', {
  definition: passTask2,
  stateMachineType: sfn.StateMachineType.EXPRESS,
});

//Step Functions IAM Role
const stepFunctionRole = new iam.Role(this, "sfnRole", {
  assumedBy: new iam.ServicePrincipal("apigateway.amazonaws.com"),
  inlinePolicies: {
    AllowSFNExec: new iam.PolicyDocument({
      statements: [
        new iam.PolicyStatement({
          actions: ["states:StartSyncExecution"],
          effect: iam.Effect.ALLOW,
          resources: [handler.stateMachineArn]
        })
      ]
    })
  }
});

const api = new apigwv2.HttpApi(this, 'HttpApiEndpoint');

api.addRoutes({
  path: '/start',
  methods: [ apigwv2.HttpMethod.POST ],
  integration: new StepFunctionsStartSyncExecutionIntegration({
    stateMachine: handler,
    input: '{"test":"out"}',
  }),
});

`

Expected Output
The expected output is to have state machine output ("Hello) along with billing details and other information

Actual Result
Permission Error: Access Denied Exception
{"__type":"com.amazon.coral.service#AccessDeniedException","Message":"User: arn:aws:sts::123456789102:assumed-role/DemoCdkStack-HttpApiEndpointPOSTstartRoleF1234567-xxxxxxxx/xxxxxxx is not authorized to perform: states:StartSyncExecution on resource: arn:aws:states:us-west-2:123456789102:stateMachine:handlerExxxxxxx-xxxxxxxx because no identity-based policy allows the states:StartSyncExecution action"}%

Visual Proof
Screen Shot 2021-09-27 at 11 24 53 AM

Severity
Medium - EXPRESS State Machine invocation is not working with StartSyncExecution

Fix
I was able to fix the bug by doing the following:

  1. From your stack, pass stack into the StepFunctionsStartSyncExecutionIntegration as the Construct.
  2. Edit the StepFunctionsStartSyncExecutionIntegration cosntructor to accept a Construct ( private readonly _scope: Construct )
  3. Change the _fulfillRole function implementation to do the following:
    • Change 'this._props.stateMachine.grantStartExecution' to 'this._props.stateMachine.grantExecution(credentialsRole.grantPrincipal, 'states:StartSyncExecution')'
    • Next use credentialsRole.attachInlinePolicy() and add IAM Policy with PolicyStatement (with 'states:StartSyncExecution' as the actions) along with other parameters. You will need to pass the Construct (_scope) into the attachInlinePolicy().

This should fix the bug.

I would suggest looking into StepFunctionsStartExecutionIntegration implementation too as I dd not see any attached policy and I'm not sure if it works correctly or not.

Thanks for your deep dive the exception and proposed fix.

Will keep an eye on it due to the CDK team does not have review bandwidth.

saqibdhuka pushed a commit to zxkane/aws-cdk that referenced this pull request Sep 29, 2021
…cutionIntegration fixed to attach Inline Policy for credentialsRole. Fixed README to change input for correct input passing. Fixed Unit and Integration tests. All tests passing. Permissions bug mentioned in the PR is now fixed. Fix Bug awsGH-14498."
@saqibdhuka
Copy link
Contributor

This is a good feature.

I was testing it out with a EXPRESS Synchronous State Machine and the following bug was found:

Environment Testing it on Linux OS Software: Visual Studo Code Language: Typescript

Steps to reproduce the bug

1. Set up the State Machine to be of type EXPRESS and set it as a Pass State Machine with result value: "Hello"

2. Use StepFunctionsStartSyncExecutionIntegration within api.addRoutes()

3. Set input parameter within the integration to be '{"test":"out"}' (with single quotations)

4. Deploy the CDK Stack

5. Ue "curl -X POST <invoke URL>/start" (without quotations)

Code to reproduce the bug `

const passTask2 = new sfn.Pass(this, 'passTask2', {
  result: { value: "Hello" },
});

const handler: sfn.IStateMachine = new sfn.StateMachine(this, 'handler', {
  definition: passTask2,
  stateMachineType: sfn.StateMachineType.EXPRESS,
});

//Step Functions IAM Role
const stepFunctionRole = new iam.Role(this, "sfnRole", {
  assumedBy: new iam.ServicePrincipal("apigateway.amazonaws.com"),
  inlinePolicies: {
    AllowSFNExec: new iam.PolicyDocument({
      statements: [
        new iam.PolicyStatement({
          actions: ["states:StartSyncExecution"],
          effect: iam.Effect.ALLOW,
          resources: [handler.stateMachineArn]
        })
      ]
    })
  }
});

const api = new apigwv2.HttpApi(this, 'HttpApiEndpoint');

api.addRoutes({
  path: '/start',
  methods: [ apigwv2.HttpMethod.POST ],
  integration: new StepFunctionsStartSyncExecutionIntegration({
    stateMachine: handler,
    input: '{"test":"out"}',
  }),
});

`

Expected Output The expected output is to have state machine output ("Hello) along with billing details and other information

Actual Result Permission Error: Access Denied Exception {"__type":"com.amazon.coral.service#AccessDeniedException","Message":"User: arn:aws:sts::123456789102:assumed-role/DemoCdkStack-HttpApiEndpointPOSTstartRoleF1234567-xxxxxxxx/xxxxxxx is not authorized to perform: states:StartSyncExecution on resource: arn:aws:states:us-west-2:123456789102:stateMachine:handlerExxxxxxx-xxxxxxxx because no identity-based policy allows the states:StartSyncExecution action"}%

Visual Proof Screen Shot 2021-09-27 at 11 24 53 AM

Severity Medium - EXPRESS State Machine invocation is not working with StartSyncExecution

Fix I was able to fix the bug by doing the following:

1. From your stack, pass stack into the StepFunctionsStartSyncExecutionIntegration as the Construct.

2. Edit the StepFunctionsStartSyncExecutionIntegration cosntructor to accept a Construct ( private readonly _scope: Construct )

3. Change the _fulfillRole function implementation to do the following:
   - Change 'this._props.stateMachine.grantStartExecution' to 'this._props.stateMachine.grantExecution(credentialsRole.grantPrincipal, 'states:StartSyncExecution')'
   - Next use credentialsRole.attachInlinePolicy() and add IAM Policy with PolicyStatement (with 'states:StartSyncExecution' as the actions) along with other parameters. You will need to pass the Construct (_scope) into the attachInlinePolicy().

This should fix the bug.

I would suggest looking into StepFunctionsStartExecutionIntegration implementation too as I dd not see any attached policy and I'm not sure if it works correctly or not.

The bug is now fixed!!

@saqibdhuka saqibdhuka force-pushed the apiv2-aws-integration branch 2 times, most recently from 711b6cb to 16447ea Compare October 2, 2021 00:04
Comment on lines +53 to +70
* The StepFunctions-StartExecution integration resource for HTTP API
*/
export class StepFunctionsStartExecutionIntegration extends StepFunctionsIntegration {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one says StartExecution but later on L79 you are giving permission to StartSyncExecution.

Also resources [*] should be avoided if you have the state machine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good Note. I will fix this. Thank you

Comment on lines 75 to 100
credentialsRole.attachInlinePolicy(
new iam.Policy(this._scope, 'AllowSfnSyncExec', {
statements: [
new iam.PolicyStatement({
actions: ['states:StartSyncExecution'],
effect: iam.Effect.ALLOW,
resources: ['*'],
}),
],
}),
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should be removed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This attaches the policy and fixes the permission bug mentioned above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but this is for StartExecution, not StartSyncExecution right? They are different constructs and therefore requires different permissions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes I have fixed that in the push

*/
protected _fulfillRole(credentialsRole: iam.IRole): void {

this._props.stateMachine.grantExecution(credentialsRole.grantPrincipal, 'states:StartSyncExecution');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please clarify what is this line of code doing?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It grants the execution permission, but does not attach the policy. That needs to be done explicitly.

new iam.PolicyStatement({
actions: ['states:StartSyncExecution'],
effect: iam.Effect.ALLOW,
resources: ['*'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe permission to * should be avoided as you have the state machine. It should give permission only to the state machine ARN as a best practice (least privilege).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that is correct. I will fix this. Thank you.

*
* @default - undefined
*/
readonly traceHeader?: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't StartExecution also accepts a traceheader?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it does.


public bind(_options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig {

const role = new Role(_options.scope, 'Role', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be called ApiGatewayIntegrationRole?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I will fix that

@diegotry
Copy link
Contributor

diegotry commented Oct 2, 2021

I believe the template files should be removed from your request.

@saqibdhuka saqibdhuka force-pushed the apiv2-aws-integration branch 3 times, most recently from b73875a to 6551bec Compare October 2, 2021 01:24
Copy link
Contributor

@diegotry diegotry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a bunch of files that are not related to your change. Example: Lambda Hot swap


public bind(_options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig {

const ApiGatewayIntegrationRole = new Role(_options.scope, 'ApiGatewayIntegrationRole', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should be lowercase.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will fix that

PayloadFormatVersion: '1.0',
RequestParameters: {
StateMachineArn: {
Ref: 'MyStateMachine6C968CA5',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this should be the state machine arn instead of the resource. Did it work if you try to deploy?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope it does not work. it needs the resource.

Comment on lines 64 to 89
expect(stack).toHaveResource('AWS::ApiGatewayV2::Integration', {
IntegrationType: 'AWS_PROXY',
IntegrationSubtype: 'StepFunctions-StartSyncExecution',
PayloadFormatVersion: '1.0',
RequestParameters: {
StateMachineArn: {
Ref: 'MyStateMachine6C968CA5',
},
Input: {
a: 'b',
},
},
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should you validate if the other resources are also created? The IAM Role for example

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IAM Role did not show up in the properties when testing, but I will add more extended tests for both.

Comment on lines 20 to 26
const endpoint = new HttpApi(stack, 'AwsIntegrationApi', {
defaultIntegration: new StepFunctionsStartExecutionIntegration(stack, {
stateMachine: state,
input: '$request.body',
}),
});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this include some assertions? What is this test file doing?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is integration testing. While testing, it validates the test against expected json.

Comment on lines 20 to 25
const endpoint = new HttpApi(stack, 'AwsIntegrationApi', {
defaultIntegration: new StepFunctionsStartSyncExecutionIntegration(stack, {
stateMachine: state,
input: '$request.body',
}),
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same question as above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is integration testing. While testing, it validates the test against expected json.

@saqibdhuka saqibdhuka force-pushed the apiv2-aws-integration branch from 6551bec to 009114d Compare October 2, 2021 23:17
nija-at
nija-at previously requested changes Oct 7, 2021
Copy link
Contributor

@nija-at nija-at left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. This PR is changing unrelated files and has merge conflicts. Please update the PR to the latest master and make sure only the necessary changes are here.

  2. Please add a section to the README with a sample usage.

@saqibdhuka saqibdhuka force-pushed the apiv2-aws-integration branch from 009114d to afc9ef9 Compare October 7, 2021 16:38
@mergify mergify bot dismissed nija-at’s stale review October 7, 2021 16:39

Pull request has been modified.

@saqibdhuka saqibdhuka force-pushed the apiv2-aws-integration branch from afc9ef9 to 0a6a1b1 Compare October 14, 2021 00:00
@saqibdhuka saqibdhuka force-pushed the apiv2-aws-integration branch 3 times, most recently from 98e87a2 to a50b049 Compare October 14, 2021 17:40
@saqibdhuka saqibdhuka force-pushed the apiv2-aws-integration branch from a50b049 to 9c04142 Compare November 4, 2021 17:33
…ncExecutionIntegration.

Added unit and integration tests.
Fixed issues mentioned in the Pull-request.
Added example to README
Fixed unit test

closes aws#11947.
@saqibdhuka saqibdhuka force-pushed the apiv2-aws-integration branch from 9c04142 to 1e2999c Compare November 4, 2021 18:46
@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject89A8053A-LhjRyN9kxr8o
  • Commit ID: 1e2999c
  • Result: FAILED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@rix0rrr rix0rrr added feature-request A feature should be added or improved. p2 and removed p2 effort/medium Medium work item – several days of effort @aws-cdk/aws-apigatewayv2 Related to Amazon API Gateway v2 feature-request A feature should be added or improved. labels Mar 4, 2022
@TheRealAmazonKendra
Copy link
Contributor

This PR has been deemed to be abandoned, and will be closed. Please create a new PR for these changes if you think this decision has been made in error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

(aws-apigatewayv2-integrations): integration sub type - step functions
8 participants