Skip to content

Commit 3414416

Browse files
author
EC2 Default User
committed
Updating DLAC to use CDKv2.
1 parent 3c21d66 commit 3414416

9 files changed

+54
-62
lines changed

DeployOrUpdateDataLake.sh

-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
#!/bin/sh
22
npm run build
3-
currentPrincipalArn=$(aws sts get-caller-identity --query Arn --output text)
4-
#Just in case you are using an IAM role, we will switch the identity from your STS arn to the underlying role ARN.
5-
currentPrincipalArn=$(sed 's/\(sts\)\(.*\)\(assumed-role\)\(.*\)\(\/.*\)/iam\2role\4/' <<< $currentPrincipalArn)
6-
jq '.context.starterLakeFormationAdmin = $currentPrincipalArn' --arg currentPrincipalArn $currentPrincipalArn cdk.json > tmp.$$.json && mv tmp.$$.json cdk.json
73
cdk deploy CoreDataLake --require-approval never
84
#cdk deploy ExampleS3DataSet --require-approval never
95
#cdk deploy ExamplePgRdsDataSet --require-approval never

InstallCdkDependencies.sh

-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
npm install -g aws-cdk
22
npm install "@types/node" --save-dev
33
npm update
4-
sudo apt install jq -y
5-
sudo yum install jq -y
6-
npm install
74
cdk bootstrap

bin/aws.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ import { BaselineStack } from '../lib/Baseline-stack';
1414
const app = new App();
1515

1616
const coreDataLake = new DataLakeStack(app, 'CoreDataLake', {
17-
description: "AWS Data Lake as Code core data lake template. (ib-87ce095eDf)",
18-
starterLakeFormationAdminPrincipalArn: app.node.tryGetContext("starterLakeFormationAdmin")
17+
description: "AWS Data Lake as Code core data lake template. (ib-87ce095eDf)"
1918
});
2019

2120

cdk.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
"context": {
44
"@aws-cdk/aws-rds:lowercaseDbIdentifier": false,
55
"@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": false,
6-
"@aws-cdk/core:stackRelativeExports": false,
7-
"starterLakeFormationAdmin": "arn:aws:iam::XXXXX:role/Cloud9-Roda-IAM-Role"
6+
"@aws-cdk/core:stackRelativeExports": false
87
}
98
}

lib/constructs/data-lake-enrollment.ts

+17-11
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ export class DataLakeEnrollment extends Construct {
2020
private CoarseResourceAccessPolicy: iam.ManagedPolicy;
2121
private CoarseIamPolciesApplied: boolean;
2222
private WorkflowCronScheduleExpression?: string;
23-
23+
public SourceCfnResource?: lakeformation.CfnResource;
24+
public DatalakeCfnResource?: lakeformation.CfnResource;
2425

2526
constructor(scope: Construct, id: string, props: DataLakeEnrollment.DataLakeEnrollmentProps) {
2627
super(scope, id);
@@ -32,19 +33,19 @@ export class DataLakeEnrollment extends Construct {
3233

3334
}
3435

35-
grantGlueRoleLakeFormationPermissions(DataSetGlueRole: iam.Role, DataSetName: string) {
36+
grantGlueRoleLakeFormationPermissions(DataSetGlueRole: iam.Role, DataSetName: string, description: string, resource?: lakeformation.CfnResource) {
3637

3738
this.grantDataLocationPermissions(this.DataEnrollment.DataSetGlueRole, {
3839
Grantable: true,
39-
GrantResourcePrefix: `${DataSetName}locationGrant`,
40+
GrantResourcePrefix: `${DataSetName}${description}locationGrant`,
4041
Location: this.DataEnrollment.DataLakeBucketName,
4142
LocationPrefix: this.DataEnrollment.DataLakePrefix
42-
});
43+
}, resource);
4344

4445
this.grantDatabasePermission(this.DataEnrollment.DataSetGlueRole, {
4546
DatabasePermissions: [DataLakeEnrollment.DatabasePermission.All],
4647
GrantableDatabasePermissions: [DataLakeEnrollment.DatabasePermission.All],
47-
GrantResourcePrefix: `${DataSetName}RoleGrant`
48+
GrantResourcePrefix: `${DataSetName}${description}RoleGrant`
4849
}, true);
4950
}
5051

@@ -75,8 +76,8 @@ export class DataLakeEnrollment extends Construct {
7576
"Resource": [
7677
`arn:aws:glue:${Stack.of(this).region}:${Stack.of(this).account}:catalog`,
7778
`arn:aws:glue:${Stack.of(this).region}:${Stack.of(this).account}:database/default`,
78-
this.DataEnrollment.Dataset_Datalake.ref,
79-
`arn:aws:glue:${Stack.of(this).region}:${Stack.of(this).account}:table/${this.DataEnrollment.Dataset_Datalake.getAtt('DatabaseInput.Name').toString()}/*`
79+
`arn:aws:glue:${Stack.of(this).region}:${Stack.of(this).account}:database/${this.DataEnrollment.Dataset_DatalakeDatabaseName}`,
80+
`arn:aws:glue:${Stack.of(this).region}:${Stack.of(this).account}:table/${this.DataEnrollment.Dataset_DatalakeDatabaseName}/*`
8081
],
8182
"Effect": "Allow"
8283
};
@@ -121,7 +122,12 @@ export class DataLakeEnrollment extends Construct {
121122

122123
const policyParams = {
123124
policyName: `${this.DataSetName}-coarseIamDataLakeAccessPolicy`,
124-
statements: [s3PolicyStatement,gluePolicyStatement, athenaPolicyStatement, coarseLakeFormationPolicy]
125+
statements: [
126+
s3PolicyStatement,
127+
gluePolicyStatement,
128+
athenaPolicyStatement,
129+
coarseLakeFormationPolicy
130+
]
125131
}
126132

127133
this.CoarseResourceAccessPolicy = new iam.ManagedPolicy(this, `${this.DataSetName}-coarseIamDataLakeAccessPolicy`, policyParams );
@@ -356,7 +362,7 @@ export class DataLakeEnrollment extends Construct {
356362

357363
public grantDatabasePermission(principal: iam.IPrincipal, permissionGrant: DataLakeEnrollment.DatabasePermissionGrant, includeSourceDb: boolean = false){
358364

359-
const databaseName = this.DataEnrollment.Dataset_Datalake.getAtt('DatabaseInput.Name').toString();
365+
const databaseName = this.DataEnrollment.Dataset_DatalakeDatabaseName;
360366
var grantIdPrefix = ""
361367
var dataLakePrincipal : lakeformation.CfnPermissions.DataLakePrincipalProperty = {
362368
dataLakePrincipalIdentifier: ""
@@ -404,7 +410,7 @@ export class DataLakeEnrollment extends Construct {
404410
public grantTablePermissions(principal: iam.IPrincipal, permissionGrant: DataLakeEnrollment.TablePermissionGrant){
405411

406412
const coreGrant = this.setupIamAndLakeFormationDatabasePermissionForPrincipal(principal, permissionGrant.DatabasePermissions, permissionGrant.GrantableDatabasePermissions);
407-
const databaseName = this.DataEnrollment.Dataset_Datalake.getAtt('DatabaseInput.Name').toString();
413+
const databaseName = this.DataEnrollment.Dataset_DatalakeDatabaseName;
408414
permissionGrant.tables.forEach(table => {
409415
var tableResourceProperty : lakeformation.CfnPermissions.ResourceProperty = {
410416
tableResource:{
@@ -487,7 +493,7 @@ export class DataLakeEnrollment extends Construct {
487493
private setupIamAndLakeFormationDatabasePermissionForPrincipal(principal: iam.IPrincipal, databasePermissions: Array<DataLakeEnrollment.DatabasePermission>, grantableDatabasePermissions: Array<DataLakeEnrollment.DatabasePermission> ){
488494

489495
this.grantCoarseIamRead(principal);
490-
const databaseName = this.DataEnrollment.Dataset_Datalake.getAtt('DatabaseInput.Name').toString();
496+
const databaseName = this.DataEnrollment.Dataset_DatalakeDatabaseName;
491497

492498
var grantIdPrefix = ""
493499
var dataLakePrincipal : lakeformation.CfnPermissions.DataLakePrincipalProperty = {

lib/constructs/data-set-enrollment.ts

+15-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Construct, } from 'constructs';
2-
import { Aws, App, Stack, Resource, StackProps, CustomResource, Duration } from 'aws-cdk-lib';
2+
import { Aws, App, Stack, Resource, StackProps, CustomResource, Duration, Fn, Token } from 'aws-cdk-lib';
33

44
import * as ec2 from 'aws-cdk-lib/aws-ec2';
55
import * as iam from 'aws-cdk-lib/aws-iam';
@@ -186,20 +186,24 @@ export class DataSetEnrollment extends Construct {
186186
public readonly Dataset_Source: glue.CfnDatabase;
187187
public readonly Dataset_Datalake: glue.CfnDatabase;
188188

189+
public readonly Dataset_SourceDatabaseName: string;
190+
public readonly Dataset_DatalakeDatabaseName: string;
191+
189192
public readonly DataLakeBucketName: string;
190193
public readonly DataLakePrefix: string;
191194
public readonly DataLakeTargets: glue.CfnCrawler.TargetsProperty;
192195

193196

194-
private setupCrawler(targetGlueDatabase: glue.CfnDatabase, targets: glue.CfnCrawler.TargetsProperty, isSourceCrawler: boolean){
197+
private setupCrawler(targetGlueDatabase: glue.CfnDatabase, targets: glue.CfnCrawler.TargetsProperty, isSourceCrawler: boolean, databaseName: string){
195198

196199
var sourceCrawler = isSourceCrawler ? "src" : "dl";
197200

201+
198202
return new glue.CfnCrawler(this, `${this.DataSetName}-${sourceCrawler}-crawler`,{
199203
name: `${this.DataSetName}_${sourceCrawler}_crawler`,
200204
targets: targets,
201205
role: this.DataSetGlueRole.roleName,
202-
databaseName: targetGlueDatabase.getAtt('DatabaseInput.Name').toString(),
206+
databaseName: databaseName,
203207
schemaChangePolicy: {
204208
deleteBehavior: "DEPRECATE_IN_DATABASE",
205209
updateBehavior: "UPDATE_IN_DATABASE",
@@ -219,17 +223,20 @@ export class DataSetEnrollment extends Construct {
219223

220224
this.DataSetName = props.dataSetName;
221225

226+
this.Dataset_SourceDatabaseName = `${props.dataSetName}_src`;
227+
this.Dataset_DatalakeDatabaseName = `${props.dataSetName}_dl`;
228+
222229
this.Dataset_Source = new glue.CfnDatabase(this, `${props.dataSetName}_src`, {
223230
catalogId: Aws.ACCOUNT_ID,
224231
databaseInput: {
225-
name: `${props.dataSetName}_src`,
232+
name: this.Dataset_SourceDatabaseName,
226233
locationUri: `s3://${props.dataLakeBucket.bucketName}/${props.dataSetName}/`
227234
}
228235
});
229236
this.Dataset_Datalake = new glue.CfnDatabase(this, `${props.dataSetName}_dl`, {
230237
catalogId: Aws.ACCOUNT_ID,
231238
databaseInput: {
232-
name: `${props.dataSetName}_dl`,
239+
name: this.Dataset_DatalakeDatabaseName,
233240
locationUri: `s3://${props.dataLakeBucket.bucketName}/${props.dataSetName}/`
234241
}
235242
});
@@ -261,9 +268,8 @@ export class DataSetEnrollment extends Construct {
261268
if(typeof props.SourceAccessPolicy !== 'undefined'){
262269
props.SourceAccessPolicy.attachToRole(this.DataSetGlueRole);
263270
}
264-
265-
266-
const sourceCrawler = this.setupCrawler(this.Dataset_Source, props.SourceTargets, true);
271+
272+
const sourceCrawler = this.setupCrawler(this.Dataset_Source, props.SourceTargets, true, this.Dataset_SourceDatabaseName);
267273

268274

269275

@@ -300,16 +306,7 @@ export class DataSetEnrollment extends Construct {
300306
const etl_job = new glue.CfnJob(this, `${props.dataSetName}-EtlJob`, jobParams );
301307

302308

303-
const datalake_crawler = this.setupCrawler(this.Dataset_Datalake, this.DataLakeTargets, false);
304-
305-
// const datalake_crawler = this.setupCrawler(this.Dataset_Datalake, {
306-
// s3Targets: [
307-
// {
308-
// path: `s3://${props.dataLakeBucket.bucketName}/${props.dataSetName}/`
309-
// }
310-
// ]
311-
// }, false);
312-
309+
const datalake_crawler = this.setupCrawler(this.Dataset_Datalake, this.DataLakeTargets, false, this.Dataset_DatalakeDatabaseName);
313310

314311
const datalakeEnrollmentWorkflow = new DataLakeEnrollmentWorkflow(this,`${props.dataSetName}DataLakeWorkflow`,{
315312
workfowName: `${props.dataSetName}_DataLakeEnrollmentWorkflow`,

lib/constructs/rds-data-set-enrollment.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export class RDSDataSetEnrollment extends DataLakeEnrollment {
8080

8181

8282
this.createCoarseIamPolicy();
83-
this.grantGlueRoleLakeFormationPermissions(this.DataEnrollment.DataSetGlueRole, props.DataSetName);
83+
this.grantGlueRoleLakeFormationPermissions(this.DataEnrollment.DataSetGlueRole, props.DataSetName, 'src');
8484
this.grantCoarseIamRead(this.DataEnrollment.DataSetGlueRole);
8585
}
8686
}

lib/constructs/s3-data-set-enrollment.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,24 @@ export class S3dataSetEnrollment extends DataLakeEnrollment{
2323

2424
private readonly sourceBucket: s3.IBucket;
2525

26-
setupGlueRoleLakeFormationPermissions(DataSetGlueRole: iam.Role, DataSetName: string, sourceDataBucket: s3.IBucket) {
26+
setupGlueRoleLakeFormationPermissions(DataSetGlueRole: iam.Role, DataSetName: string, sourceDataBucket: s3.IBucket, locationDescription: string) {
2727

28-
const sourceLakeFormationLocation = new lakeformation.CfnResource( this, "sourceLakeFormationLocation",
28+
const sourceLakeFormationLocation = new lakeformation.CfnResource( this, `sourceLakeFormationLocation-${sourceDataBucket}`,
2929
{
3030
resourceArn: sourceDataBucket.bucketArn,
3131
roleArn: this.DataEnrollment.DataSetGlueRole.roleArn,
3232
useServiceLinkedRole: true,
3333
}
3434
);
3535

36-
super.grantGlueRoleLakeFormationPermissions(DataSetGlueRole, DataSetName);
37-
3836
this.grantDataLocationPermissions(this.DataEnrollment.DataSetGlueRole, {
3937
Grantable: true,
40-
GrantResourcePrefix: `${DataSetName}SourcelocationGrant`,
38+
GrantResourcePrefix: `${DataSetName}-${locationDescription}-locationGrant`,
4139
Location: sourceDataBucket.bucketName,
4240
LocationPrefix: "/"
4341
}, sourceLakeFormationLocation);
42+
43+
return sourceLakeFormationLocation;
4444

4545
}
4646

@@ -114,8 +114,11 @@ export class S3dataSetEnrollment extends DataLakeEnrollment{
114114

115115
this.createCoarseIamPolicy();
116116

117+
this.SourceCfnResource = this.setupGlueRoleLakeFormationPermissions(this.DataEnrollment.DataSetGlueRole, props.DataSetName, props.sourceBucket, "src");
118+
this.DatalakeCfnResource = this.setupGlueRoleLakeFormationPermissions(this.DataEnrollment.DataSetGlueRole, props.DataSetName, props.dataLakeBucket, "dl");
117119

118-
this.setupGlueRoleLakeFormationPermissions(this.DataEnrollment.DataSetGlueRole, props.DataSetName, props.sourceBucket);
120+
super.grantGlueRoleLakeFormationPermissions(this.DataEnrollment.DataSetGlueRole, props.DataSetName, 'src', this.SourceCfnResource);
121+
super.grantGlueRoleLakeFormationPermissions(this.DataEnrollment.DataSetGlueRole, props.DataSetName, 'dl', this.DatalakeCfnResource);
119122

120123
this.grantCoarseIamRead(this.DataEnrollment.DataSetGlueRole);
121124

lib/stacks/datalake-stack.ts

+10-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Construct } from 'constructs';
2-
import { App, Stack, Resource, StackProps, CustomResource, Duration } from 'aws-cdk-lib';
2+
import { App, Stack, Resource, StackProps, CustomResource, Duration, DefaultStackSynthesizer, Fn } from 'aws-cdk-lib';
33

44
import * as ec2 from 'aws-cdk-lib/aws-ec2';
55
import * as iam from 'aws-cdk-lib/aws-iam';
@@ -19,7 +19,7 @@ import {
1919
} from "../constructs/data-set-enrollment";
2020

2121
export interface DataLakeStackProps extends StackProps {
22-
starterLakeFormationAdminPrincipalArn: string;
22+
2323
}
2424

2525
export class DataLakeStack extends Stack {
@@ -29,7 +29,6 @@ export class DataLakeStack extends Stack {
2929
public readonly LakeFormationResource: lakeformation.CfnResource;
3030
public readonly PrimaryAthenaWorkgroup: athena.CfnWorkGroup;
3131
private readonly bucketRole: iam.Role;
32-
private readonly starterAdminArn: string;
3332

3433
public grantAthenaResultsBucketPermission(principal: iam.IPrincipal) {
3534
if (principal instanceof iam.Role) {
@@ -63,15 +62,17 @@ export class DataLakeStack extends Stack {
6362
constructor(scope: Construct, id: string, props: DataLakeStackProps) {
6463
super(scope, id, props);
6564

65+
6666
this.DataLakeBucket = new s3.Bucket(this, 'dataLakeBucket',{
67+
bucketName: 'aws-roda-fintech-datalake'
6768
});
6869
this.AthenaResultsBucket = new s3.Bucket(this, "athenaResultsBucket");
6970

70-
new lakeformation.CfnDataLakeSettings(this, "starterAdminPermission", {
71+
72+
new lakeformation.CfnDataLakeSettings(this, "cdkCfnExecRoleAdminPermission", {
7173
admins: [
7274
{
73-
dataLakePrincipalIdentifier:
74-
props.starterLakeFormationAdminPrincipalArn,
75+
dataLakePrincipalIdentifier: Fn.sub((this.synthesizer as DefaultStackSynthesizer).cloudFormationExecutionRoleArn)
7576
},
7677
],
7778
});
@@ -94,9 +95,7 @@ export class DataLakeStack extends Stack {
9495
coarseAthenaResultBucketAccess
9596
);
9697

97-
this.AthenaResultsBucketAccessPolicy = new iam.ManagedPolicy(
98-
this,
99-
`athenaResultBucketAccessPolicy`,
98+
this.AthenaResultsBucketAccessPolicy = new iam.ManagedPolicy(this, `athenaResultBucketAccessPolicy`,
10099
{
101100
document: coarseAthenaResultBucketAccessPolicyDoc,
102101
description: `AthenaResultBucketAccessPolicy`,
@@ -111,19 +110,15 @@ export class DataLakeStack extends Stack {
111110

112111
this.DataLakeBucket.grantReadWrite(this.bucketRole);
113112

114-
this.LakeFormationResource = new lakeformation.CfnResource(
115-
this,
116-
"dataLakeBucketLakeFormationResource",
113+
this.LakeFormationResource = new lakeformation.CfnResource(this,"dataLakeBucketLakeFormationResource",
117114
{
118115
resourceArn: this.DataLakeBucket.bucketArn,
119116
roleArn: this.bucketRole.roleArn,
120117
useServiceLinkedRole: true,
121118
}
122119
);
123120

124-
const workGroupConfigCustResourceRole = new iam.Role(
125-
this,
126-
"workGroupConfigCustResourceRole",
121+
const workGroupConfigCustResourceRole = new iam.Role(this,"workGroupConfigCustResourceRole",
127122
{
128123
assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
129124
}

0 commit comments

Comments
 (0)