in packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/athena/start-query-execution.ts [140:245]
private createPolicyStatements(): iam.PolicyStatement[] {
const policyStatements = [
new iam.PolicyStatement({
resources: [
cdk.Stack.of(this).formatArn({
service: 'athena',
resource: 'datacatalog',
resourceName: this.props.queryExecutionContext?.catalogName ?? 'AwsDataCatalog',
}),
cdk.Stack.of(this).formatArn({
service: 'athena',
resource: 'workgroup',
resourceName: this.props.workGroup ?? 'primary',
}),
],
actions: ['athena:getDataCatalog', 'athena:startQueryExecution', 'athena:getQueryExecution'],
}),
];
policyStatements.push(
new iam.PolicyStatement({
actions: ['s3:CreateBucket',
's3:ListBucket',
's3:GetBucketLocation',
's3:GetObject'],
resources: ['*'], // Need * permissions to create new output location https://docs.aws.amazon.com/athena/latest/ug/security-iam-athena.html
}),
);
policyStatements.push(
new iam.PolicyStatement({
actions: ['s3:AbortMultipartUpload',
's3:ListBucketMultipartUploads',
's3:ListMultipartUploadParts',
's3:PutObject'],
resources: [
this.props.resultConfiguration?.outputLocation?.bucketName
? cdk.Stack.of(this).formatArn({
// S3 Bucket names are globally unique in a partition,
// and so their ARNs have empty region and account components
region: '',
account: '',
service: 's3',
resource: this.props.resultConfiguration?.outputLocation?.bucketName,
resourceName: `${this.props.resultConfiguration?.outputLocation?.objectKey}/*`,
})
: '*',
],
}),
);
policyStatements.push(
new iam.PolicyStatement({
actions: ['lakeformation:GetDataAccess'],
resources: ['*'], // State machines scoped to output location fail and * permissions are required as per documentation https://docs.aws.amazon.com/lake-formation/latest/dg/permissions-reference.html
}),
);
policyStatements.push(
new iam.PolicyStatement({
actions: ['glue:BatchCreatePartition',
'glue:BatchDeletePartition',
'glue:BatchDeleteTable',
'glue:BatchGetPartition',
'glue:CreateDatabase',
'glue:CreatePartition',
'glue:CreateTable',
'glue:DeleteDatabase',
'glue:DeletePartition',
'glue:DeleteTable',
'glue:GetDatabase',
'glue:GetDatabases',
'glue:GetPartition',
'glue:GetPartitions',
'glue:GetTable',
'glue:GetTables',
'glue:UpdateDatabase',
'glue:UpdatePartition',
'glue:UpdateTable'],
resources: [
cdk.Stack.of(this).formatArn({
service: 'glue',
resource: 'catalog',
}),
cdk.Stack.of(this).formatArn({
service: 'glue',
resource: 'database',
resourceName: this.props.queryExecutionContext?.databaseName ?? 'default',
}),
cdk.Stack.of(this).formatArn({
service: 'glue',
resource: 'table',
resourceName: (this.props.queryExecutionContext?.databaseName ?? 'default') + '/*', // grant access to all tables in the specified or default database to prevent cross database access https://docs.aws.amazon.com/IAM/latest/UserGuide/list_awsglue.html
}),
cdk.Stack.of(this).formatArn({
service: 'glue',
resource: 'userDefinedFunction',
resourceName: (this.props.queryExecutionContext?.databaseName ?? 'default') + '/*', // grant access to get all user defined functions for the particular database in the request or the default database https://docs.aws.amazon.com/IAM/latest/UserGuide/list_awsglue.html
}),
],
}),
);
return policyStatements;
}