constructor()

in source/labs/msk-lambda-role.ts [23:204]


    constructor(scope: cdk.Construct, id: string, props: SolutionStackProps) {
        super(scope, id, props);

        const ec2Role = new iam.Role(this, 'EC2Role', {
            assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com')
        });

        const assetsBucket = s3.Bucket.fromBucketName(this, 'AssetsBucket', 'reinvent2019-msk-liftandshift');

        const policy = new iam.Policy(this, 'KafkaClientEC2InstancePolicy', {
            statements: [
                new iam.PolicyStatement({
                    sid: 'S3AssetsPolicy',
                    effect: iam.Effect.ALLOW,
                    actions: ['s3:GetObject', 's3:ListBucket'],
                    resources: [assetsBucket.bucketArn, assetsBucket.arnForObjects('*')]
                }),

                new iam.PolicyStatement({
                    sid: 'MskMetadataPolicy',
                    effect: iam.Effect.ALLOW,
                    actions: ['kafka:DescribeCluster', 'kafka:GetBootstrapBrokers'],
                    resources: ['*']
                }),

                new iam.PolicyStatement({
                    sid: 'CloudFormationStacksPolicy',
                    effect: iam.Effect.ALLOW,
                    actions: ['cloudformation:DescribeStacks'],
                    resources: [`arn:${cdk.Aws.PARTITION}:cloudformation:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:stack/*/*`]
                }),

                new iam.PolicyStatement({
                    sid: 'ProducerGluePolicy',
                    effect: iam.Effect.ALLOW,
                    actions: [
                        'glue:CreateSchema',
                        'glue:GetSchemaByDefinition',
                        'glue:RegisterSchemaVersion'
                    ],
                    resources: [
                        `arn:${cdk.Aws.PARTITION}:glue:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:registry/default-registry`,
                        `arn:${cdk.Aws.PARTITION}:glue:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:schema/*`
                    ]
                }),

                /*
                    There are some assumptions in the policies below (from https://github.com/aws-samples/integration-sample-lambda-msk):
                        - The SAM bucket will be named `lambda-artifacts-[random-value]`
                        - The CloudFormation stack will be named `MSKToS3` (and some resources will have that as a prefix)
                */

                new iam.PolicyStatement({
                    sid: 'SamS3Policy',
                    effect: iam.Effect.ALLOW,
                    actions: [
                        's3:CreateBucket',
                        's3:DeleteBucket',
                        's3:DeleteObject',
                        's3:GetObject',
                        's3:ListBucket',
                        's3:PutObject'
                    ],
                    resources: [
                        `arn:${cdk.Aws.PARTITION}:s3:::lambda-artifacts-*`,
                        `arn:${cdk.Aws.PARTITION}:s3:::msktos3-*`,
                        `arn:${cdk.Aws.PARTITION}:s3:::lambda-artifacts-*/*`,
                        `arn:${cdk.Aws.PARTITION}:s3:::msktos3-*/*`,
                    ]
                }),

                new iam.PolicyStatement({
                    sid: 'SamCloudFormationPolicy',
                    effect: iam.Effect.ALLOW,
                    actions: [
                        'cloudformation:CreateChangeSet',
                        'cloudformation:DeleteStack',
                        'cloudformation:DescribeChangeSet',
                        'cloudformation:DescribeStackEvents',
                        'cloudformation:DescribeStackResource',
                        'cloudformation:ExecuteChangeSet',
                        'cloudformation:GetTemplateSummary',
                        'cloudformation:ListStackResources',
                        'cloudformation:UpdateStack'
                    ],
                    resources: [
                        `arn:${cdk.Aws.PARTITION}:cloudformation:${cdk.Aws.REGION}:aws:transform/Serverless-2016-10-31`,
                        `arn:${cdk.Aws.PARTITION}:cloudformation:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:stack/MSKToS3/*`,
                    ]
                }),

                new iam.PolicyStatement({
                    sid: 'LambdaMappingPolicy',
                    effect: iam.Effect.ALLOW,
                    actions: [
                        'lambda:CreateEventSourceMapping',
                        'lambda:DeleteEventSourceMapping',
                        'lambda:GetEventSourceMapping',
                        'lambda:ListEventSourceMappings'
                    ],
                    resources: ['*']
                }),

                new iam.PolicyStatement({
                    sid: 'LambdaVpcPolicy',
                    effect: iam.Effect.ALLOW,
                    actions: [
                        'ec2:DescribeNetworkInterfaces',
                        'ec2:DescribeVpcs',
                        'ec2:DescribeSubnets',
                        'ec2:DescribeSecurityGroups'
                    ],
                    resources: ['*']
                }),

                new iam.PolicyStatement({
                    sid: 'CloudFormationResourcesPolicy',
                    effect: iam.Effect.ALLOW,
                    actions: [
                        'ec2:CreateNetworkInterface',
                        'ec2:DeleteNetworkInterface',
                        'firehose:CreateDeliveryStream',
                        'firehose:DeleteDeliveryStream',
                        'firehose:DescribeDeliveryStream',
                        'iam:AttachRolePolicy',
                        'iam:CreateRole',
                        'iam:DeleteRole',
                        'iam:DeleteRolePolicy',
                        'iam:DetachRolePolicy',
                        'iam:GetRole',
                        'iam:GetRolePolicy',
                        'iam:PassRole',
                        'iam:PutRolePolicy',
                        'lambda:CreateFunction',
                        'lambda:DeleteFunction',
                        'lambda:GetFunction',
                        'logs:DeleteLogGroup'
                    ],
                    resources: [
                        `arn:${cdk.Aws.PARTITION}:ec2:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:network-interface/*`,
                        `arn:${cdk.Aws.PARTITION}:ec2:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:security-group/*`,
                        `arn:${cdk.Aws.PARTITION}:ec2:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:subnet/*`,
                        `arn:${cdk.Aws.PARTITION}:iam::${cdk.Aws.ACCOUNT_ID}:role/MSKToS3-*`,
                        `arn:${cdk.Aws.PARTITION}:firehose:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:deliverystream/MSKToS3-*`,
                        `arn:${cdk.Aws.PARTITION}:lambda:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:function:MSKToS3-*`,
                        `arn:${cdk.Aws.PARTITION}:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:log-group:/aws/lambda/MSKToS3-*`
                    ]
                })
            ]
        });

        policy.attachToRole(ec2Role);

        CfnNagHelper.addSuppressions(
            policy.node.defaultChild as iam.CfnPolicy,
            [
                {
                    Id: 'W12',
                    Reason: 'Some actions do not support resource level permissions'
                },
                {
                    Id: 'W76',
                    Reason: 'SPCM is higher than 25 since role is used for several tasks during a lab'
                }
            ]
        );

        //---------------------------------------------------------------------
        // Solution metrics
        new SolutionHelper(this, 'SolutionHelper', {
            solutionId: props.solutionId,
            pattern: MskLambdaRoleStack.name
        });

        //---------------------------------------------------------------------
        // Outputs
        new cdk.CfnOutput(this, 'KafkaClientEC2Role', {
            value: ec2Role.roleName,
            description: 'IAM role for the EC2 instance',
            exportName: `${cdk.Aws.STACK_NAME}-KafkaClientEC2Role`
        });
    }