def _default_lambda_role(self): lambda_trust_policy = make_simple_assume_policy('lambda.amazonaws.com') return self._add( r.aws_iam_role(self.titled('role'), name=self.env_titled('role'), assume_role_policy=lambda_trust_policy.to_json()))
def _get_replicated_lambda_state_machine_role( self, remover_function, # type: Dict[str, Union[awslambda.Function, iam.Role, Any]] # noqa pylint: disable=line-too-long self_destruct_function # type: Dict[str, Union[awslambda.Function, iam.Role, Any]] # noqa pylint: disable=line-too-long ): # type (...) -> iam.Role entity = Join('.', ['states', Region, 'amazonaws.com']) return self.template.add_resource( iam.Role( 'StateMachineRole', AssumeRolePolicyDocument=make_simple_assume_policy(entity), Policies=[ iam.Policy( PolicyName="InvokeLambda", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[awacs.awslambda.InvokeFunction], Effect=Allow, Resource=[ remover_function.get_att('Arn'), self_destruct_function.get_att('Arn') ]) ])) ]))
def add_lambda_execution_role( self, name='LambdaExecutionRole', # type: str function_name='' # type: str ): # noqa: E124 # type: (...) -> iam.Role """Create the Lambda@Edge execution role.""" variables = self.get_variables() lambda_resource = Join('', [ 'arn:', Partition, ':logs:*:', AccountId, ':log-group:/aws/lambda/', StackName, '-%s-*' % function_name ]) edge_resource = Join('', [ 'arn:', Partition, ':logs:*:', AccountId, ':log-group:/aws/lambda/*.', StackName, '-%s-*' % function_name, ]) return self.template.add_resource( iam.Role( name, AssumeRolePolicyDocument=make_simple_assume_policy( 'lambda.amazonaws.com', 'edgelambda.amazonaws.com'), PermissionsBoundary=(variables['RoleBoundaryArn'] if self.role_boundary_specified else NoValue), Policies=[ iam.Policy(PolicyName="LambdaLogCreation", PolicyDocument=PolicyDocument( Version='2012-10-17', Statement=[ Statement(Action=[ awacs.logs.CreateLogGroup, awacs.logs.CreateLogStream, awacs.logs.PutLogEvents ], Effect=Allow, Resource=[ lambda_resource, edge_resource ]) ])), ], ))
def _get_replicated_lambda_state_machine_role( self, remover_function, # type: Dict[str, Union[awslambda.Function, iam.Role, Any]] self_destruct_function, # type: Dict[str, Union[awslambda.Function, iam.Role, Any]] ): # type (...) -> iam.Role variables = self.get_variables() entity = Join(".", ["states", Region, "amazonaws.com"]) return self.template.add_resource( iam.Role( "StateMachineRole", AssumeRolePolicyDocument=make_simple_assume_policy(entity), PermissionsBoundary=( variables["RoleBoundaryArn"] if self.role_boundary_specified else NoValue ), Policies=[ iam.Policy( PolicyName="InvokeLambda", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[awacs.awslambda.InvokeFunction], Effect=Allow, Resource=[ remover_function.get_att("Arn"), self_destruct_function.get_att("Arn"), ], ) ], ), ) ], ) )
def _get_replicated_lambda_state_machine_role(self, remover_function, # type: Dict[str, Union[awslambda.Function, iam.Role, Any]] # noqa pylint: disable=line-too-long self_destruct_function # type: Dict[str, Union[awslambda.Function, iam.Role, Any]] # noqa pylint: disable=line-too-long # TODO remove after dropping python 2 ): # pylint: disable=bad-continuation # type (...) -> iam.Role variables = self.get_variables() entity = Join('.', ['states', Region, 'amazonaws.com']) return self.template.add_resource( iam.Role( 'StateMachineRole', AssumeRolePolicyDocument=make_simple_assume_policy(entity), PermissionsBoundary=( variables['RoleBoundaryArn'] if self.role_boundary_specified else NoValue ), Policies=[ iam.Policy( PolicyName="InvokeLambda", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[awacs.awslambda.InvokeFunction], Effect=Allow, Resource=[ remover_function.get_att('Arn'), self_destruct_function.get_att('Arn') ] ) ] ) ) ] ) )
def create_template(self): """Create template (main function called by Stacker).""" template = self.template # variables = self.get_variables() template.add_version('2010-09-09') template.add_description('Kubernetes IAM policies - V1.0.0') # Resources nodeinstancerole = template.add_resource( iam.Role( 'NodeInstanceRole', AssumeRolePolicyDocument=make_simple_assume_policy( 'ec2.amazonaws.com'), ManagedPolicyArns=[ IAM_POLICY_ARN_PREFIX + i for i in [ 'AmazonEKSWorkerNodePolicy', 'AmazonEKS_CNI_Policy', 'AmazonEC2ContainerRegistryReadOnly', # SSM agent not shipped ootb # 'AmazonSSMManagedInstanceCore' ] ])) template.add_output( Output('NodeInstanceRole', Description='The node instance role name', Value=nodeinstancerole.ref())) template.add_output( Output('NodeInstanceRoleArn', Description='The node instance role ARN', Value=nodeinstancerole.get_att('Arn'))) nodeinstanceprofile = template.add_resource( iam.InstanceProfile('NodeInstanceProfile', Path='/', Roles=[nodeinstancerole.ref()])) template.add_output( Output('NodeInstanceProfile', Description='The node instance profile', Value=nodeinstanceprofile.ref())) template.add_output( Output('NodeInstanceProfileArn', Description='The node instance profile ARN', Value=nodeinstanceprofile.get_att('Arn'))) template.add_resource( iam.Role( 'ClusterAutoScalerInstanceRole', AssumeRolePolicyDocument=make_simple_assume_policy( 'ec2.amazonaws.com'), Policies=[ iam.Policy( PolicyName='cluster-autoscaler', PolicyDocument=PolicyDocument( Version='2012-10-17', Statement=[ Statement( Action=[ awacs.autoscaling. DescribeAutoScalingGroups, # noqa awacs.autoscaling. DescribeAutoScalingInstances, # noqa awacs.autoscaling.DescribeTags, awacs.autoscaling. SetDesiredCapacity, # noqa awacs.autoscaling. TerminateInstanceInAutoScalingGroup ], # noqa pylint: disable=line-too-long Effect=Allow, Resource=['*']) ])) ]))
def add_test_resources(test_name): """Add the resources for the given test.""" codebuild_role = template.add_resource( iam.Role( "CodeBuildRole{}".format(test_name), AssumeRolePolicyDocument=make_simple_assume_policy( "codebuild.amazonaws.com"), Policies=IAM_POLICY_BUILDER.build(test_name), )) template.add_resource( codebuild.Project( f"RunwayIntegrationTest{test_name}", Artifacts=codebuild.Artifacts(Type="NO_ARTIFACTS"), Description=f"{test_name} runway integration tests", Environment=codebuild.Environment( ComputeType="BUILD_GENERAL1_SMALL", EnvironmentVariables=[ codebuild.EnvironmentVariable( Name="DEPLOY_ENVIRONMENT", Type="PLAINTEXT", Value=variables["EnvironmentName"].ref, ), codebuild.EnvironmentVariable( Name="TEST_TO_RUN", Type="PLAINTEXT", Value=test_name.lower(), ), codebuild.EnvironmentVariable( # Disable emojis in output. Name="PIPENV_HIDE_EMOJIS", Type="PLAINTEXT", Value="1", ), codebuild.EnvironmentVariable( # disable terminal spinner. Name="PIPENV_NOSPIN", Type="PLAINTEXT", Value="1", ), codebuild.EnvironmentVariable( # Pipenv automatically assumes “yes” at all prompts. Name="PIPENV_YES", Type="PLAINTEXT", Value="1", ), ], Image="aws/codebuild/standard:2.0", Type="LINUX_CONTAINER", ), Name=f"runway-int-test-{test_name}", ServiceRole=codebuild_role.get_att("Arn"), Source=codebuild.Source( Type="GITHUB", Location=variables["GitHubUrl"].ref), Triggers=codebuild.ProjectTriggers( Webhook=True, FilterGroups=[[ codebuild.WebhookFilter( Type="ACTOR_ACCOUNT_ID", Pattern="|".join( str(x) for x in GITHUB_ACCOUNT_IDS), ), codebuild.WebhookFilter( Type="EVENT", Pattern="PULL_REQUEST_CREATED," "PULL_REQUEST_UPDATED," "PULL_REQUEST_REOPENED", ), codebuild.WebhookFilter( Type="BASE_REF", Pattern="^refs/heads/release$"), codebuild.WebhookFilter( Type="HEAD_REF", Pattern="^refs/heads/master$"), ]], ), ))
def create_template(self): """Create template (main function called by Stacker).""" template = self.template variables = self.get_variables() template.add_version('2010-09-09') template.add_description('Kubernetes Master via EKS - V1.0.0') # Resources ccpsecuritygroup = template.add_resource( ec2.SecurityGroup( 'ClusterControlPlaneSecurityGroup', GroupDescription='Cluster communication with worker nodes', Tags=[ {'Key': Sub('kubernetes.io/cluster/${EksClusterName}'), 'Value': 'owned'}, {'Key': 'Product', 'Value': 'Kubernetes'}, {'Key': 'Project', 'Value': 'eks'}, {'Key': 'Name', 'Value': Sub('${EksClusterName}-sg-worker-nodes')} ], VpcId=variables['VPC'].ref ) ) template.add_output( Output( ccpsecuritygroup.title, Description='Cluster communication with worker nodes', Export=Export( Sub('${AWS::StackName}-ControlPlaneSecurityGroup') ), Value=ccpsecuritygroup.ref() ) ) eksservicerole = template.add_resource( iam.Role( 'EksServiceRole', AssumeRolePolicyDocument=make_simple_assume_policy( 'eks.amazonaws.com' ), ManagedPolicyArns=[ IAM_POLICY_ARN_PREFIX + i for i in [ 'AmazonEKSClusterPolicy', 'AmazonEKSServicePolicy' ] ], Policies=[ iam.Policy( PolicyName='EksServiceRolePolicy', PolicyDocument=PolicyDocument( Statement=[ Statement( Action=[awacs.iam.CreateServiceLinkedRole, awacs.iam.PutRolePolicy], Condition=Condition( StringLike( 'iam:AWSServiceName', 'elasticloadbalancing.amazonaws.com' # noqa ) ), Effect=Allow, Resource=[ Sub('arn:aws:iam::${AWS::AccountId}:role/' # noqa 'aws-service-role/' 'elasticloadbalancing.amazonaws.com/' # noqa 'AWSServiceRoleForElasticLoadBalancing*') # noqa ] ) ] ) ) ] ) ) ekscluster = template.add_resource( eks.Cluster( 'EksCluster', Name=variables['EksClusterName'].ref, Version=variables['EksVersion'].ref, RoleArn=eksservicerole.get_att('Arn'), ResourcesVpcConfig=eks.ResourcesVpcConfig( SecurityGroupIds=[ccpsecuritygroup.ref()], SubnetIds=variables['EksSubnets'].ref ) ) ) template.add_output( Output( "%sName" % ekscluster.title, Description='EKS Cluster Name', Export=Export( Sub("${AWS::StackName}-%sName" % ekscluster.title) ), Value=ekscluster.ref() ) ) template.add_output( Output( "%sEndpoint" % ekscluster.title, Description='EKS Cluster Endpoint', Export=Export( Sub("${AWS::StackName}-%sEndpoint" % ekscluster.title) ), Value=ekscluster.get_att('Endpoint') ) ) # Additional Outputs template.add_output( Output( 'VpcId', Description='EKS Cluster VPC Id', Export=Export( Sub('${AWS::StackName}-VpcId') ), Value=variables['VPC'].ref ) ) template.add_output( Output( 'Subnets', Description='EKS Cluster Subnets', Export=Export( Sub('${AWS::StackName}-Subnets') ), Value=Join(',', variables['EksSubnets'].ref) ) )
def get_application_autoscaling_assumerole_policy(region=''): """ Helper function for building the AWS Lambda AssumeRole Policy""" service = make_service_domain_name('application-autoscaling', region) return make_simple_assume_policy(service)
def add_lambda_execution_role(self, name: str = "LambdaExecutionRole", function_name: str = "") -> iam.Role: """Create the Lambda@Edge execution role. Args: name: Name for the Lambda Execution Role. function_name: Name of the Lambda Function the Role will be attached to. """ lambda_resource = Join( "", [ "arn:", Partition, ":logs:*:", AccountId, ":log-group:/aws/lambda/", StackName, "-%s-*" % function_name, ], ) edge_resource = Join( "", [ "arn:", Partition, ":logs:*:", AccountId, ":log-group:/aws/lambda/*.", StackName, "-%s-*" % function_name, ], ) return self.template.add_resource( iam.Role( name, AssumeRolePolicyDocument=make_simple_assume_policy( "lambda.amazonaws.com", "edgelambda.amazonaws.com"), PermissionsBoundary=(self.variables["RoleBoundaryArn"] if self.role_boundary_specified else NoValue), Policies=[ iam.Policy( PolicyName="LambdaLogCreation", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[ awacs.logs.CreateLogGroup, awacs.logs.CreateLogStream, awacs.logs.PutLogEvents, ], Effect=Allow, Resource=[lambda_resource, edge_resource], ) ], ), ), ], ))
def _get_replicated_lambda_remover_lambda(self): # type: () -> Dict[str, Any] res = {} variables = self.get_variables() res["role"] = self.template.add_resource( iam.Role( "ReplicatedLambdaRemoverRole", AssumeRolePolicyDocument=make_simple_assume_policy( "lambda.amazonaws.com" ), PermissionsBoundary=( variables["RoleBoundaryArn"] if self.role_boundary_specified else NoValue ), Policies=[ iam.Policy( PolicyName="LambdaLogCreation", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[ awacs.logs.CreateLogGroup, awacs.logs.CreateLogStream, awacs.logs.PutLogEvents, ], Effect=Allow, Resource=[ Join( "", [ "arn:", Partition, ":logs:*:", AccountId, ":log-group:/aws/lambda/", StackName, "-ReplicatedLambdaRemover-*", ], ) ], ) ], ), ), iam.Policy( PolicyName="DeleteLambda", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[awacs.awslambda.DeleteFunction], Effect=Allow, Resource=self.get_variables()["function_arns"], ) ], ), ), ], ) ) self.template.add_output( Output( "ReplicatedLambdaRemoverRole", Description="The name of the Replicated Lambda Remover Role", Value=res["role"].ref(), ) ) res["function"] = self.template.add_resource( awslambda.Function( "ReplicatedLambdaRemover", Code=awslambda.Code( ZipFile=read_value_from_path( "file://" + os.path.join( os.path.dirname(__file__), "templates/replicated_lambda_remover.template.py", ) ) ), Description="Checks for Replicated Lambdas created during the main stack and " "deletes them when they are ready.", Handler="index.handler", Role=res["role"].get_att("Arn"), Runtime="python3.7", ) ) self.template.add_output( Output( "ReplicatedLambdaRemoverArn", Description="The ARN of the Replicated Function", Value=res["function"].get_att("Arn"), ) ) return res
def _get_self_destruct(self, replicated_lambda_remover): # type: (Dict[str, Union[awslambda.Function, Any]]) -> Dict[str, Any] res = {} variables = self.get_variables() res["role"] = self.template.add_resource( iam.Role( "SelfDestructRole", AssumeRolePolicyDocument=make_simple_assume_policy( "lambda.amazonaws.com" ), PermissionsBoundary=( variables["RoleBoundaryArn"] if self.role_boundary_specified else NoValue ), Policies=[ iam.Policy( PolicyName="LambdaLogCreation", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[ awacs.logs.CreateLogGroup, awacs.logs.CreateLogStream, awacs.logs.PutLogEvents, ], Effect=Allow, Resource=[ Join( "", [ "arn:", Partition, ":logs:*:", AccountId, ":log-group:/aws/lambda/", StackName, "-SelfDestruct-*", ], ) ], ) ], ), ), iam.Policy( PolicyName="DeleteStateMachine", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[awacs.states.DeleteStateMachine], Effect=Allow, Resource=[ # StateMachine Join( "", [ "arn:", Partition, ":states:", Region, ":", AccountId, ":stateMachine:StaticSiteCleanup-", variables["stack_name"], ], ) ], ) ], ), ), iam.Policy( PolicyName="DeleteRolesAndPolicies", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[ awacs.iam.DeleteRolePolicy, awacs.iam.DeleteRole, ], Effect=Allow, Resource=[ Join( "", [ "arn:", Partition, ":iam::", AccountId, ":role/", StackName, "-*", ], ), ], ) ], ), ), iam.Policy( PolicyName="DeleteLambdas", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[awacs.awslambda.DeleteFunction], Effect=Allow, Resource=[ Join( "", [ "arn:", Partition, ":lambda:", Region, ":", AccountId, ":function:%s-SelfDestruct-*" % (variables["stack_name"]), ], ), replicated_lambda_remover["function"].get_att( "Arn" ), ], ) ], ), ), iam.Policy( PolicyName="DeleteStack", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[awacs.cloudformation.DeleteStack], Effect=Allow, Resource=[ Join( "", [ "arn:", Partition, ":cloudformation:", Region, ":", AccountId, ":stack/%s/*" % (variables["stack_name"]), ], ) ], ) ], ), ), ], ) ) self.template.add_output( Output( "SelfDestructLambdaRole", Description="The name of the Self Destruct Role", Value=res["role"].ref(), ) ) res["function"] = self.template.add_resource( awslambda.Function( "SelfDestruct", Code=awslambda.Code( ZipFile=read_value_from_path( "file://" + os.path.join( os.path.dirname(__file__), "templates/self_destruct.template.py", ) ) ), Description="Issues a Delete Stack command to the Cleanup stack", Handler="index.handler", Role=res["role"].get_att("Arn"), Runtime="python3.7", ) ) self.template.add_output( Output( "SelfDestructLambdaArn", Description="The ARN of the Replicated Function", Value=res["function"].get_att("Arn"), ) ) return res
def get_role(self, service_name): service = '{0}.amazonaws.com'.format(service_name) return trust.make_simple_assume_policy(service)
def create_template(self): """Create template (main function called by Stacker).""" template = self.template variables = self.get_variables() template.set_version('2010-09-09') template.set_description('Runway CodeBuild Project') # Resources deploy_name_list = [ 'runway-integration-tests-', variables['EnvironmentName'].ref ] # This must match what is in the the Terraform # integration tests. This corresponds to the template listed in # integration_tests\test_terraform\tf_state.cfn test_suite_prefix = 'testsuite-tf-state' codebuild_role = template.add_resource( iam.Role( 'CodeBuildRole', AssumeRolePolicyDocument=make_simple_assume_policy( 'codebuild.amazonaws.com'), # todo: drop this broad access in favor of more narrow # permissions (will mean identifying all the needed # permissions across all tests) ManagedPolicyArns=[ 'arn:aws:iam::aws:policy/AdministratorAccess' ], Policies=[ iam.Policy( PolicyName=Join('', deploy_name_list + ['-policy']), PolicyDocument=PolicyDocument( Version='2012-10-17', Statement=[ Statement(Action=[ awacs.logs.CreateLogGroup, awacs.logs.CreateLogStream, awacs.logs.PutLogEvents ], Effect=Allow, Resource=[ Join('', [ 'arn:', Partition, ':logs:', Region, ':', AccountId, ':log-group:/aws/codebuild/' ] + deploy_name_list + ['*'] + x) for x in [[':*'], [':*/*']] ]), Statement( Action=[awacs.sts.AssumeRole], Effect=Allow, Resource=[ Join( '', [ 'arn:', Partition, ':iam::', ALT_TESTING_ACCOUNT_ID, ':role/runway-integration-test-role-', # noqa variables['EnvironmentName']. ref ]) ]), Statement( Action=[Action('cloudformation', '*')], Effect=Allow, Resource=[ Join(':', [ 'arn', Partition, 'cloudformation', Region, AccountId, Sub('stack/${prefix}/*', {'prefix': test_suite_prefix}) ]) ]), Statement( Action=[Action('dynamodb', '*')], Effect=Allow, Resource=[ Join(':', [ 'arn', Partition, 'dynamodb', Region, AccountId, Sub('table/${prefix}-*', {'prefix': test_suite_prefix}) ]) ]), Statement( Action=[Action('s3', '*')], Effect=Allow, Resource=[ Join(':', [ 'arn', Partition, Sub('s3:::${prefix}', {'prefix': test_suite_prefix}) ]), Join(':', [ 'arn', Partition, Sub('s3:::${prefix}/*', {'prefix': test_suite_prefix}) ]) ]), Statement( Action=[Action('sqs', '*')], Effect=Allow, Resource=[ Join(':', [ 'arn', Partition, 'sqs', Region, AccountId, 'terraform-*' ]) ]) ])) ])) template.add_resource( codebuild.Project( 'RunwayIntegrationTests', Artifacts=codebuild.Artifacts(Type='NO_ARTIFACTS'), Environment=codebuild.Environment( ComputeType='BUILD_GENERAL1_SMALL', EnvironmentVariables=[ codebuild.EnvironmentVariable(Name='CI', Type='PLAINTEXT', Value='1'), codebuild.EnvironmentVariable( Name='DEPLOY_ENVIRONMENT', Type='PLAINTEXT', Value=variables['EnvironmentName'].ref) ], Image='aws/codebuild/standard:2.0', Type='LINUX_CONTAINER'), Name=Join('', deploy_name_list), ServiceRole=codebuild_role.get_att('Arn'), Source=codebuild.Source(Type='GITHUB', Location=variables['GitHubUrl'].ref), Triggers=codebuild.ProjectTriggers( Webhook=True, FilterGroups=[[ codebuild.WebhookFilter( Type='ACTOR_ACCOUNT_ID', Pattern='|'.join( str(x) for x in GITHUB_ACCOUNT_IDS)), codebuild.WebhookFilter( Type='EVENT', Pattern= 'PULL_REQUEST_CREATED,PULL_REQUEST_UPDATED,PULL_REQUEST_REOPENED' # noqa ), codebuild.WebhookFilter( Type='BASE_REF', Pattern='^refs/heads/release$'), codebuild.WebhookFilter(Type='HEAD_REF', Pattern='^refs/heads/master$') ]])))
def create_template(self): """Create template (main function called by Stacker).""" template = self.template variables = self.get_variables() template.set_version('2010-09-09') template.set_description('App - Build Pipeline') # Resources boundary_arn = Join('', [ 'arn:', Partition, ':iam::', AccountId, ':policy/', variables['RolePermissionsBoundaryName'].ref ]) # Repo image limit is 1000 by default; this lambda function will prune # old images image_param_path = Join( '', ['/', variables['AppPrefix'].ref, '/current-hash']) image_param_arn = Join('', [ 'arn:', Partition, ':ssm:', Region, ':', AccountId, ':parameter', image_param_path ]) ecr_repo_arn = Join('', [ 'arn:', Partition, ':ecr:', Region, ':', AccountId, ':repository/', variables['EcrRepoName'].ref ]) cleanuplambdarole = template.add_resource( iam.Role('CleanupLambdaRole', AssumeRolePolicyDocument=make_simple_assume_policy( 'lambda.amazonaws.com'), ManagedPolicyArns=[ IAM_ARN_PREFIX + 'AWSLambdaBasicExecutionRole' ], PermissionsBoundary=boundary_arn, Policies=[ iam.Policy( PolicyName=Join( '', [variables['AppPrefix'].ref, '-ecrcleanup']), PolicyDocument=PolicyDocument( Version='2012-10-17', Statement=[ Statement(Action=[awacs.ssm.GetParameter], Effect=Allow, Resource=[image_param_arn]), Statement(Action=[ awacs.ecr.DescribeImages, awacs.ecr.BatchDeleteImage ], Effect=Allow, Resource=[ecr_repo_arn]) ])) ])) cleanupfunction = template.add_resource( awslambda.Function( 'CleanupFunction', Description='Cleanup stale ECR images', Code=awslambda.Code( ZipFile=variables['ECRCleanupLambdaFunction']), Environment=awslambda.Environment( Variables={ 'ECR_REPO_NAME': variables['EcrRepoName'].ref, 'SSM_PARAM': image_param_path }), Handler='index.handler', Role=cleanuplambdarole.get_att('Arn'), Runtime='python3.6', Timeout=120)) cleanuprule = template.add_resource( events.Rule('CleanupRule', Description='Regularly invoke CleanupFunction', ScheduleExpression='rate(7 days)', State='ENABLED', Targets=[ events.Target(Arn=cleanupfunction.get_att('Arn'), Id='CleanupFunction') ])) template.add_resource( awslambda.Permission( 'AllowCWLambdaInvocation', FunctionName=cleanupfunction.ref(), Action=awacs.awslambda.InvokeFunction.JSONrepr(), Principal='events.amazonaws.com', SourceArn=cleanuprule.get_att('Arn'))) appsource = template.add_resource( codecommit.Repository( 'AppSource', RepositoryName=Join('-', [variables['AppPrefix'].ref, 'source']))) for i in ['Name', 'Arn']: template.add_output( Output("AppRepo%s" % i, Description="%s of app source repo" % i, Value=appsource.get_att(i))) bucket = template.add_resource( s3.Bucket( 'Bucket', AccessControl=s3.Private, LifecycleConfiguration=s3.LifecycleConfiguration(Rules=[ s3.LifecycleRule(NoncurrentVersionExpirationInDays=90, Status='Enabled') ]), VersioningConfiguration=s3.VersioningConfiguration( Status='Enabled'))) template.add_output( Output('PipelineBucketName', Description='Name of pipeline bucket', Value=bucket.ref())) # This list must be kept in sync between the CodeBuild project and its # role build_name = Join('', [variables['AppPrefix'].ref, '-build']) build_role = template.add_resource( iam.Role( 'BuildRole', AssumeRolePolicyDocument=make_simple_assume_policy( 'codebuild.amazonaws.com'), PermissionsBoundary=boundary_arn, Policies=[ iam.Policy( PolicyName=Join('', [build_name, '-policy']), PolicyDocument=PolicyDocument( Version='2012-10-17', Statement=[ Statement( Action=[awacs.s3.GetObject], Effect=Allow, Resource=[ Join('', [bucket.get_att('Arn'), '/*']) ]), Statement( Action=[awacs.ecr.GetAuthorizationToken], Effect=Allow, Resource=['*']), Statement(Action=[ awacs.ecr.BatchCheckLayerAvailability, awacs.ecr.BatchGetImage, awacs.ecr.CompleteLayerUpload, awacs.ecr.DescribeImages, awacs.ecr.GetDownloadUrlForLayer, awacs.ecr.InitiateLayerUpload, awacs.ecr.PutImage, awacs.ecr.UploadLayerPart ], Effect=Allow, Resource=[ecr_repo_arn]), Statement(Action=[ awacs.ssm.GetParameter, awacs.ssm.PutParameter ], Effect=Allow, Resource=[image_param_arn]), Statement(Action=[ awacs.logs.CreateLogGroup, awacs.logs.CreateLogStream, awacs.logs.PutLogEvents ], Effect=Allow, Resource=[ Join('', [ 'arn:', Partition, ':logs:', Region, ':', AccountId, ':log-group:/aws/codebuild/', build_name ] + x) for x in [[':*'], [':*/*']] ]) ])) ])) buildproject = template.add_resource( codebuild.Project( 'BuildProject', Artifacts=codebuild.Artifacts(Type='CODEPIPELINE'), Environment=codebuild.Environment( ComputeType='BUILD_GENERAL1_SMALL', EnvironmentVariables=[ codebuild.EnvironmentVariable( Name='AWS_DEFAULT_REGION', Type='PLAINTEXT', Value=Region), codebuild.EnvironmentVariable(Name='AWS_ACCOUNT_ID', Type='PLAINTEXT', Value=AccountId), codebuild.EnvironmentVariable( Name='IMAGE_REPO_NAME', Type='PLAINTEXT', Value=variables['EcrRepoName'].ref), ], Image='aws/codebuild/docker:18.09.0', Type='LINUX_CONTAINER'), Name=build_name, ServiceRole=build_role.get_att('Arn'), Source=codebuild.Source( Type='CODEPIPELINE', BuildSpec=variables['BuildProjectBuildSpec']))) pipelinerole = template.add_resource( iam.Role( 'PipelineRole', AssumeRolePolicyDocument=make_simple_assume_policy( 'codepipeline.amazonaws.com'), PermissionsBoundary=boundary_arn, Policies=[ iam.Policy( PolicyName=Join('', [build_name, '-pipeline-policy']), PolicyDocument=PolicyDocument( Version='2012-10-17', Statement=[ Statement( Action=[ awacs.codecommit.GetBranch, awacs.codecommit.GetCommit, awacs.codecommit.UploadArchive, awacs.codecommit. GetUploadArchiveStatus, # noqa awacs.codecommit.CancelUploadArchive ], # noqa Effect=Allow, Resource=[appsource.get_att('Arn')]), Statement( Action=[awacs.s3.GetBucketVersioning], Effect=Allow, Resource=[bucket.get_att('Arn')]), Statement( Action=[ awacs.s3.GetObject, awacs.s3.PutObject ], Effect=Allow, Resource=[ Join('', [bucket.get_att('Arn'), '/*']) ]), Statement( Action=[ awacs.codebuild.BatchGetBuilds, awacs.codebuild.StartBuild ], Effect=Allow, Resource=[buildproject.get_att('Arn')]) ])) ])) template.add_resource( codepipeline.Pipeline( 'Pipeline', ArtifactStore=codepipeline.ArtifactStore(Location=bucket.ref(), Type='S3'), Name=build_name, RoleArn=pipelinerole.get_att('Arn'), Stages=[ codepipeline.Stages( Name='Source', Actions=[ codepipeline.Actions( Name='CodeCommit', ActionTypeId=codepipeline.ActionTypeId( Category='Source', Owner='AWS', Provider='CodeCommit', Version='1'), Configuration={ 'RepositoryName': appsource.get_att('Name'), # noqa 'BranchName': 'master' }, OutputArtifacts=[ codepipeline.OutputArtifacts( Name='CodeCommitRepo') ]), ]), codepipeline.Stages( Name='Build', Actions=[ codepipeline.Actions( Name='Build', ActionTypeId=codepipeline.ActionTypeId( Category='Build', Owner='AWS', Provider='CodeBuild', Version='1'), Configuration={ 'ProjectName': buildproject.ref() }, InputArtifacts=[ codepipeline.InputArtifacts( Name='CodeCommitRepo') ]) ]) ]))
def _allow_assume_role_service(self, service_name): # make_simple_assume_policy does not add a version number, # so this is a wrapper that injects the version string. policy = make_simple_assume_policy('%s.amazonaws.com' % service_name, ) policy.Version = '2012-10-17' return policy
def create_template(self): """Create template (main function called by Stacker).""" template = self.template variables = self.get_variables() template.add_version("2010-09-09") template.add_description("Kubernetes Master via EKS - V1.0.0") # Resources ccpsecuritygroup = template.add_resource( ec2.SecurityGroup( "ClusterControlPlaneSecurityGroup", GroupDescription="Cluster communication with worker nodes", Tags=[ { "Key": Sub("kubernetes.io/cluster/${EksClusterName}"), "Value": "owned", }, { "Key": "Product", "Value": "Kubernetes" }, { "Key": "Project", "Value": "eks" }, { "Key": "Name", "Value": Sub("${EksClusterName}-sg-worker-nodes") }, ], VpcId=variables["VPC"].ref, )) template.add_output( Output( ccpsecuritygroup.title, Description="Cluster communication with worker nodes", Export=Export( Sub("${AWS::StackName}-ControlPlaneSecurityGroup")), Value=ccpsecuritygroup.ref(), )) eksservicerole = template.add_resource( iam.Role( "EksServiceRole", AssumeRolePolicyDocument=make_simple_assume_policy( "eks.amazonaws.com"), ManagedPolicyArns=[ IAM_POLICY_ARN_PREFIX + "AmazonEKSClusterPolicy" ], Policies=[ iam.Policy( PolicyName="EksServiceRolePolicy", PolicyDocument=PolicyDocument(Statement=[ Statement( Action=[ awacs.iam.CreateServiceLinkedRole, awacs.iam.PutRolePolicy, ], Condition=Condition( StringLike( "iam:AWSServiceName", "elasticloadbalancing.amazonaws.com", )), Effect=Allow, Resource=[ Sub("arn:aws:iam::${AWS::AccountId}:role/" "aws-service-role/" "elasticloadbalancing.amazonaws.com/" "AWSServiceRoleForElasticLoadBalancing*" ) ], ) ]), ) ], )) ekscluster = template.add_resource( eks.Cluster( "EksCluster", Name=variables["EksClusterName"].ref, Version=variables["EksVersion"].ref, RoleArn=eksservicerole.get_att("Arn"), ResourcesVpcConfig=eks.ResourcesVpcConfig( SecurityGroupIds=[ccpsecuritygroup.ref()], SubnetIds=variables["EksSubnets"].ref, ), )) template.add_output( Output( "%sName" % ekscluster.title, Description="EKS Cluster Name", Export=Export( Sub("${AWS::StackName}-%sName" % ekscluster.title)), Value=ekscluster.ref(), )) template.add_output( Output( "%sEndpoint" % ekscluster.title, Description="EKS Cluster Endpoint", Export=Export( Sub("${AWS::StackName}-%sEndpoint" % ekscluster.title)), Value=ekscluster.get_att("Endpoint"), )) # Additional Outputs template.add_output( Output( "VpcId", Description="EKS Cluster VPC Id", Export=Export(Sub("${AWS::StackName}-VpcId")), Value=variables["VPC"].ref, )) template.add_output( Output( "Subnets", Description="EKS Cluster Subnets", Export=Export(Sub("${AWS::StackName}-Subnets")), Value=Join(",", variables["EksSubnets"].ref), ))
def _allow_assume_role_service(self, service_name): policy = make_simple_assume_policy( '%s.amazonaws.com' % service_name, ) policy.Version = '2012-10-17' return policy
def _get_self_destruct(self, replicated_lambda_remover): # type: (Dict[str, Union[awslambda.Function, Any]]) -> Dict[str, Any] res = {} variables = self.get_variables() res['role'] = self.template.add_resource( iam.Role( 'SelfDestructRole', AssumeRolePolicyDocument=make_simple_assume_policy( 'lambda.amazonaws.com'), Policies=[ iam.Policy(PolicyName="LambdaLogCreation", PolicyDocument=PolicyDocument( Version='2012-10-17', Statement=[ Statement( Action=[ awacs.logs.CreateLogGroup, awacs.logs.CreateLogStream, awacs.logs.PutLogEvents ], Effect=Allow, Resource=[ Join('', [ 'arn:', Partition, ':logs:*:', AccountId, ':log-group:/aws/lambda/', StackName, '-SelfDestruct-*' ]) ]) ])), iam.Policy( PolicyName="DeleteStateMachine", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[awacs.states.DeleteStateMachine], Effect=Allow, Resource=[ # StateMachine Join('', [ 'arn:', Partition, ':states:', Region, ':', AccountId, ':stateMachine:StaticSiteCleanup-', variables['stack_name'] ]) ]) ])), iam.Policy(PolicyName="DeleteRolesAndPolicies", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[ awacs.iam.DeleteRolePolicy, awacs.iam.DeleteRole ], Effect=Allow, Resource=[ Join('', [ 'arn:', Partition, ':iam::', AccountId, ':role/', StackName, '-*' ]), ]) ])), iam.Policy( PolicyName="DeleteLambdas", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[awacs.awslambda.DeleteFunction], Effect=Allow, Resource=[ Join('', [ 'arn:', Partition, ':lambda:', Region, ':', AccountId, ':function:%s-SelfDestruct-*' % (variables['stack_name']) ]), replicated_lambda_remover['function']. get_att('Arn') ]) ])), iam.Policy( PolicyName="DeleteStack", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[awacs.cloudformation.DeleteStack], Effect=Allow, Resource=[ Join('', [ 'arn:', Partition, ':cloudformation:', Region, ':', AccountId, ':stack/%s/*' % (variables['stack_name']) ]) ]) ])) ], )) self.template.add_output( Output('SelfDestructLambdaRole', Description='The name of the Self Destruct Role', Value=res['role'].ref())) res['function'] = self.template.add_resource( awslambda.Function( 'SelfDestruct', Code=awslambda.Code(ZipFile=read_value_from_path( 'file://' + os.path.join(os.path.dirname(__file__), 'templates/self_destruct.template.py'))), Description= "Issues a Delete Stack command to the Cleanup stack", Handler='index.handler', Role=res['role'].get_att('Arn'), Runtime='python3.7')) self.template.add_output( Output('SelfDestructLambdaArn', Description='The ARN of the Replicated Function', Value=res['function'].get_att('Arn'))) return res
def create_template(self): """Create template (main function called by Stacker).""" template = self.template # variables = self.get_variables() template.add_version("2010-09-09") template.add_description("Kubernetes IAM policies - V1.0.0") # Resources nodeinstancerole = template.add_resource( iam.Role( "NodeInstanceRole", AssumeRolePolicyDocument=make_simple_assume_policy("ec2.amazonaws.com"), ManagedPolicyArns=[ IAM_POLICY_ARN_PREFIX + i for i in [ "AmazonEKSWorkerNodePolicy", "AmazonEKS_CNI_Policy", "AmazonEC2ContainerRegistryReadOnly", # SSM agent not shipped ootb # 'AmazonSSMManagedInstanceCore' ] ], ) ) template.add_output( Output( "NodeInstanceRole", Description="The node instance role name", Value=nodeinstancerole.ref(), ) ) template.add_output( Output( "NodeInstanceRoleArn", Description="The node instance role ARN", Value=nodeinstancerole.get_att("Arn"), ) ) nodeinstanceprofile = template.add_resource( iam.InstanceProfile( "NodeInstanceProfile", Path="/", Roles=[nodeinstancerole.ref()] ) ) template.add_output( Output( "NodeInstanceProfile", Description="The node instance profile", Value=nodeinstanceprofile.ref(), ) ) template.add_output( Output( "NodeInstanceProfileArn", Description="The node instance profile ARN", Value=nodeinstanceprofile.get_att("Arn"), ) ) template.add_resource( iam.Role( "ClusterAutoScalerInstanceRole", AssumeRolePolicyDocument=make_simple_assume_policy("ec2.amazonaws.com"), Policies=[ iam.Policy( PolicyName="cluster-autoscaler", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[ awacs.autoscaling.DescribeAutoScalingGroups, awacs.autoscaling.DescribeAutoScalingInstances, awacs.autoscaling.DescribeTags, awacs.autoscaling.SetDesiredCapacity, awacs.autoscaling.TerminateInstanceInAutoScalingGroup, ], Effect=Allow, Resource=["*"], ) ], ), ) ], ) )
def _get_replicated_lambda_remover_lambda(self): # type: () -> Dict[str, Any] res = {} res['role'] = self.template.add_resource( iam.Role( 'ReplicatedLambdaRemoverRole', AssumeRolePolicyDocument=make_simple_assume_policy( 'lambda.amazonaws.com'), Policies=[ iam.Policy(PolicyName="LambdaLogCreation", PolicyDocument=PolicyDocument( Version='2012-10-17', Statement=[ Statement( Action=[ awacs.logs.CreateLogGroup, awacs.logs.CreateLogStream, awacs.logs.PutLogEvents ], Effect=Allow, Resource=[ Join('', [ 'arn:', Partition, ':logs:*:', AccountId, ':log-group:/aws/lambda/', StackName, '-ReplicatedLambdaRemover-*' ]) ]) ])), iam.Policy(PolicyName="DeleteLambda", PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement(Action=[ awacs.awslambda.DeleteFunction ], Effect=Allow, Resource=self.get_variables() ['function_arns']) ])) ], )) self.template.add_output( Output( 'ReplicatedLambdaRemoverRole', Description='The name of the Replicated Lambda Remover Role', Value=res['role'].ref())) res['function'] = self.template.add_resource( awslambda.Function( 'ReplicatedLambdaRemover', Code=awslambda.Code( ZipFile=read_value_from_path('file://' + os.path.join( os.path.dirname(__file__), 'templates/replicated_lambda_remover.template.py'))), Description= "Checks for Replicated Lambdas created during the main stack and " "deletes them when they are ready.", Handler='index.handler', Role=res['role'].get_att('Arn'), Runtime='python3.7')) self.template.add_output( Output('ReplicatedLambdaRemoverArn', Description='The ARN of the Replicated Function', Value=res['function'].get_att('Arn'))) return res
def create_template(self): """Create template (main function called by Stacker).""" template = self.template variables = self.get_variables() template.set_version("2010-09-09") template.set_description("App - Build Pipeline") # Resources boundary_arn = Join( "", [ "arn:", Partition, ":iam::", AccountId, ":policy/", variables["RolePermissionsBoundaryName"].ref, ], ) # Repo image limit is 1000 by default; this lambda function will prune # old images image_param_path = Join("", ["/", variables["AppPrefix"].ref, "/current-hash"]) image_param_arn = Join( "", [ "arn:", Partition, ":ssm:", Region, ":", AccountId, ":parameter", image_param_path, ], ) ecr_repo_arn = Join( "", [ "arn:", Partition, ":ecr:", Region, ":", AccountId, ":repository/", variables["EcrRepoName"].ref, ], ) cleanuplambdarole = template.add_resource( iam.Role( "CleanupLambdaRole", AssumeRolePolicyDocument=make_simple_assume_policy( "lambda.amazonaws.com" ), ManagedPolicyArns=[IAM_ARN_PREFIX + "AWSLambdaBasicExecutionRole"], PermissionsBoundary=boundary_arn, Policies=[ iam.Policy( PolicyName=Join( "", [variables["AppPrefix"].ref, "-ecrcleanup"] ), PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[awacs.ssm.GetParameter], Effect=Allow, Resource=[image_param_arn], ), Statement( Action=[ awacs.ecr.DescribeImages, awacs.ecr.BatchDeleteImage, ], Effect=Allow, Resource=[ecr_repo_arn], ), ], ), ) ], ) ) cleanupfunction = template.add_resource( awslambda.Function( "CleanupFunction", Description="Cleanup stale ECR images", Code=awslambda.Code(ZipFile=variables["ECRCleanupLambdaFunction"]), Environment=awslambda.Environment( Variables={ "ECR_REPO_NAME": variables["EcrRepoName"].ref, "SSM_PARAM": image_param_path, } ), Handler="index.handler", Role=cleanuplambdarole.get_att("Arn"), Runtime="python3.6", Timeout=120, ) ) cleanuprule = template.add_resource( events.Rule( "CleanupRule", Description="Regularly invoke CleanupFunction", ScheduleExpression="rate(7 days)", State="ENABLED", Targets=[ events.Target( Arn=cleanupfunction.get_att("Arn"), Id="CleanupFunction" ) ], ) ) template.add_resource( awslambda.Permission( "AllowCWLambdaInvocation", FunctionName=cleanupfunction.ref(), Action=awacs.awslambda.InvokeFunction.JSONrepr(), Principal="events.amazonaws.com", SourceArn=cleanuprule.get_att("Arn"), ) ) appsource = template.add_resource( codecommit.Repository( "AppSource", RepositoryName=Join("-", [variables["AppPrefix"].ref, "source"]), ) ) for i in ["Name", "Arn"]: template.add_output( Output( "AppRepo%s" % i, Description="%s of app source repo" % i, Value=appsource.get_att(i), ) ) bucket = template.add_resource( s3.Bucket( "Bucket", AccessControl=s3.Private, LifecycleConfiguration=s3.LifecycleConfiguration( Rules=[ s3.LifecycleRule( NoncurrentVersionExpirationInDays=90, Status="Enabled" ) ] ), VersioningConfiguration=s3.VersioningConfiguration(Status="Enabled"), ) ) template.add_output( Output( "PipelineBucketName", Description="Name of pipeline bucket", Value=bucket.ref(), ) ) # This list must be kept in sync between the CodeBuild project and its # role build_name = Join("", [variables["AppPrefix"].ref, "-build"]) build_role = template.add_resource( iam.Role( "BuildRole", AssumeRolePolicyDocument=make_simple_assume_policy( "codebuild.amazonaws.com" ), PermissionsBoundary=boundary_arn, Policies=[ iam.Policy( PolicyName=Join("", [build_name, "-policy"]), PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[awacs.s3.GetObject], Effect=Allow, Resource=[Join("", [bucket.get_att("Arn"), "/*"])], ), Statement( Action=[awacs.ecr.GetAuthorizationToken], Effect=Allow, Resource=["*"], ), Statement( Action=[ awacs.ecr.BatchCheckLayerAvailability, awacs.ecr.BatchGetImage, awacs.ecr.CompleteLayerUpload, awacs.ecr.DescribeImages, awacs.ecr.GetDownloadUrlForLayer, awacs.ecr.InitiateLayerUpload, awacs.ecr.PutImage, awacs.ecr.UploadLayerPart, ], Effect=Allow, Resource=[ecr_repo_arn], ), Statement( Action=[ awacs.ssm.GetParameter, awacs.ssm.PutParameter, ], Effect=Allow, Resource=[image_param_arn], ), Statement( Action=[ awacs.logs.CreateLogGroup, awacs.logs.CreateLogStream, awacs.logs.PutLogEvents, ], Effect=Allow, Resource=[ Join( "", [ "arn:", Partition, ":logs:", Region, ":", AccountId, ":log-group:/aws/codebuild/", build_name, ] + x, ) for x in [[":*"], [":*/*"]] ], ), ], ), ) ], ) ) buildproject = template.add_resource( codebuild.Project( "BuildProject", Artifacts=codebuild.Artifacts(Type="CODEPIPELINE"), Environment=codebuild.Environment( ComputeType="BUILD_GENERAL1_SMALL", EnvironmentVariables=[ codebuild.EnvironmentVariable( Name="AWS_DEFAULT_REGION", Type="PLAINTEXT", Value=Region ), codebuild.EnvironmentVariable( Name="AWS_ACCOUNT_ID", Type="PLAINTEXT", Value=AccountId ), codebuild.EnvironmentVariable( Name="IMAGE_REPO_NAME", Type="PLAINTEXT", Value=variables["EcrRepoName"].ref, ), ], Image="aws/codebuild/docker:18.09.0", Type="LINUX_CONTAINER", ), Name=build_name, ServiceRole=build_role.get_att("Arn"), Source=codebuild.Source( Type="CODEPIPELINE", BuildSpec=variables["BuildProjectBuildSpec"] ), ) ) pipelinerole = template.add_resource( iam.Role( "PipelineRole", AssumeRolePolicyDocument=make_simple_assume_policy( "codepipeline.amazonaws.com" ), PermissionsBoundary=boundary_arn, Policies=[ iam.Policy( PolicyName=Join("", [build_name, "-pipeline-policy"]), PolicyDocument=PolicyDocument( Version="2012-10-17", Statement=[ Statement( Action=[ awacs.codecommit.GetBranch, awacs.codecommit.GetCommit, awacs.codecommit.UploadArchive, awacs.codecommit.GetUploadArchiveStatus, # noqa awacs.codecommit.CancelUploadArchive, ], # noqa Effect=Allow, Resource=[appsource.get_att("Arn")], ), Statement( Action=[awacs.s3.GetBucketVersioning], Effect=Allow, Resource=[bucket.get_att("Arn")], ), Statement( Action=[awacs.s3.GetObject, awacs.s3.PutObject], Effect=Allow, Resource=[Join("", [bucket.get_att("Arn"), "/*"])], ), Statement( Action=[ awacs.codebuild.BatchGetBuilds, awacs.codebuild.StartBuild, ], Effect=Allow, Resource=[buildproject.get_att("Arn")], ), ], ), ) ], ) ) template.add_resource( codepipeline.Pipeline( "Pipeline", ArtifactStore=codepipeline.ArtifactStore( Location=bucket.ref(), Type="S3" ), Name=build_name, RoleArn=pipelinerole.get_att("Arn"), Stages=[ codepipeline.Stages( Name="Source", Actions=[ codepipeline.Actions( Name="CodeCommit", ActionTypeId=codepipeline.ActionTypeId( Category="Source", Owner="AWS", Provider="CodeCommit", Version="1", ), Configuration={ "RepositoryName": appsource.get_att("Name"), # noqa "BranchName": "master", }, OutputArtifacts=[ codepipeline.OutputArtifacts(Name="CodeCommitRepo") ], ), ], ), codepipeline.Stages( Name="Build", Actions=[ codepipeline.Actions( Name="Build", ActionTypeId=codepipeline.ActionTypeId( Category="Build", Owner="AWS", Provider="CodeBuild", Version="1", ), Configuration={"ProjectName": buildproject.ref()}, InputArtifacts=[ codepipeline.InputArtifacts(Name="CodeCommitRepo") ], ) ], ), ], ) )