def _add_imagebuilder_image(self, build_tags, lambda_cleanup_policy_statements): # ImageBuilderImage image_resource = imagebuilder.CfnImage( self, IMAGEBUILDER_RESOURCE_NAME_PREFIX, tags=build_tags, image_recipe_arn=Fn.ref("ImageRecipe"), infrastructure_configuration_arn=Fn.ref( "InfrastructureConfiguration"), distribution_configuration_arn=Fn.ref("DistributionConfiguration"), enhanced_image_metadata_enabled=False, ) if not self.custom_cleanup_lambda_role: self._add_resource_delete_policy( lambda_cleanup_policy_statements, ["imagebuilder:DeleteImage"], [ self.format_arn( service="imagebuilder", resource="image", resource_name="{0}/*".format( self._build_image_recipe_name(to_lower=True)), ) ], ) return image_resource
def _add_imagebuilder_infrastructure_configuration( self, build_tags, instance_profile_name, lambda_cleanup_policy_statements ): # ImageBuilderInfrastructureConfiguration infrastructure_configuration_resource = imagebuilder.CfnInfrastructureConfiguration( self, "InfrastructureConfiguration", name=self._build_resource_name(IMAGEBUILDER_RESOURCE_NAME_PREFIX), tags=build_tags, instance_profile_name=instance_profile_name or Fn.ref("InstanceProfile"), terminate_instance_on_failure=self.config.dev_settings.terminate_instance_on_failure if self.config.dev_settings and self.config.dev_settings.terminate_instance_on_failure is not None else True, instance_types=[self.config.build.instance_type], security_group_ids=self.config.build.security_group_ids, subnet_id=self.config.build.subnet_id, sns_topic_arn=Fn.ref("BuildNotificationTopic"), ) if not self.custom_cleanup_lambda_role: self._add_resource_delete_policy( lambda_cleanup_policy_statements, ["imagebuilder:DeleteInfrastructureConfiguration"], [ self.format_arn( service="imagebuilder", resource="infrastructure-configuration", resource_name="{0}".format( self._build_resource_name(IMAGEBUILDER_RESOURCE_NAME_PREFIX, to_lower=True) ), ) ], ) return infrastructure_configuration_resource
def _add_instance_profile(self, cleanup_policy_statements, instance_role=None): """Set default instance profile in imagebuilder cfn template.""" instance_profile_resource = iam.CfnInstanceProfile( self, "InstanceProfile", path=IAM_ROLE_PATH, roles=[ instance_role.split("/")[-1] if instance_role else Fn.ref("InstanceRole") ], instance_profile_name=self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX), ) if not self.custom_cleanup_lambda_role: self._add_resource_delete_policy( cleanup_policy_statements, ["iam:DeleteInstanceProfile"], [ self.format_arn( service="iam", region="", resource="instance-profile", resource_name="{0}/{1}".format( IAM_ROLE_PATH.strip("/"), self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX), ), ) ], ) return instance_profile_resource
def __create_s3_trigger_lambda_invoke_permission( self, bucket_name: str, s3_trigger_lambda_function: aws_lambda.Function ) -> aws_lambda.Permission: return aws_lambda.CfnPermission( self, 'S3TriggerLambdaInvokePermission', function_name=s3_trigger_lambda_function.function_name, action='lambda:InvokeFunction', principal='s3.amazonaws.com', source_account=Fn.ref('AWS::AccountId'), source_arn=f'arn:aws:s3:::{bucket_name}')
def _add_custom_components(self, components, policy_statements, components_resources): """Set custom component in imagebuilder cfn template.""" initial_components_len = len(components) arn_components_len = 0 for custom_component in self.config.build.components: custom_components_len = len( components) - initial_components_len - arn_components_len if custom_component.type == "arn": components.append( imagebuilder.CfnImageRecipe.ComponentConfigurationProperty( component_arn=custom_component.value)) arn_components_len += 1 else: component_script_name = custom_component.value.split("/")[-1] component_id = "ScriptComponent" + str(custom_components_len) custom_component_resource = imagebuilder.CfnComponent( self, component_id, name=self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX + "-Script-{0}".format(str(custom_components_len))), version=utils.get_installed_version( base_version_only=True), description= "This component is custom component for script, script name is {0}, script url is " "{1}".format(component_script_name, custom_component.value), platform="Linux", data=wrap_script_to_component(custom_component.value), ) components.append( imagebuilder.CfnImageRecipe.ComponentConfigurationProperty( component_arn=Fn.ref(component_id))) components_resources.append(custom_component_resource) if not self.custom_cleanup_lambda_role: self._add_resource_delete_policy( policy_statements, ["imagebuilder:DeleteComponent"], [ self.format_arn( service="imagebuilder", resource="component", resource_name="{0}/*".format( self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX + "-Script-{0}".format( str(custom_components_len)), to_lower=True, )), ) ], )
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) # IAM section admin_role = iam.Role(self, "admin", assumed_by=iam.AccountPrincipal(Fn.ref("AWS::AccountId"))) self.dev_role = iam.Role(self, "developer", assumed_by=iam.AccountPrincipal(Fn.ref("AWS::AccountId"))) admin_role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name("AdministratorAccess")) self.dev_role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name("ReadOnlyAccess")) # VPC section self.vpc = ec2.Vpc(self, "vpc", cidr="10.0.0.0/16", enable_dns_hostnames=True, enable_dns_support=True, max_azs=3, nat_gateways=1, subnet_configuration=[ ec2.SubnetConfiguration(name="Public", subnet_type=ec2.SubnetType.PUBLIC, cidr_mask=24), ec2.SubnetConfiguration(name="Private", subnet_type=ec2.SubnetType.PRIVATE, cidr_mask=24) ])
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) env = "dev" project = "testproject1" service = "etl" component = "workflow" Tag.add(self, "Service", service) Tag.add(self, "Component", component) param_dwh = CfnParameter( self, "ParamDWH", type="String", description="The domain of the DWH to connect to. | team=data,service=dwh", default="fakedwh.host", ) value_raw = "import: ${value_to_import}, param: ${param_dwh}" value = Fn.sub( value_raw, { "value_to_import": Fn.import_value( generate_resource_name(project, env, service, "buckets", "bucketb") ), "param_dwh": Fn.ref(param_dwh.logical_id), }, ) aws_ssm.StringParameter( self, "SSMParam", parameter_name=generate_resource_name( project, env, service, component, "ssmparam" ), string_value=value, )
def _add_lambda_cleanup(self, policy_statements, build_tags): lambda_cleanup_execution_role = None if self.custom_cleanup_lambda_role: execution_role = self.custom_cleanup_lambda_role else: # LambdaCleanupPolicies self._add_resource_delete_policy( policy_statements, ["cloudformation:DeleteStack"], [ self.format_arn( service="cloudformation", resource="stack", resource_name="{0}/{1}".format( self.image_id, self._stack_unique_id()), ) ], ) self._add_resource_delete_policy( policy_statements, ["ec2:CreateTags"], [ self.format_arn( service="ec2", account="", resource="image", region=region, resource_name="*", ) for region in self._get_distribution_regions() ], ) self._add_resource_delete_policy( policy_statements, ["tag:TagResources"], ["*"], ) self._add_resource_delete_policy( policy_statements, [ "iam:DetachRolePolicy", "iam:DeleteRole", "iam:DeleteRolePolicy" ], [ self.format_arn( service="iam", resource="role", region="", resource_name="{0}/{1}".format( IAM_ROLE_PATH.strip("/"), self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX + "Cleanup"), ), ) ], ) self._add_resource_delete_policy( policy_statements, ["lambda:DeleteFunction", "lambda:RemovePermission"], [ self.format_arn( service="lambda", resource="function", sep=":", resource_name=self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX), ) ], ) self._add_resource_delete_policy( policy_statements, ["logs:DeleteLogGroup"], [ self.format_arn( service="logs", resource="log-group", sep=":", resource_name="/aws/lambda/{0}:*".format( self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX)), ) ], ) self._add_resource_delete_policy( policy_statements, ["iam:RemoveRoleFromInstanceProfile"], [ self.format_arn( service="iam", resource="instance-profile", region="", resource_name="{0}/{1}".format( IAM_ROLE_PATH.strip("/"), self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX), ), ) ], ) self._add_resource_delete_policy( policy_statements, ["iam:DetachRolePolicy", "iam:DeleteRolePolicy"], [ self.format_arn( service="iam", resource="role", region="", resource_name="{0}/{1}".format( IAM_ROLE_PATH.strip("/"), self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX), ), ) ], ) self._add_resource_delete_policy( policy_statements, [ "SNS:GetTopicAttributes", "SNS:DeleteTopic", "SNS:Unsubscribe" ], [ self.format_arn( service="sns", resource="{0}".format( self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX)), ) ], ) policy_document = iam.PolicyDocument(statements=policy_statements) managed_lambda_policy = [ Fn.sub( "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" ), ] # LambdaCleanupExecutionRole lambda_cleanup_execution_role = iam.CfnRole( self, "DeleteStackFunctionExecutionRole", managed_policy_arns=managed_lambda_policy, assume_role_policy_document=get_assume_role_policy_document( "lambda.amazonaws.com"), path=IAM_ROLE_PATH, policies=[ iam.CfnRole.PolicyProperty( policy_document=policy_document, policy_name="LambdaCleanupPolicy", ), ], tags=build_tags, role_name=self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX + "Cleanup"), ) execution_role = lambda_cleanup_execution_role.attr_arn # LambdaCleanupEnv lambda_env = awslambda.CfnFunction.EnvironmentProperty( variables={"IMAGE_STACK_ARN": self.stack_id}) # LambdaCWLogGroup lambda_log = logs.CfnLogGroup( self, "DeleteStackFunctionLog", log_group_name="/aws/lambda/{0}".format( self._build_resource_name(IMAGEBUILDER_RESOURCE_NAME_PREFIX)), ) # LambdaCleanupFunction lambda_cleanup = awslambda.CfnFunction( self, "DeleteStackFunction", function_name=self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX), code=awslambda.CfnFunction.CodeProperty( s3_bucket=self.config.custom_s3_bucket or S3Bucket.get_bucket_name( AWSApi.instance().sts.get_account_id(), get_region()), s3_key=self.bucket.get_object_key(S3FileType.CUSTOM_RESOURCES, "artifacts.zip"), ), handler="delete_image_stack.handler", memory_size=128, role=execution_role, runtime="python3.8", timeout=900, environment=lambda_env, tags=build_tags, ) permission = awslambda.CfnPermission( self, "DeleteStackFunctionPermission", action="lambda:InvokeFunction", principal="sns.amazonaws.com", function_name=lambda_cleanup.attr_arn, source_arn=Fn.ref("BuildNotificationTopic"), ) lambda_cleanup.add_depends_on(lambda_log) return lambda_cleanup, permission, lambda_cleanup_execution_role, lambda_log
def _add_imagebuilder_components(self, build_tags, lambda_cleanup_policy_statements): imagebuilder_resources_dir = os.path.join( imagebuilder_utils.get_resources_directory(), "imagebuilder") # ImageBuilderComponents components = [] components_resources = [] if self.config.build and self.config.build.update_os_packages and self.config.build.update_os_packages.enabled: update_os_component_resource = imagebuilder.CfnComponent( self, "UpdateOSComponent", name=self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX + "-UpdateOS"), version=utils.get_installed_version(base_version_only=True), tags=build_tags, description="Update OS and Reboot", platform="Linux", data=Fn.sub( _load_yaml(imagebuilder_resources_dir, "update_and_reboot.yaml")), ) components.append( imagebuilder.CfnImageRecipe.ComponentConfigurationProperty( component_arn=Fn.ref("UpdateOSComponent"))) components_resources.append(update_os_component_resource) if not self.custom_cleanup_lambda_role: self._add_resource_delete_policy( lambda_cleanup_policy_statements, ["imagebuilder:DeleteComponent"], [ self.format_arn( service="imagebuilder", resource="component", resource_name="{0}/*".format( self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX + "-UpdateOS", to_lower=True)), ) ], ) disable_pcluster_component = ( self.config.dev_settings.disable_pcluster_component if self.config.dev_settings and self.config.dev_settings.disable_pcluster_component else False) if not disable_pcluster_component: parallelcluster_component_resource = imagebuilder.CfnComponent( self, "ParallelClusterComponent", name=self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX), version=utils.get_installed_version(base_version_only=True), tags=build_tags, description="Install ParallelCluster software stack", platform="Linux", data=Fn.sub( _load_yaml(imagebuilder_resources_dir, "parallelcluster.yaml")), ) components.append( imagebuilder.CfnImageRecipe.ComponentConfigurationProperty( component_arn=Fn.ref("ParallelClusterComponent"))) components_resources.append(parallelcluster_component_resource) if not self.custom_cleanup_lambda_role: self._add_resource_delete_policy( lambda_cleanup_policy_statements, ["imagebuilder:DeleteComponent"], [ self.format_arn( service="imagebuilder", resource="component", resource_name="{0}/*".format( self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX, to_lower=True)), ) ], ) tag_component_resource = imagebuilder.CfnComponent( self, "ParallelClusterTagComponent", name=self._build_resource_name(IMAGEBUILDER_RESOURCE_NAME_PREFIX + "-Tag"), version=utils.get_installed_version(base_version_only=True), tags=build_tags, description="Tag ParallelCluster AMI", platform="Linux", data=_load_yaml(imagebuilder_resources_dir, "parallelcluster_tag.yaml"), ) components.append( imagebuilder.CfnImageRecipe.ComponentConfigurationProperty( component_arn=Fn.ref("ParallelClusterTagComponent"))) components_resources.append(tag_component_resource) if not self.custom_cleanup_lambda_role: self._add_resource_delete_policy( lambda_cleanup_policy_statements, ["imagebuilder:DeleteComponent"], [ self.format_arn( service="imagebuilder", resource="component", resource_name="{0}/*".format( self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX + "-Tag", to_lower=True)), ) ], ) if self.config.build.components: self._add_custom_components(components, lambda_cleanup_policy_statements, components_resources) disable_validate_and_test_component = ( self.config.dev_settings.disable_validate_and_test if self.config.dev_settings and self.config.dev_settings.disable_validate_and_test else False) if not disable_pcluster_component and not disable_validate_and_test_component: validate_component_resource = imagebuilder.CfnComponent( self, id="ParallelClusterValidateComponent", name=self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX + "-Validate"), version=utils.get_installed_version(base_version_only=True), tags=build_tags, description="Validate ParallelCluster AMI", platform="Linux", data=_load_yaml(imagebuilder_resources_dir, "parallelcluster_validate.yaml"), ) components.append( imagebuilder.CfnImageRecipe.ComponentConfigurationProperty( component_arn=Fn.ref("ParallelClusterValidateComponent"))) components_resources.append(validate_component_resource) if not self.custom_cleanup_lambda_role: self._add_resource_delete_policy( lambda_cleanup_policy_statements, ["imagebuilder:DeleteComponent"], [ self.format_arn( service="imagebuilder", resource="component", resource_name="{0}/*".format( self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX + "-Validate", to_lower=True)), ) ], ) test_component_resource = imagebuilder.CfnComponent( self, id="ParallelClusterTestComponent", name=self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX + "-Test"), version=utils.get_installed_version(base_version_only=True), tags=build_tags, description="Test ParallelCluster AMI", platform="Linux", data=_load_yaml(imagebuilder_resources_dir, "parallelcluster_test.yaml"), ) components.append( imagebuilder.CfnImageRecipe.ComponentConfigurationProperty( component_arn=Fn.ref("ParallelClusterTestComponent"))) components_resources.append(test_component_resource) if not self.custom_cleanup_lambda_role: self._add_resource_delete_policy( lambda_cleanup_policy_statements, ["imagebuilder:DeleteComponent"], [ self.format_arn( service="imagebuilder", resource="component", resource_name="{0}/*".format( self._build_resource_name( IMAGEBUILDER_RESOURCE_NAME_PREFIX + "-Test", to_lower=True)), ) ], ) return components, components_resources