From 3d11a0d2a408f6acf98e5358ef5b43b4567da46b Mon Sep 17 00:00:00 2001 From: yuanhaoz Date: Wed, 9 Oct 2024 15:37:06 -0700 Subject: [PATCH 1/7] fix(core): fix policy synthesizer logic for precreated roles --- ...cdk-table-with-customized-role.assets.json | 19 ++ ...k-table-with-customized-role.template.json | 83 +++++ ...dk-table-with-customized-role2.assets.json | 19 ++ ...-table-with-customized-role2.template.json | 61 ++++ .../cdk.out | 1 + ...efaultTestDeployAssertD6C925FC.assets.json | 19 ++ ...aultTestDeployAssertD6C925FC.template.json | 36 ++ .../iam-policy-report.json | 90 +++++ .../iam-policy-report.txt | 101 ++++++ .../integ.json | 14 + .../manifest.json | 170 ++++++++++ .../tree.json | 319 ++++++++++++++++++ .../test/integ.table-with-customized-role.ts | 70 ++++ packages/aws-cdk-lib/aws-iam/README.md | 66 ++++ .../lib/helpers-internal/customize-roles.ts | 23 +- packages/aws-cdk-lib/core/lib/resolvable.ts | 41 +++ 16 files changed, 1127 insertions(+), 5 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role2.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role2.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/iam-policy-report.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/iam-policy-report.txt create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role.assets.json new file mode 100644 index 0000000000000..23b584c2e6591 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role.assets.json @@ -0,0 +1,19 @@ +{ + "version": "38.0.1", + "files": { + "70267cb4d71000f9402304c37f8f7f27be51a2639cc15153bf93abab53fc60cd": { + "source": { + "path": "cdk-table-with-customized-role.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "70267cb4d71000f9402304c37f8f7f27be51a2639cc15153bf93abab53fc60cd.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-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role.template.json new file mode 100644 index 0000000000000..4a512f0150bc8 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role.template.json @@ -0,0 +1,83 @@ +{ + "Resources": { + "TableCD117FA1": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "AttributeDefinitions": [ + { + "AttributeName": "pk", + "AttributeType": "S" + }, + { + "AttributeName": "gsi-pk", + "AttributeType": "S" + } + ], + "GlobalSecondaryIndexes": [ + { + "IndexName": "gsi", + "KeySchema": [ + { + "AttributeName": "gsi-pk", + "KeyType": "HASH" + } + ], + "Projection": { + "ProjectionType": "ALL" + }, + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + } + ], + "KeySchema": [ + { + "AttributeName": "pk", + "KeyType": "HASH" + } + ], + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + } + }, + "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-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role2.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role2.assets.json new file mode 100644 index 0000000000000..05d955ca02cea --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role2.assets.json @@ -0,0 +1,19 @@ +{ + "version": "38.0.1", + "files": { + "75d2a3c3208960a28b88f27cd9f94f89a8126de261c69dc422537395c5c29fbe": { + "source": { + "path": "cdk-table-with-customized-role2.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "75d2a3c3208960a28b88f27cd9f94f89a8126de261c69dc422537395c5c29fbe.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-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role2.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role2.template.json new file mode 100644 index 0000000000000..9b673891b73cb --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk-table-with-customized-role2.template.json @@ -0,0 +1,61 @@ +{ + "Resources": { + "TableCD117FA1": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "AttributeDefinitions": [ + { + "AttributeName": "pk", + "AttributeType": "S" + } + ], + "KeySchema": [ + { + "AttributeName": "pk", + "KeyType": "HASH" + } + ], + "ProvisionedThroughput": { + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + } + }, + "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-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk.out new file mode 100644 index 0000000000000..c6e612584e352 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"38.0.1"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.assets.json new file mode 100644 index 0000000000000..374f439045d06 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.assets.json @@ -0,0 +1,19 @@ +{ + "version": "38.0.1", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.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-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.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-dynamodb/test/integ.table-with-customized-role.js.snapshot/iam-policy-report.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/iam-policy-report.json new file mode 100644 index 0000000000000..aadc926f1bee0 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/iam-policy-report.json @@ -0,0 +1,90 @@ +{ + "roles": [ + { + "roleConstructPath": "cdk-table-with-customized-role/Table/ScalingRole", + "roleName": "AWSServiceRoleForApplicationAutoScaling_DynamoDBTable", + "assumeRolePolicy": [], + "managedPolicyArns": [], + "managedPolicyStatements": [], + "identityPolicyStatements": [] + }, + { + "roleConstructPath": "cdk-table-with-customized-role/Role", + "roleName": "my-precreated-role-name", + "missing": false, + "assumeRolePolicy": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "dynamodb.amazonaws.com" + } + } + ], + "managedPolicyArns": [], + "managedPolicyStatements": [], + "identityPolicyStatements": [ + { + "Action": [ + "dynamodb:BatchGetItem", + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:Query", + "dynamodb:GetItem", + "dynamodb:Scan", + "dynamodb:ConditionCheckItem", + "dynamodb:DescribeTable" + ], + "Effect": "Allow", + "Resource": [ + "(cdk-table-with-customized-role/Table/Resource.Arn)", + "(cdk-table-with-customized-role/Table/Resource.Arn)/index/*" + ] + } + ] + }, + { + "roleConstructPath": "cdk-table-with-customized-role2/Table/ScalingRole", + "roleName": "AWSServiceRoleForApplicationAutoScaling_DynamoDBTable", + "assumeRolePolicy": [], + "managedPolicyArns": [], + "managedPolicyStatements": [], + "identityPolicyStatements": [] + }, + { + "roleConstructPath": "cdk-table-with-customized-role2/Role", + "roleName": "my-precreated-role-name", + "missing": false, + "assumeRolePolicy": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "dynamodb.amazonaws.com" + } + } + ], + "managedPolicyArns": [], + "managedPolicyStatements": [], + "identityPolicyStatements": [ + { + "Action": [ + "dynamodb:BatchGetItem", + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:Query", + "dynamodb:GetItem", + "dynamodb:Scan", + "dynamodb:ConditionCheckItem", + "dynamodb:DescribeTable" + ], + "Effect": "Allow", + "Resource": [ + "(cdk-table-with-customized-role2/Table/Resource.Arn)", + "(NOVALUE)" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/iam-policy-report.txt b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/iam-policy-report.txt new file mode 100644 index 0000000000000..30c4bdd499491 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/iam-policy-report.txt @@ -0,0 +1,101 @@ + (cdk-table-with-customized-role/Table/ScalingRole) + +AssumeRole Policy: +NONE + +Managed Policy ARNs: +NONE + +Managed Policies Statements: +NONE + +Identity Policy Statements: +NONE (cdk-table-with-customized-role/Role) + +AssumeRole Policy: +[ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "dynamodb.amazonaws.com" + } + } +] + +Managed Policy ARNs: +NONE + +Managed Policies Statements: +NONE + +Identity Policy Statements: +[ + { + "Action": [ + "dynamodb:BatchGetItem", + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:Query", + "dynamodb:GetItem", + "dynamodb:Scan", + "dynamodb:ConditionCheckItem", + "dynamodb:DescribeTable" + ], + "Effect": "Allow", + "Resource": [ + "(cdk-table-with-customized-role/Table/Resource.Arn)", + "(cdk-table-with-customized-role/Table/Resource.Arn)/index/*" + ] + } +] (cdk-table-with-customized-role2/Table/ScalingRole) + +AssumeRole Policy: +NONE + +Managed Policy ARNs: +NONE + +Managed Policies Statements: +NONE + +Identity Policy Statements: +NONE (cdk-table-with-customized-role2/Role) + +AssumeRole Policy: +[ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "dynamodb.amazonaws.com" + } + } +] + +Managed Policy ARNs: +NONE + +Managed Policies Statements: +NONE + +Identity Policy Statements: +[ + { + "Action": [ + "dynamodb:BatchGetItem", + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:Query", + "dynamodb:GetItem", + "dynamodb:Scan", + "dynamodb:ConditionCheckItem", + "dynamodb:DescribeTable" + ], + "Effect": "Allow", + "Resource": [ + "(cdk-table-with-customized-role2/Table/Resource.Arn)", + "(NOVALUE)" + ] + } +] \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/integ.json new file mode 100644 index 0000000000000..05d41e8b269ff --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/integ.json @@ -0,0 +1,14 @@ +{ + "version": "38.0.1", + "testCases": { + "cdk-dynamodb-customized-role-integ/DefaultTest": { + "stacks": [ + "cdk-table-with-customized-role", + "cdk-table-with-customized-role2" + ], + "diffAssets": true, + "assertionStack": "cdk-dynamodb-customized-role-integ/DefaultTest/DeployAssert", + "assertionStackName": "cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/manifest.json new file mode 100644 index 0000000000000..66aa906b31622 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/manifest.json @@ -0,0 +1,170 @@ +{ + "version": "38.0.1", + "artifacts": { + "cdk-table-with-customized-role.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "cdk-table-with-customized-role.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "cdk-table-with-customized-role": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "cdk-table-with-customized-role.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "notificationArns": [], + "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}/70267cb4d71000f9402304c37f8f7f27be51a2639cc15153bf93abab53fc60cd.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "cdk-table-with-customized-role.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": [ + "cdk-table-with-customized-role.assets" + ], + "metadata": { + "/cdk-table-with-customized-role/Table/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TableCD117FA1" + } + ], + "/cdk-table-with-customized-role/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/cdk-table-with-customized-role/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "cdk-table-with-customized-role" + }, + "cdk-table-with-customized-role2.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "cdk-table-with-customized-role2.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "cdk-table-with-customized-role2": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "cdk-table-with-customized-role2.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "notificationArns": [], + "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}/75d2a3c3208960a28b88f27cd9f94f89a8126de261c69dc422537395c5c29fbe.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "cdk-table-with-customized-role2.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": [ + "cdk-table-with-customized-role2.assets" + ], + "metadata": { + "/cdk-table-with-customized-role2/Table/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TableCD117FA1" + } + ], + "/cdk-table-with-customized-role2/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/cdk-table-with-customized-role2/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "cdk-table-with-customized-role2" + }, + "cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "notificationArns": [], + "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": [ + "cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.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": [ + "cdkdynamodbcustomizedroleintegDefaultTestDeployAssertD6C925FC.assets" + ], + "metadata": { + "/cdk-dynamodb-customized-role-integ/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/cdk-dynamodb-customized-role-integ/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "cdk-dynamodb-customized-role-integ/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-dynamodb/test/integ.table-with-customized-role.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/tree.json new file mode 100644 index 0000000000000..8cb209f416f3b --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/tree.json @@ -0,0 +1,319 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "cdk-table-with-customized-role": { + "id": "cdk-table-with-customized-role", + "path": "cdk-table-with-customized-role", + "children": { + "Table": { + "id": "Table", + "path": "cdk-table-with-customized-role/Table", + "children": { + "Resource": { + "id": "Resource", + "path": "cdk-table-with-customized-role/Table/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::DynamoDB::Table", + "aws:cdk:cloudformation:props": { + "attributeDefinitions": [ + { + "attributeName": "pk", + "attributeType": "S" + }, + { + "attributeName": "gsi-pk", + "attributeType": "S" + } + ], + "globalSecondaryIndexes": [ + { + "indexName": "gsi", + "keySchema": [ + { + "attributeName": "gsi-pk", + "keyType": "HASH" + } + ], + "projection": { + "projectionType": "ALL" + }, + "provisionedThroughput": { + "readCapacityUnits": 5, + "writeCapacityUnits": 5 + } + } + ], + "keySchema": [ + { + "attributeName": "pk", + "keyType": "HASH" + } + ], + "provisionedThroughput": { + "readCapacityUnits": 5, + "writeCapacityUnits": 5 + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_dynamodb.CfnTable", + "version": "0.0.0" + } + }, + "ImportScalingRole": { + "id": "ImportScalingRole", + "path": "cdk-table-with-customized-role/Table/ImportScalingRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "ScalingRole": { + "id": "ScalingRole", + "path": "cdk-table-with-customized-role/Table/ScalingRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_dynamodb.Table", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "cdk-table-with-customized-role/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "cdk-table-with-customized-role/Role/ImportRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "PrecreatedRoleRole": { + "id": "PrecreatedRoleRole", + "path": "cdk-table-with-customized-role/Role/PrecreatedRoleRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "cdk-table-with-customized-role/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "cdk-table-with-customized-role/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "PolicySynthesizer": { + "id": "PolicySynthesizer", + "path": "PolicySynthesizer", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "cdk-table-with-customized-role2": { + "id": "cdk-table-with-customized-role2", + "path": "cdk-table-with-customized-role2", + "children": { + "Table": { + "id": "Table", + "path": "cdk-table-with-customized-role2/Table", + "children": { + "Resource": { + "id": "Resource", + "path": "cdk-table-with-customized-role2/Table/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::DynamoDB::Table", + "aws:cdk:cloudformation:props": { + "attributeDefinitions": [ + { + "attributeName": "pk", + "attributeType": "S" + } + ], + "keySchema": [ + { + "attributeName": "pk", + "keyType": "HASH" + } + ], + "provisionedThroughput": { + "readCapacityUnits": 5, + "writeCapacityUnits": 5 + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_dynamodb.CfnTable", + "version": "0.0.0" + } + }, + "ImportScalingRole": { + "id": "ImportScalingRole", + "path": "cdk-table-with-customized-role2/Table/ImportScalingRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "ScalingRole": { + "id": "ScalingRole", + "path": "cdk-table-with-customized-role2/Table/ScalingRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_dynamodb.Table", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "cdk-table-with-customized-role2/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "cdk-table-with-customized-role2/Role/ImportRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "PrecreatedRoleRole": { + "id": "PrecreatedRoleRole", + "path": "cdk-table-with-customized-role2/Role/PrecreatedRoleRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "cdk-table-with-customized-role2/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "cdk-table-with-customized-role2/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "cdk-dynamodb-customized-role-integ": { + "id": "cdk-dynamodb-customized-role-integ", + "path": "cdk-dynamodb-customized-role-integ", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "cdk-dynamodb-customized-role-integ/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "cdk-dynamodb-customized-role-integ/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "cdk-dynamodb-customized-role-integ/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "cdk-dynamodb-customized-role-integ/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "cdk-dynamodb-customized-role-integ/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.3.0" + } + } + }, + "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-dynamodb/test/integ.table-with-customized-role.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.ts new file mode 100644 index 0000000000000..f57a789aac8af --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.ts @@ -0,0 +1,70 @@ +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import { App, Stack, StackProps } from 'aws-cdk-lib'; +import { AttributeType, Table } from 'aws-cdk-lib/aws-dynamodb'; +import { Construct } from 'constructs'; +import { Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; + +class TestStack extends Stack { + public constructor(scope: Construct, id: string, props: StackProps) { + super(scope, id, props); + + Role.customizeRoles(this, { + usePrecreatedRoles: { + 'cdk-table-with-customized-role/Role': 'my-precreated-role-name', + }, + }); + + const table = new Table(this, 'Table', { + partitionKey: { + name: 'pk', + type: AttributeType.STRING, + }, + }); + + // Add GSI will add a new Resource under IAM Policy + // i.e. `${this.tableArn}/index/*`. Test the Policy + // Synthesizer generation with concatenated value. + table.addGlobalSecondaryIndex({ + indexName: 'gsi', + partitionKey: { + name: 'gsi-pk', + type: AttributeType.STRING, + }, + }); + const role = new Role(this, 'Role', { + assumedBy: new ServicePrincipal('dynamodb.amazonaws.com'), + }); + table.grantReadData(role); + } +} + +class TestStack2 extends Stack { + public constructor(scope: Construct, id: string, props: StackProps) { + super(scope, id, props); + + Role.customizeRoles(this, { + usePrecreatedRoles: { + 'cdk-table-with-customized-role2/Role': 'my-precreated-role-name', + }, + }); + + const table = new Table(this, 'Table', { + partitionKey: { + name: 'pk', + type: AttributeType.STRING, + }, + }); + const role = new Role(this, 'Role', { + assumedBy: new ServicePrincipal('dynamodb.amazonaws.com'), + }); + table.grantReadData(role); + } +} + +const app = new App(); +const stack = new TestStack(app, 'cdk-table-with-customized-role', {}); +const stack2 = new TestStack2(app, 'cdk-table-with-customized-role2', {}); +new IntegTest(app, 'cdk-dynamodb-customized-role-integ', { + testCases: [stack, stack2], + diffAssets: true, +}); diff --git a/packages/aws-cdk-lib/aws-iam/README.md b/packages/aws-cdk-lib/aws-iam/README.md index b020dc7c55063..16301d68f25ea 100644 --- a/packages/aws-cdk-lib/aws-iam/README.md +++ b/packages/aws-cdk-lib/aws-iam/README.md @@ -238,6 +238,72 @@ iam.Role.customizeRoles(this, { For more information on configuring permissions see the [Security And Safety Dev Guide](https://github.com/aws/aws-cdk/wiki/Security-And-Safety-Dev-Guide) +#### Policy report generation + +When `customizeRoles` is used, the `iam-policy-report.txt` report will contain a list +of IAM roles and associated permissions that would have been created. This report is +generated so that it attempts to resolve any references and replace with a more user +friendly value. + +The following are some examples of the value that will appear in the report: + +```json +"Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/Role" + ] + ] +} +``` + +The policy report will instead get: + +```json +"Resource": "arn:(PARTITION):iam::(ACCOUNT):role/Role" +``` + +If IAM policy is referencing a resource attribute: + +```json +"Resource": [ + { + "Fn::GetAtt": [ + "SomeResource", + "Arn" + ] + }, + { + "Ref": "AWS::NoValue", + } +] +``` + +The policy report will instead get: + +```json +"Resource": [ + "(Path/To/SomeResource.Arn)" + "(NoValue)" +] +``` + +The following pseudo parameters will be converted: + +1. `{ 'Ref': 'AWS::AccountId' }` -> `(ACCOUNT) +2. `{ 'Ref': 'AWS::Partition' }` -> `(PARTITION) +3. `{ 'Ref': 'AWS::Region' }` -> `(REGION) +4. `{ 'Ref': 'AWS::NoValue' }` -> `(NOVALUE) + #### Generating a permissions report It is also possible to generate the report _without_ preventing the role/policy creation. diff --git a/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts b/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts index 67d81b5d85727..d1354f8773f24 100644 --- a/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts +++ b/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts @@ -4,7 +4,7 @@ import { Construct } from 'constructs'; import { Annotations } from '../annotations'; import { attachCustomSynthesis } from '../app'; import { Reference } from '../reference'; -import { IResolvable, DefaultTokenResolver, StringConcat } from '../resolvable'; +import { IResolvable, StringConcat, PolicySynthesizerTokenResolver } from '../resolvable'; import { ISynthesisSession } from '../stack-synthesizers'; import { Token, Tokenization } from '../token'; @@ -139,14 +139,17 @@ export class PolicySynthesizer extends Construct { if (synthesizer) { return synthesizer as PolicySynthesizer; } - return new PolicySynthesizer(scope.node.root); + return new PolicySynthesizer(scope); } + private readonly _scope: Construct; private readonly roleReport: { [rolePath: string]: RoleReportOptions } = {}; private readonly managedPolicyReport: { [policyPath: string]: ManagedPolicyReportOptions } = {}; constructor(scope: Construct) { - super(scope, POLICY_SYNTHESIZER_ID); + // PolicySynthesizer should be created under the `App` scope + super(scope.node.root, POLICY_SYNTHESIZER_ID); + this._scope = scope; attachCustomSynthesis(this, { onSynthesize: (session: ISynthesisSession) => { const report = this.createJsonReport(); @@ -316,9 +319,11 @@ export class PolicySynthesizer extends Construct { if (Reference.isReference(r)) { return `(${r.target.node.path}.${r.displayName})`; } + // Token resolution requires a stack scope. We can't directly use this + // because PolicySynthesizer is always created in the App scope. const resolved = Tokenization.resolve(r, { - scope: this, - resolver: new DefaultTokenResolver(new StringConcat()), + scope: this._scope, + resolver: new PolicySynthesizerTokenResolver(new StringConcat()), }); if (typeof resolved === 'object' && resolved.hasOwnProperty('Ref')) { switch (resolved.Ref) { @@ -328,10 +333,18 @@ export class PolicySynthesizer extends Construct { return '(PARTITION)'; case 'AWS::Region': return '(REGION)'; + case 'AWS::NoValue': + return '(NOVALUE)'; default: return r; } } + // If the original value is an unresolved Token and we have successfully + // resolve it through the above Token resolution process, we should + // return the resolved token instead. + if (Token.isUnresolved(r) && typeof resolved === 'string' && resolved) { + return resolved; + } return r; }, }); diff --git a/packages/aws-cdk-lib/core/lib/resolvable.ts b/packages/aws-cdk-lib/core/lib/resolvable.ts index fe41ee78d20a1..51d489d7bb0ba 100644 --- a/packages/aws-cdk-lib/core/lib/resolvable.ts +++ b/packages/aws-cdk-lib/core/lib/resolvable.ts @@ -1,7 +1,9 @@ import { IConstruct } from 'constructs'; import { TokenString } from './private/encoding'; import { TokenMap } from './private/token-map'; +import { Reference } from './reference'; import { TokenizedStringFragments } from './string-fragments'; +import { Tokenization } from './token'; import { ResolutionTypeHint } from './type-hints'; /** @@ -200,3 +202,42 @@ export class DefaultTokenResolver implements ITokenResolver { return fragments.mapTokens({ mapToken: context.resolve }).firstValue; } } + +/** + * PolicySynthesizer token resolver implementation + * + */ +export class PolicySynthesizerTokenResolver extends DefaultTokenResolver { + constructor(concat: IFragmentConcatenator) { + super(concat); + } + + /** + * PolicySynthesizer Token resolution + * + * Resolve the Token, recurse into whatever it returns, + * then finally post-process it. + */ + public resolveToken(t: IResolvable, context: IResolveContext, postProcessor: IPostProcessor) { + try { + let resolved = t.resolve(context); + + // The token might have returned more values that need resolving, recurse + const resolvable = Tokenization.reverseString(resolved); + if (resolvable.length === 1 && Reference.isReference(resolvable.firstToken)) { + return `(${resolvable.firstToken.target.node.path}.${resolvable.firstToken.displayName})`; + } + resolved = context.resolve(resolved); + resolved = postProcessor.postProcess(resolved, context); + return resolved; + } catch (e: any) { + let message = `Resolution error: ${e.message}.`; + if (t.creationStack && t.creationStack.length > 0) { + message += `\nObject creation stack:\n at ${t.creationStack.join('\n at ')}`; + } + + e.message = message; + throw e; + } + } +} From adb7607a9e9b5ba0ed597219dfe577b2228fe32f Mon Sep 17 00:00:00 2001 From: yuanhaoz Date: Wed, 9 Oct 2024 16:18:21 -0700 Subject: [PATCH 2/7] update docstring --- packages/aws-cdk-lib/core/lib/resolvable.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/aws-cdk-lib/core/lib/resolvable.ts b/packages/aws-cdk-lib/core/lib/resolvable.ts index 51d489d7bb0ba..f8fa71c0c447c 100644 --- a/packages/aws-cdk-lib/core/lib/resolvable.ts +++ b/packages/aws-cdk-lib/core/lib/resolvable.ts @@ -215,18 +215,21 @@ export class PolicySynthesizerTokenResolver extends DefaultTokenResolver { /** * PolicySynthesizer Token resolution * - * Resolve the Token, recurse into whatever it returns, - * then finally post-process it. + * Resolve the Token until the token can be resolved into + * "(Path/To/SomeResource.Arn)" format. Otherwise, recurse + * into whatever it returns, */ public resolveToken(t: IResolvable, context: IResolveContext, postProcessor: IPostProcessor) { try { let resolved = t.resolve(context); - // The token might have returned more values that need resolving, recurse + // If the token value is resolvable into the format "(Path/To/SomeResource.Arn)", return it + // as this is the format expected by the Policy Synthesizer. const resolvable = Tokenization.reverseString(resolved); if (resolvable.length === 1 && Reference.isReference(resolvable.firstToken)) { return `(${resolvable.firstToken.target.node.path}.${resolvable.firstToken.displayName})`; } + // The token might have returned more values that need resolving, recurse resolved = context.resolve(resolved); resolved = postProcessor.postProcess(resolved, context); return resolved; From f5ad099932499e5807b8cde2b64c4f8308448f79 Mon Sep 17 00:00:00 2001 From: yuanhaoz Date: Wed, 9 Oct 2024 16:19:43 -0700 Subject: [PATCH 3/7] update docstring --- .../aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts b/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts index d1354f8773f24..2a4f16a1eef6b 100644 --- a/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts +++ b/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts @@ -319,8 +319,8 @@ export class PolicySynthesizer extends Construct { if (Reference.isReference(r)) { return `(${r.target.node.path}.${r.displayName})`; } - // Token resolution requires a stack scope. We can't directly use this - // because PolicySynthesizer is always created in the App scope. + // Token resolution requires a stack scope. We can't directly use 'this' scope + // because PolicySynthesizer is always created under 'App' scope. const resolved = Tokenization.resolve(r, { scope: this._scope, resolver: new PolicySynthesizerTokenResolver(new StringConcat()), From 1ce33efd1aef12f51ef1608ce8531f46b31f8e4c Mon Sep 17 00:00:00 2001 From: yuanhaoz Date: Wed, 9 Oct 2024 16:34:51 -0700 Subject: [PATCH 4/7] add more tests --- .../integ.customize-role.js.snapshot/cdk.out | 1 + .../iam-policy-report.json | 33 ++++ .../iam-policy-report.txt | 33 ++++ .../integ-customize-role.assets.json | 19 +++ .../integ-customize-role.template.json | 41 +++++ .../integ.json | 12 ++ ...efaultTestDeployAssert811D838D.assets.json | 19 +++ ...aultTestDeployAssert811D838D.template.json | 36 ++++ .../manifest.json | 115 +++++++++++++ .../tree.json | 157 ++++++++++++++++++ .../test/aws-iam/test/integ.customize-role.ts | 36 ++++ 11 files changed, 502 insertions(+) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.txt create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integ-customize-role.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integ-customize-role.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integiamcustomizeroleDefaultTestDeployAssert811D838D.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integiamcustomizeroleDefaultTestDeployAssert811D838D.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/cdk.out new file mode 100644 index 0000000000000..c6e612584e352 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"38.0.1"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.json new file mode 100644 index 0000000000000..aab8578ff3f55 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.json @@ -0,0 +1,33 @@ +{ + "roles": [ + { + "roleConstructPath": "integ-customize-role/TestRole", + "roleName": "my-precreated-role", + "missing": false, + "assumeRolePolicy": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "sqs.amazonaws.com" + } + } + ], + "managedPolicyArns": [], + "managedPolicyStatements": [], + "identityPolicyStatements": [ + { + "Action": "sqs:SendMessage", + "Effect": "Allow", + "Resource": [ + "arn:aws:s3:::abc/xyz/123.txt", + "(NOVALUE)", + "arn:(PARTITION):iam::(ACCOUNT)/role/FakeRole'", + "(integ-customize-role/MyGroup/Resource.Arn)/*", + "(integ-customize-role/MyGroup/Resource.Arn)" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.txt b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.txt new file mode 100644 index 0000000000000..d0826b6d1eb9f --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.txt @@ -0,0 +1,33 @@ + (integ-customize-role/TestRole) + +AssumeRole Policy: +[ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "sqs.amazonaws.com" + } + } +] + +Managed Policy ARNs: +NONE + +Managed Policies Statements: +NONE + +Identity Policy Statements: +[ + { + "Action": "sqs:SendMessage", + "Effect": "Allow", + "Resource": [ + "arn:aws:s3:::abc/xyz/123.txt", + "(NOVALUE)", + "arn:(PARTITION):iam::(ACCOUNT)/role/FakeRole'", + "(integ-customize-role/MyGroup/Resource.Arn)/*", + "(integ-customize-role/MyGroup/Resource.Arn)" + ] + } +] \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integ-customize-role.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integ-customize-role.assets.json new file mode 100644 index 0000000000000..ced77f405ca79 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integ-customize-role.assets.json @@ -0,0 +1,19 @@ +{ + "version": "38.0.1", + "files": { + "99b010bd74243a5c7fc3fe4f0861127e62239193f1706349d5e1cc8bede9b752": { + "source": { + "path": "integ-customize-role.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "99b010bd74243a5c7fc3fe4f0861127e62239193f1706349d5e1cc8bede9b752.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-iam/test/integ.customize-role.js.snapshot/integ-customize-role.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integ-customize-role.template.json new file mode 100644 index 0000000000000..19256abf8289c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integ-customize-role.template.json @@ -0,0 +1,41 @@ +{ + "Resources": { + "MyGroupCBA54B1B": { + "Type": "AWS::IAM::Group" + } + }, + "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-iam/test/integ.customize-role.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integ.json new file mode 100644 index 0000000000000..9268abe090edd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "38.0.1", + "testCases": { + "integ-iam-customize-role/DefaultTest": { + "stacks": [ + "integ-customize-role" + ], + "assertionStack": "integ-iam-customize-role/DefaultTest/DeployAssert", + "assertionStackName": "integiamcustomizeroleDefaultTestDeployAssert811D838D" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integiamcustomizeroleDefaultTestDeployAssert811D838D.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integiamcustomizeroleDefaultTestDeployAssert811D838D.assets.json new file mode 100644 index 0000000000000..f200334e177fb --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integiamcustomizeroleDefaultTestDeployAssert811D838D.assets.json @@ -0,0 +1,19 @@ +{ + "version": "38.0.1", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "integiamcustomizeroleDefaultTestDeployAssert811D838D.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-iam/test/integ.customize-role.js.snapshot/integiamcustomizeroleDefaultTestDeployAssert811D838D.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integiamcustomizeroleDefaultTestDeployAssert811D838D.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/integiamcustomizeroleDefaultTestDeployAssert811D838D.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-iam/test/integ.customize-role.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/manifest.json new file mode 100644 index 0000000000000..c68843a263202 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/manifest.json @@ -0,0 +1,115 @@ +{ + "version": "38.0.1", + "artifacts": { + "integ-customize-role.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integ-customize-role.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integ-customize-role": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integ-customize-role.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "notificationArns": [], + "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}/99b010bd74243a5c7fc3fe4f0861127e62239193f1706349d5e1cc8bede9b752.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integ-customize-role.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": [ + "integ-customize-role.assets" + ], + "metadata": { + "/integ-customize-role/MyGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyGroupCBA54B1B" + } + ], + "/integ-customize-role/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-customize-role/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-customize-role" + }, + "integiamcustomizeroleDefaultTestDeployAssert811D838D.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integiamcustomizeroleDefaultTestDeployAssert811D838D.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integiamcustomizeroleDefaultTestDeployAssert811D838D": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integiamcustomizeroleDefaultTestDeployAssert811D838D.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "notificationArns": [], + "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": [ + "integiamcustomizeroleDefaultTestDeployAssert811D838D.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": [ + "integiamcustomizeroleDefaultTestDeployAssert811D838D.assets" + ], + "metadata": { + "/integ-iam-customize-role/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-iam-customize-role/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-iam-customize-role/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-iam/test/integ.customize-role.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/tree.json new file mode 100644 index 0000000000000..8ea986612ca8b --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/tree.json @@ -0,0 +1,157 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "integ-customize-role": { + "id": "integ-customize-role", + "path": "integ-customize-role", + "children": { + "MyGroup": { + "id": "MyGroup", + "path": "integ-customize-role/MyGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-customize-role/MyGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Group", + "aws:cdk:cloudformation:props": {} + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Group", + "version": "0.0.0" + } + }, + "TestRole": { + "id": "TestRole", + "path": "integ-customize-role/TestRole", + "children": { + "ImportTestRole": { + "id": "ImportTestRole", + "path": "integ-customize-role/TestRole/ImportTestRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "PrecreatedRoleTestRole": { + "id": "PrecreatedRoleTestRole", + "path": "integ-customize-role/TestRole/PrecreatedRoleTestRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-customize-role/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-customize-role/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "PolicySynthesizer": { + "id": "PolicySynthesizer", + "path": "PolicySynthesizer", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "integ-iam-customize-role": { + "id": "integ-iam-customize-role", + "path": "integ-iam-customize-role", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "integ-iam-customize-role/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "integ-iam-customize-role/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "integ-iam-customize-role/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-iam-customize-role/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-iam-customize-role/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.3.0" + } + } + }, + "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-iam/test/integ.customize-role.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.ts new file mode 100644 index 0000000000000..f4de8a2668069 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.ts @@ -0,0 +1,36 @@ +import { App, Fn, Stack } from 'aws-cdk-lib'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import { Group, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; + +const app = new App(); + +const stack = new Stack(app, 'integ-customize-role'); + +Role.customizeRoles(stack, { + usePrecreatedRoles: { + 'integ-customize-role/TestRole': 'my-precreated-role', + }, +}); + +const group = new Group(stack, 'MyGroup'); + +const role = new Role(stack, 'TestRole', { + assumedBy: new ServicePrincipal('sqs.amazonaws.com'), +}); + +role.addToPolicy(new PolicyStatement({ + resources: [ + 'arn:aws:s3:::abc/xyz/123.txt', + Fn.ref('AWS::NoValue'), + `arn:${Fn.ref('AWS::Partition')}:iam::${Fn.ref('AWS::AccountId')}/role/FakeRole'`, + `${group.groupArn}/*`, + group.groupArn, + ], + actions: ['sqs:SendMessage'], +})); + +new IntegTest(app, 'integ-iam-customize-role', { + testCases: [stack], +}); + +app.synth(); From 787b15b6b6e0a3b31ae7e963bd2343d37b295f39 Mon Sep 17 00:00:00 2001 From: yuanhaoz Date: Wed, 9 Oct 2024 17:01:50 -0700 Subject: [PATCH 5/7] update file import paths --- .../lib/helpers-internal/customize-roles.ts | 44 ++++++++++++++++++- packages/aws-cdk-lib/core/lib/resolvable.ts | 44 ------------------- 2 files changed, 43 insertions(+), 45 deletions(-) diff --git a/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts b/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts index 2a4f16a1eef6b..ea8f7d047428d 100644 --- a/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts +++ b/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts @@ -4,7 +4,7 @@ import { Construct } from 'constructs'; import { Annotations } from '../annotations'; import { attachCustomSynthesis } from '../app'; import { Reference } from '../reference'; -import { IResolvable, StringConcat, PolicySynthesizerTokenResolver } from '../resolvable'; +import { IResolvable, StringConcat, DefaultTokenResolver, IFragmentConcatenator } from '../resolvable'; import { ISynthesisSession } from '../stack-synthesizers'; import { Token, Tokenization } from '../token'; @@ -122,6 +122,48 @@ interface PolicyReportRole { readonly identityPolicyStatements?: string[]; } +/** + * PolicySynthesizer token resolver implementation + * + */ +export class PolicySynthesizerTokenResolver extends DefaultTokenResolver { + constructor(concat: IFragmentConcatenator) { + super(concat); + } + + /** + * PolicySynthesizer Token resolution + * + * Resolve the Token until the token can be resolved into + * "(Path/To/SomeResource.Arn)" format. Otherwise, recurse + * into whatever it returns, + */ + public resolveToken(t: IResolvable, context: any, postProcessor: any) { + try { + let resolved = t.resolve(context); + + // If the token value is resolvable into the format "(Path/To/SomeResource.Arn)", return it + // as this is the format expected by the Policy Synthesizer. + const resolvable = Tokenization.reverseString(resolved); + if (resolvable.length === 1 && Reference.isReference(resolvable.firstToken)) { + return `(${resolvable.firstToken.target.node.path}.${resolvable.firstToken.displayName})`; + } + // The token might have returned more values that need resolving, recurse + resolved = context.resolve(resolved); + resolved = postProcessor.postProcess(resolved, context); + return resolved; + } catch (e: any) { + let message = `Resolution error: ${e.message}.`; + if (t.creationStack && t.creationStack.length > 0) { + message += `\nObject creation stack:\n at ${t.creationStack.join('\n at ')}`; + } + + e.message = message; + throw e; + } + } +} + /** * A construct that is responsible for generating an IAM policy Report * for all IAM roles that are created as part of the CDK application. diff --git a/packages/aws-cdk-lib/core/lib/resolvable.ts b/packages/aws-cdk-lib/core/lib/resolvable.ts index f8fa71c0c447c..fe41ee78d20a1 100644 --- a/packages/aws-cdk-lib/core/lib/resolvable.ts +++ b/packages/aws-cdk-lib/core/lib/resolvable.ts @@ -1,9 +1,7 @@ import { IConstruct } from 'constructs'; import { TokenString } from './private/encoding'; import { TokenMap } from './private/token-map'; -import { Reference } from './reference'; import { TokenizedStringFragments } from './string-fragments'; -import { Tokenization } from './token'; import { ResolutionTypeHint } from './type-hints'; /** @@ -202,45 +200,3 @@ export class DefaultTokenResolver implements ITokenResolver { return fragments.mapTokens({ mapToken: context.resolve }).firstValue; } } - -/** - * PolicySynthesizer token resolver implementation - * - */ -export class PolicySynthesizerTokenResolver extends DefaultTokenResolver { - constructor(concat: IFragmentConcatenator) { - super(concat); - } - - /** - * PolicySynthesizer Token resolution - * - * Resolve the Token until the token can be resolved into - * "(Path/To/SomeResource.Arn)" format. Otherwise, recurse - * into whatever it returns, - */ - public resolveToken(t: IResolvable, context: IResolveContext, postProcessor: IPostProcessor) { - try { - let resolved = t.resolve(context); - - // If the token value is resolvable into the format "(Path/To/SomeResource.Arn)", return it - // as this is the format expected by the Policy Synthesizer. - const resolvable = Tokenization.reverseString(resolved); - if (resolvable.length === 1 && Reference.isReference(resolvable.firstToken)) { - return `(${resolvable.firstToken.target.node.path}.${resolvable.firstToken.displayName})`; - } - // The token might have returned more values that need resolving, recurse - resolved = context.resolve(resolved); - resolved = postProcessor.postProcess(resolved, context); - return resolved; - } catch (e: any) { - let message = `Resolution error: ${e.message}.`; - if (t.creationStack && t.creationStack.length > 0) { - message += `\nObject creation stack:\n at ${t.creationStack.join('\n at ')}`; - } - - e.message = message; - throw e; - } - } -} From f49dd75ce29aa3d4373aab5e31f0ccc15ace6aa2 Mon Sep 17 00:00:00 2001 From: yuanhaoz Date: Wed, 16 Oct 2024 17:15:01 -0700 Subject: [PATCH 6/7] address feedbacks --- .../integ.customize-role.js.snapshot/iam-policy-report.json | 2 +- .../integ.customize-role.js.snapshot/iam-policy-report.txt | 2 +- .../test/aws-iam/test/integ.customize-role.ts | 2 +- packages/aws-cdk-lib/aws-iam/README.md | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.json b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.json index aab8578ff3f55..5158764076512 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.json @@ -22,7 +22,7 @@ "Resource": [ "arn:aws:s3:::abc/xyz/123.txt", "(NOVALUE)", - "arn:(PARTITION):iam::(ACCOUNT)/role/FakeRole'", + "arn:(PARTITION):iam:(REGION):(ACCOUNT)/role/FakeRole'", "(integ-customize-role/MyGroup/Resource.Arn)/*", "(integ-customize-role/MyGroup/Resource.Arn)" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.txt b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.txt index d0826b6d1eb9f..411574c3f4a84 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.txt +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.js.snapshot/iam-policy-report.txt @@ -25,7 +25,7 @@ Identity Policy Statements: "Resource": [ "arn:aws:s3:::abc/xyz/123.txt", "(NOVALUE)", - "arn:(PARTITION):iam::(ACCOUNT)/role/FakeRole'", + "arn:(PARTITION):iam:(REGION):(ACCOUNT)/role/FakeRole'", "(integ-customize-role/MyGroup/Resource.Arn)/*", "(integ-customize-role/MyGroup/Resource.Arn)" ] diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.ts index f4de8a2668069..13f36822fdb6f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-iam/test/integ.customize-role.ts @@ -22,7 +22,7 @@ role.addToPolicy(new PolicyStatement({ resources: [ 'arn:aws:s3:::abc/xyz/123.txt', Fn.ref('AWS::NoValue'), - `arn:${Fn.ref('AWS::Partition')}:iam::${Fn.ref('AWS::AccountId')}/role/FakeRole'`, + `arn:${Fn.ref('AWS::Partition')}:iam:${Fn.ref('AWS::Region')}:${Fn.ref('AWS::AccountId')}/role/FakeRole'`, `${group.groupArn}/*`, group.groupArn, ], diff --git a/packages/aws-cdk-lib/aws-iam/README.md b/packages/aws-cdk-lib/aws-iam/README.md index 16301d68f25ea..354a91570c7aa 100644 --- a/packages/aws-cdk-lib/aws-iam/README.md +++ b/packages/aws-cdk-lib/aws-iam/README.md @@ -242,8 +242,8 @@ Guide](https://github.com/aws/aws-cdk/wiki/Security-And-Safety-Dev-Guide) When `customizeRoles` is used, the `iam-policy-report.txt` report will contain a list of IAM roles and associated permissions that would have been created. This report is -generated so that it attempts to resolve any references and replace with a more user -friendly value. +generated in an attempt to resolve and replace any references with a more user-friendly +value. The following are some examples of the value that will appear in the report: @@ -293,7 +293,7 @@ The policy report will instead get: ```json "Resource": [ "(Path/To/SomeResource.Arn)" - "(NoValue)" + "(NOVALUE)" ] ``` From 2f857dbd68730d675cf8d27f60d50226a06e1c44 Mon Sep 17 00:00:00 2001 From: yuanhaoz Date: Thu, 17 Oct 2024 11:41:21 -0700 Subject: [PATCH 7/7] address feedbacks --- .../iam-policy-report.txt | 12 +++++++++--- .../core/lib/helpers-internal/customize-roles.ts | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/iam-policy-report.txt b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/iam-policy-report.txt index 30c4bdd499491..25b1ead7ae780 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/iam-policy-report.txt +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-dynamodb/test/integ.table-with-customized-role.js.snapshot/iam-policy-report.txt @@ -10,7 +10,9 @@ Managed Policies Statements: NONE Identity Policy Statements: -NONE (cdk-table-with-customized-role/Role) +NONE + + (cdk-table-with-customized-role/Role) AssumeRole Policy: [ @@ -48,7 +50,9 @@ Identity Policy Statements: "(cdk-table-with-customized-role/Table/Resource.Arn)/index/*" ] } -] (cdk-table-with-customized-role2/Table/ScalingRole) +] + + (cdk-table-with-customized-role2/Table/ScalingRole) AssumeRole Policy: NONE @@ -60,7 +64,9 @@ Managed Policies Statements: NONE Identity Policy Statements: -NONE (cdk-table-with-customized-role2/Role) +NONE + + (cdk-table-with-customized-role2/Role) AssumeRole Policy: [ diff --git a/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts b/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts index ea8f7d047428d..c456cfb2665db 100644 --- a/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts +++ b/packages/aws-cdk-lib/core/lib/helpers-internal/customize-roles.ts @@ -240,7 +240,7 @@ export class PolicySynthesizer extends Construct { '', 'Identity Policy Statements:', this.toJsonString(role.identityPolicyStatements), - ].join('\n')).join(''); + ].join('\n')).join('\n\n'); } /**