constructor()

in use_cases/custom-cloud9-ssm/lib/index.ts [106:205]


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

        let cloud9Env: cloud9.Ec2Environment

        // Create the Cloud9 environment using the default configuration
        if (!props.cloud9Ec2Props) {
            cloud9Env = new cloud9.Ec2Environment(this,'Cloud9Ec2Environment', {
                vpc: new ec2.Vpc(this, id + '-VPC', {
                    maxAzs: 2
                })
            })
        }
        // Create the Cloud9 environment using the received props
        else {
            cloud9Env = new cloud9.Ec2Environment(this,'Cloud9Ec2Environment', props.cloud9Ec2Props)
        }

        // Create a Role for the EC2 instance and an instance profile with it
        this.ec2Role = new iam.Role(this,'Ec2Role', {
            assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
            roleName: id + '-CustomCloud9SsmEc2Role',
            managedPolicies: [
                iam.ManagedPolicy.fromManagedPolicyArn(
                    this,
                    id + '-SsmManagedPolicy',
                    'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore'
                )
            ]
        })
        const instanceProfile = new iam.CfnInstanceProfile(this,'Ec2InstanceProfile', {
            roles: [this.ec2Role.roleName]
        })

        // Create the SSM Document using the default configuration
        if (!props.ssmDocumentProps) {
            let content: string = fs.readFileSync(CustomCloud9Ssm.DEFAULT_DOCUMENT_FILE_NAME, 'utf8')

            const ssmDocumentProps = {
                documentType: 'Command',
                content: yaml.parse(content),
                name: id + '-' + CustomCloud9Ssm.DEFAULT_DOCUMENT_NAME
            }

            this.document = new ssm.CfnDocument(this,'SsmDocument', ssmDocumentProps)
            this.resizeEBSTo(CustomCloud9Ssm.DEFAULT_EBS_SIZE)
        }
        // Create the SSM Document using the received props
        else {
            if (!props.ssmDocumentProps.name) {
                throw new Error("The document name must be specified.")
            }

            this.document = new ssm.CfnDocument(this,'SsmDocument', props.ssmDocumentProps)
        }

        // Create an SSM Association to apply the document configuration
        new ssm.CfnAssociation(this,'SsmAssociation', {
            name: this.document.name as string,
            targets: [
                {
                    key: 'tag:aws:cloud9:environment',
                    values: [cloud9Env.environmentId]
                }
            ]
        })

        // Create the Lambda function that attaches the instance profile to the EC2 instance
        let code: string = fs.readFileSync(CustomCloud9Ssm.ATTACH_PROFILE_FILE_NAME, 'utf8')

        const lambdaFunction = new lambda.Function(this,'LambdaFunction', {
            runtime: lambda.Runtime.PYTHON_3_6,
            code: lambda.Code.fromInline(code),
            handler: 'index.handler',
            timeout: cdk.Duration.seconds(60)
        })

        // Give permissions to the function to execute some APIs
        lambdaFunction.addToRolePolicy(new iam.PolicyStatement({
            effect: iam.Effect.ALLOW,
            actions: [
                'ec2:DescribeInstances',
                'ec2:AssociateIamInstanceProfile',
                'ec2:ReplaceIamInstanceProfileAssociation',
                'ec2:RebootInstances',
                'iam:ListInstanceProfiles',
                'iam:PassRole'
            ],
            resources: ['*']
        }))

        // Create the Custom Resource that invokes the Lambda function
        new cdk.CustomResource(this, 'CustomResource', {
            serviceToken: lambdaFunction.functionArn,
            properties: {
                cloud9_env_id: cloud9Env.environmentId,
                profile_arn: instanceProfile.attrArn
            }
        })
    }