diff --git a/packages/@aws-cdk/aws-neptune/README.md b/packages/@aws-cdk/aws-neptune/README.md index 77f50a7f6192d..bc14307f4bd69 100644 --- a/packages/@aws-cdk/aws-neptune/README.md +++ b/packages/@aws-cdk/aws-neptune/README.md @@ -73,7 +73,9 @@ const cluster = new neptune.DatabaseCluster(this, 'Cluster', { iamAuthentication: true, // Optional - will be automatically set if you call grantConnect(). }); const role = new iam.Role(this, 'DBRole', { assumedBy: new iam.AccountPrincipal(this.account) }); -cluster.grantConnect(role); // Grant the role connection access to the DB. +// Use one of the following statements to grant the role the necessary permissions +cluster.grantConnect(role); // Grant the role neptune-db:* access to the DB +cluster.grant(role, 'neptune-db:ReadDataViaQuery', 'neptune-db:WriteDataViaQuery'); // Grant the role the specified actions to the DB ``` ## Customizing parameters diff --git a/packages/@aws-cdk/aws-neptune/lib/cluster.ts b/packages/@aws-cdk/aws-neptune/lib/cluster.ts index afbcf91d73059..48ed396205cca 100644 --- a/packages/@aws-cdk/aws-neptune/lib/cluster.ts +++ b/packages/@aws-cdk/aws-neptune/lib/cluster.ts @@ -267,6 +267,15 @@ export interface IDatabaseCluster extends IResource, ec2.IConnectable { */ readonly clusterReadEndpoint: Endpoint; + /** + * Grant the given identity the specified actions + * @param grantee the identity to be granted the actions + * @param actions the data-access actions + * + * @see https://docs.aws.amazon.com/neptune/latest/userguide/iam-dp-actions.html + */ + grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant; + /** * Grant the given identity connection access to the database. */ @@ -360,15 +369,15 @@ export abstract class DatabaseClusterBase extends Resource implements IDatabaseC protected abstract enableIamAuthentication?: boolean; - public grantConnect(grantee: iam.IGrantable): iam.Grant { + public grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant { if (this.enableIamAuthentication === false) { - throw new Error('Cannot grant connect when IAM authentication is disabled'); + throw new Error('Cannot grant when IAM authentication is disabled'); } this.enableIamAuthentication = true; return iam.Grant.addToPrincipal({ grantee, - actions: ['neptune-db:*'], + actions, resourceArns: [ [ 'arn', @@ -381,6 +390,10 @@ export abstract class DatabaseClusterBase extends Resource implements IDatabaseC ], }); } + + public grantConnect(grantee: iam.IGrantable): iam.Grant { + return this.grant(grantee, 'neptune-db:*'); + } } /** diff --git a/packages/@aws-cdk/aws-neptune/test/cluster.test.ts b/packages/@aws-cdk/aws-neptune/test/cluster.test.ts index 212a344d56131..109bae7c69db8 100644 --- a/packages/@aws-cdk/aws-neptune/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-neptune/test/cluster.test.ts @@ -473,7 +473,7 @@ describe('DatabaseCluster', () => { }); }); - test('createGrant - creates IAM policy and enables IAM auth', () => { + test('grantConnect - enables IAM auth and grants neptune-db:* to the grantee', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -528,7 +528,7 @@ describe('DatabaseCluster', () => { }); }); - test('createGrant - throws if IAM auth disabled', () => { + test('grantConnect - throws if IAM auth disabled', () => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -544,7 +544,81 @@ describe('DatabaseCluster', () => { }); // THEN - expect(() => { cluster.grantConnect(role); }).toThrow(/Cannot grant connect when IAM authentication is disabled/); + expect(() => { cluster.grantConnect(role); }).toThrow(/Cannot grant when IAM authentication is disabled/); + }); + + test('grant - enables IAM auth and grants specified actions to the grantee', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + const cluster = new DatabaseCluster(stack, 'Cluster', { + vpc, + instanceType: InstanceType.R5_LARGE, + }); + const role = new iam.Role(stack, 'DBRole', { + assumedBy: new iam.AccountPrincipal(stack.account), + }); + cluster.grant(role, 'neptune-db:ReadDataViaQuery', 'neptune-db:WriteDataViaQuery'); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Neptune::DBCluster', { + IamAuthEnabled: true, + }); + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [{ + Effect: 'Allow', + Action: ['neptune-db:ReadDataViaQuery', 'neptune-db:WriteDataViaQuery'], + Resource: { + 'Fn::Join': [ + '', [ + 'arn:', { + Ref: 'AWS::Partition', + }, + ':neptune-db:', + { + Ref: 'AWS::Region', + }, + ':', + { + Ref: 'AWS::AccountId', + }, + ':', + { + 'Fn::GetAtt': [ + 'ClusterEB0386A7', + 'ClusterResourceId', + ], + }, + '/*', + ], + ], + }, + }], + Version: '2012-10-17', + }, + }); + }); + + test('grant - throws if IAM auth disabled', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + const cluster = new DatabaseCluster(stack, 'Cluster', { + vpc, + instanceType: InstanceType.R5_LARGE, + iamAuthentication: false, + }); + const role = new iam.Role(stack, 'DBRole', { + assumedBy: new iam.AccountPrincipal(stack.account), + }); + + // THEN + expect(() => { cluster.grant(role, 'neptune-db:ReadDataViaQuery', 'neptune-db:WriteDataViaQuery'); }).toThrow(/Cannot grant when IAM authentication is disabled/); }); test('autoMinorVersionUpgrade is enabled when configured', () => {