From ecb59fda50078e29d579b7b0ee82600f553aec75 Mon Sep 17 00:00:00 2001 From: Otavio Macedo <288203+otaviomacedo@users.noreply.github.com> Date: Fri, 19 May 2023 19:57:20 +0100 Subject: [PATCH] feat(apigateway): add grantExecute to API Methods (#25630) To grant permission to a user: ```ts const books = api.root.addResource('books'); books.grantExecute(user); ``` Closes https://github.com/aws/aws-cdk/issues/5198. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../GrantExecute.assets.json | 19 + .../GrantExecute.template.json | 179 +++++++++ ...efaultTestDeployAssertA66B6F20.assets.json | 19 + ...aultTestDeployAssertA66B6F20.template.json | 36 ++ .../cdk.out | 1 + .../integ.json | 12 + .../manifest.json | 153 ++++++++ .../tree.json | 355 ++++++++++++++++++ .../test/integ.method-grant-execute.ts | 19 + packages/aws-cdk-lib/aws-apigateway/README.md | 8 + .../aws-cdk-lib/aws-apigateway/lib/method.ts | 14 + .../aws-apigateway/test/method.test.ts | 48 +++ 12 files changed, 863 insertions(+) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecute.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecute.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecuteTestDefaultTestDeployAssertA66B6F20.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecuteTestDefaultTestDeployAssertA66B6F20.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecute.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecute.assets.json new file mode 100644 index 0000000000000..0b10c220d7fac --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecute.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "454874b4674a38a5eb7ede0bc79fe77dcbf5062acaeb3b4424c7919758ae5191": { + "source": { + "path": "GrantExecute.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "454874b4674a38a5eb7ede0bc79fe77dcbf5062acaeb3b4424c7919758ae5191.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecute.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecute.template.json new file mode 100644 index 0000000000000..186a0e205a3f9 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecute.template.json @@ -0,0 +1,179 @@ +{ + "Resources": { + "user2C2B57AE": { + "Type": "AWS::IAM::User" + }, + "userDefaultPolicy083DF682": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "execute-api:Invoke", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "testapiD6451F70" + }, + "/", + { + "Ref": "testapiDeploymentStageprod5C9E92A4" + }, + "/GET/pets" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "userDefaultPolicy083DF682", + "Users": [ + { + "Ref": "user2C2B57AE" + } + ] + } + }, + "testapiD6451F70": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Name": "test-api" + } + }, + "testapiDeployment356D2C358af14d7f8fefbad1c57a65ea01cc6136": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "testapiD6451F70" + }, + "Description": "Automatically created by the RestApi construct" + }, + "DependsOn": [ + "testapipetsGET25A78130", + "testapipets981F319E" + ] + }, + "testapiDeploymentStageprod5C9E92A4": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "RestApiId": { + "Ref": "testapiD6451F70" + }, + "DeploymentId": { + "Ref": "testapiDeployment356D2C358af14d7f8fefbad1c57a65ea01cc6136" + }, + "StageName": "prod" + } + }, + "testapipets981F319E": { + "Type": "AWS::ApiGateway::Resource", + "Properties": { + "ParentId": { + "Fn::GetAtt": [ + "testapiD6451F70", + "RootResourceId" + ] + }, + "PathPart": "pets", + "RestApiId": { + "Ref": "testapiD6451F70" + } + } + }, + "testapipetsGET25A78130": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "HttpMethod": "GET", + "ResourceId": { + "Ref": "testapipets981F319E" + }, + "RestApiId": { + "Ref": "testapiD6451F70" + }, + "AuthorizationType": "NONE", + "Integration": { + "Type": "MOCK" + } + } + } + }, + "Outputs": { + "testapiEndpoint4AE34D29": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "testapiD6451F70" + }, + ".execute-api.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "testapiDeploymentStageprod5C9E92A4" + }, + "/" + ] + ] + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecuteTestDefaultTestDeployAssertA66B6F20.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecuteTestDefaultTestDeployAssertA66B6F20.assets.json new file mode 100644 index 0000000000000..316bd7d581d68 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecuteTestDefaultTestDeployAssertA66B6F20.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "GrantExecuteTestDefaultTestDeployAssertA66B6F20.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecuteTestDefaultTestDeployAssertA66B6F20.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecuteTestDefaultTestDeployAssertA66B6F20.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/GrantExecuteTestDefaultTestDeployAssertA66B6F20.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/cdk.out new file mode 100644 index 0000000000000..7925065efbcc4 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/integ.json new file mode 100644 index 0000000000000..3806bee2a2e3c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "31.0.0", + "testCases": { + "GrantExecuteTest/DefaultTest": { + "stacks": [ + "GrantExecute" + ], + "assertionStack": "GrantExecuteTest/DefaultTest/DeployAssert", + "assertionStackName": "GrantExecuteTestDefaultTestDeployAssertA66B6F20" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/manifest.json new file mode 100644 index 0000000000000..06817f21c13a9 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/manifest.json @@ -0,0 +1,153 @@ +{ + "version": "31.0.0", + "artifacts": { + "GrantExecute.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "GrantExecute.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "GrantExecute": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "GrantExecute.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/454874b4674a38a5eb7ede0bc79fe77dcbf5062acaeb3b4424c7919758ae5191.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "GrantExecute.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "GrantExecute.assets" + ], + "metadata": { + "/GrantExecute/user/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "user2C2B57AE" + } + ], + "/GrantExecute/user/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "userDefaultPolicy083DF682" + } + ], + "/GrantExecute/test-api/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "testapiD6451F70" + } + ], + "/GrantExecute/test-api/Deployment/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "testapiDeployment356D2C358af14d7f8fefbad1c57a65ea01cc6136" + } + ], + "/GrantExecute/test-api/DeploymentStage.prod/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "testapiDeploymentStageprod5C9E92A4" + } + ], + "/GrantExecute/test-api/Endpoint": [ + { + "type": "aws:cdk:logicalId", + "data": "testapiEndpoint4AE34D29" + } + ], + "/GrantExecute/test-api/Default/pets/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "testapipets981F319E" + } + ], + "/GrantExecute/test-api/Default/pets/GET/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "testapipetsGET25A78130" + } + ], + "/GrantExecute/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/GrantExecute/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "GrantExecute" + }, + "GrantExecuteTestDefaultTestDeployAssertA66B6F20.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "GrantExecuteTestDefaultTestDeployAssertA66B6F20.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "GrantExecuteTestDefaultTestDeployAssertA66B6F20": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "GrantExecuteTestDefaultTestDeployAssertA66B6F20.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "GrantExecuteTestDefaultTestDeployAssertA66B6F20.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "GrantExecuteTestDefaultTestDeployAssertA66B6F20.assets" + ], + "metadata": { + "/GrantExecuteTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/GrantExecuteTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "GrantExecuteTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/tree.json new file mode 100644 index 0000000000000..07fd5007601fd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.js.snapshot/tree.json @@ -0,0 +1,355 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "GrantExecute": { + "id": "GrantExecute", + "path": "GrantExecute", + "children": { + "user": { + "id": "user", + "path": "GrantExecute/user", + "children": { + "Resource": { + "id": "Resource", + "path": "GrantExecute/user/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::User", + "aws:cdk:cloudformation:props": {} + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnUser", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "GrantExecute/user/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "GrantExecute/user/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "execute-api:Invoke", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "testapiD6451F70" + }, + "/", + { + "Ref": "testapiDeploymentStageprod5C9E92A4" + }, + "/GET/pets" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "userDefaultPolicy083DF682", + "users": [ + { + "Ref": "user2C2B57AE" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.User", + "version": "0.0.0" + } + }, + "test-api": { + "id": "test-api", + "path": "GrantExecute/test-api", + "children": { + "Resource": { + "id": "Resource", + "path": "GrantExecute/test-api/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::RestApi", + "aws:cdk:cloudformation:props": { + "name": "test-api" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.CfnRestApi", + "version": "0.0.0" + } + }, + "Deployment": { + "id": "Deployment", + "path": "GrantExecute/test-api/Deployment", + "children": { + "Resource": { + "id": "Resource", + "path": "GrantExecute/test-api/Deployment/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Deployment", + "aws:cdk:cloudformation:props": { + "restApiId": { + "Ref": "testapiD6451F70" + }, + "description": "Automatically created by the RestApi construct" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.CfnDeployment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.Deployment", + "version": "0.0.0" + } + }, + "DeploymentStage.prod": { + "id": "DeploymentStage.prod", + "path": "GrantExecute/test-api/DeploymentStage.prod", + "children": { + "Resource": { + "id": "Resource", + "path": "GrantExecute/test-api/DeploymentStage.prod/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Stage", + "aws:cdk:cloudformation:props": { + "restApiId": { + "Ref": "testapiD6451F70" + }, + "deploymentId": { + "Ref": "testapiDeployment356D2C358af14d7f8fefbad1c57a65ea01cc6136" + }, + "stageName": "prod" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.CfnStage", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.Stage", + "version": "0.0.0" + } + }, + "Endpoint": { + "id": "Endpoint", + "path": "GrantExecute/test-api/Endpoint", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnOutput", + "version": "0.0.0" + } + }, + "Default": { + "id": "Default", + "path": "GrantExecute/test-api/Default", + "children": { + "pets": { + "id": "pets", + "path": "GrantExecute/test-api/Default/pets", + "children": { + "Resource": { + "id": "Resource", + "path": "GrantExecute/test-api/Default/pets/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Resource", + "aws:cdk:cloudformation:props": { + "parentId": { + "Fn::GetAtt": [ + "testapiD6451F70", + "RootResourceId" + ] + }, + "pathPart": "pets", + "restApiId": { + "Ref": "testapiD6451F70" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.CfnResource", + "version": "0.0.0" + } + }, + "GET": { + "id": "GET", + "path": "GrantExecute/test-api/Default/pets/GET", + "children": { + "Resource": { + "id": "Resource", + "path": "GrantExecute/test-api/Default/pets/GET/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Method", + "aws:cdk:cloudformation:props": { + "httpMethod": "GET", + "resourceId": { + "Ref": "testapipets981F319E" + }, + "restApiId": { + "Ref": "testapiD6451F70" + }, + "authorizationType": "NONE", + "integration": { + "type": "MOCK" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.CfnMethod", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.Method", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.Resource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.ResourceBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.RestApi", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "GrantExecute/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "GrantExecute/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "GrantExecuteTest": { + "id": "GrantExecuteTest", + "path": "GrantExecuteTest", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "GrantExecuteTest/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "GrantExecuteTest/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.25" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "GrantExecuteTest/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "GrantExecuteTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "GrantExecuteTest/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.25" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.ts new file mode 100644 index 0000000000000..9960bd3fde900 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.method-grant-execute.ts @@ -0,0 +1,19 @@ +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as cdk from 'aws-cdk-lib'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import * as apigw from 'aws-cdk-lib/aws-apigateway'; + + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'GrantExecute'); + +const user = new iam.User(stack, 'user'); +const api = new apigw.RestApi(stack, 'test-api'); +const method = api.root.addResource('pets').addMethod('GET'); +method.grantExecute(user); + +new integ.IntegTest(app, 'GrantExecuteTest', { + testCases: [stack], +}); + +app.synth(); diff --git a/packages/aws-cdk-lib/aws-apigateway/README.md b/packages/aws-cdk-lib/aws-apigateway/README.md index 9acadea42b75b..3008ba27848b3 100644 --- a/packages/aws-cdk-lib/aws-apigateway/README.md +++ b/packages/aws-cdk-lib/aws-apigateway/README.md @@ -60,6 +60,14 @@ book.addMethod('GET'); book.addMethod('DELETE'); ``` +To give an IAM User or Role permission to invoke a method, use `grantExecute`: + +```ts +declare user: iam.User; +const books = api.root.addResource('books'); +books.grantExecute(user); +``` + ## AWS Lambda-backed APIs A very common practice is to use Amazon API Gateway with AWS Lambda as the diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/method.ts b/packages/aws-cdk-lib/aws-apigateway/lib/method.ts index 7a2850babbd4d..53f4b44eeed03 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/method.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/method.ts @@ -12,6 +12,7 @@ import { IRestApi, RestApi, RestApiBase } from './restapi'; import { IStage } from './stage'; import { validateHttpMethod } from './util'; import * as cloudwatch from '../../aws-cloudwatch'; +import * as iam from '../../aws-iam'; import { ArnFormat, FeatureFlags, Lazy, Names, Resource, Stack } from '../../core'; import { APIGATEWAY_REQUEST_VALIDATOR_UNIQUE_ID } from '../../cx-api'; @@ -455,6 +456,19 @@ export class Method extends Resource { return this.cannedMetric(ApiGatewayMetrics.latencyAverage, stage, props); } + /** + * Grants an IAM principal permission to invoke this method. + * + * @param grantee the principal + */ + public grantExecute(grantee: iam.IGrantable): iam.Grant { + return iam.Grant.addToPrincipal({ + grantee, + actions: ['execute-api:Invoke'], + resourceArns: [this.methodArn], + }); + } + private cannedMetric(fn: (dims: { ApiName: string; Method: string; diff --git a/packages/aws-cdk-lib/aws-apigateway/test/method.test.ts b/packages/aws-cdk-lib/aws-apigateway/test/method.test.ts index 81cd18ef8b0bb..1772c509ff3c4 100644 --- a/packages/aws-cdk-lib/aws-apigateway/test/method.test.ts +++ b/packages/aws-cdk-lib/aws-apigateway/test/method.test.ts @@ -1073,5 +1073,53 @@ describe('method', () => { expect(metric.color).toEqual(color); expect(metric.dimensions).toEqual({ ApiName: 'test-api', Method: 'GET', Resource: '/pets', Stage: api.deploymentStage.stageName }); }); + + test('grantExecute', () => { + // GIVEN + const stack = new cdk.Stack(); + const user = new iam.User(stack, 'user'); + + // WHEN + const api = new apigw.RestApi(stack, 'test-api'); + const method = api.root.addResource('pets').addMethod('GET'); + method.grantExecute(user); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'execute-api:Invoke', + Effect: 'Allow', + Resource: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':execute-api:', + { + Ref: 'AWS::Region', + }, + ':', + { Ref: 'AWS::AccountId' }, + ':', + { Ref: 'testapiD6451F70' }, + '/', + { Ref: 'testapiDeploymentStageprod5C9E92A4' }, + '/GET/pets', + ], + ], + }, + }, + ], + }, + Users: [{ + Ref: 'user2C2B57AE', + }], + }); + }); }); });