diff --git a/docs/providers-guide.md b/docs/providers-guide.md index 4f689d1e4..db97e3b7b 100644 --- a/docs/providers-guide.md +++ b/docs/providers-guide.md @@ -16,6 +16,7 @@ Providers and Actions. - [CodeCommit](#codecommit) - [GitHub](#github) - [S3](#s3) + - [CodeStar](#codestar) - [Build](#build) - [CodeBuild](#codebuild) - [Jenkins](#jenkins) @@ -33,7 +34,7 @@ Providers and Actions. ```yaml default_providers: source: - provider: codecommit|github|s3 + provider: codecommit|github|s3|codestar properties: # All provider specific properties go here. ``` @@ -126,6 +127,36 @@ Provider type: `s3`. > The Specific Object within the bucket that will trigger the pipeline > execution. +### CodeStar + +Use CodeStar as a source to trigger your pipeline. The source action retrieves code changes when a pipeline is manually executed or when a webhook event is sent from the source provider. CodeStar Connections currently supports the following third-party repositories: + +- Bitbucket +- GitHub and GitHub Enterprise Cloud +- GitHub Enterprise Server + +The AWS CodeStar connection needs to already exist and be in the "Available" Status. To use the AWS CodeStar Connection with ADF, its arn needs to be stored in AWS Systems Manager Parameter Store in the deployment account's main region (see details below). Read the CodePipeline documentation for more [information on how to setup the connection](https://docs.aws.amazon.com/dtconsole/latest/userguide/getting-started-connections.html). + +Provider type: `codestar`. + +#### Properties + +- *repository* - *(String)* defaults to name of the pipeline. + > The CodeStar repository name. + > For example, for the ADF repository it would be: + > `aws-deployment-framework`. +- *branch* - *(String)* - default: `master`. + > The Branch on the third-party repository to use to trigger this specific + > pipeline. +- *owner* - *(String)* **(required)** + > The name of the third-party user or organization who owns the third-party repository. + > For example, for the ADF repository that would be: `awslabs`. +- *codestar_connection_path* - *(String)* **(required)** + > The CodeStar Connection ARN token path in AWS Systems Manager Parameter Store in the deployment account + > in the main region that holds the CodeStar Connection ARN that will be used to download the source + > code and create the web hook as part of the pipeline. Read the CodeStar Connections documentation + > for more [information](https://docs.aws.amazon.com/dtconsole/latest/userguide/connections.html). + ## Build ```yaml diff --git a/docs/samples-guide.md b/docs/samples-guide.md index 6f42b9752..b53445fa2 100644 --- a/docs/samples-guide.md +++ b/docs/samples-guide.md @@ -16,7 +16,7 @@ The samples this guide will cover deploying are: In this guide, we will deploy a foundational VPC with associated resources along with a ECR Repository to hold our shared container images. Once the VPC is in place, we can deploy a ECS Cluster that will run our sample NodeJS application. -ADF supports multiple source types *(Github, CodeCommit, S3)* for pipelines, in this example we will use AWS CodeCommit as the source for our pipelines. Firstly, we will need to define an AWS Account where our source code originates from. In a real world example, we should assume that the account where the source code is kept and maintained is different from that which performs the deploy action, and again, different from that which actually runs the application. The regions used in this guide *(us-west-2, eu-west-1)* have been defined as target regions in *adfconfig.yml* and the deployment account has been bootstrapped as defined in the [installation guide](./installation-guide.md). +ADF supports multiple source types *(Github, CodeCommit, S3, CodeStar)* for pipelines, in this example we will use AWS CodeCommit as the source for our pipelines. Firstly, we will need to define an AWS Account where our source code originates from. In a real world example, we should assume that the account where the source code is kept and maintained is different from that which performs the deploy action, and again, different from that which actually runs the application. The regions used in this guide *(us-west-2, eu-west-1)* have been defined as target regions in *adfconfig.yml* and the deployment account has been bootstrapped as defined in the [installation guide](./installation-guide.md). Let's create a new AWS Account called `banking-source` via AWS Organizations that will act as a point of entry for our sample code. The role name we choose when we create a new account must match that of the one we define in out `adfconfig.yml`. *(Leave blank for default)* diff --git a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/global.yml b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/global.yml index 13b287087..c48b3bb0d 100644 --- a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/global.yml +++ b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/global.yml @@ -436,6 +436,15 @@ Resources: Resource: - !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:webhook:adf-webhook-* - !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${PipelinePrefix}* + - Effect: Allow + Action: + - "codestar-connections:GetConnection" + - "codestar-connections:GetHost" + - "codestar-connections:ListConnections" + - "codestar-connections:ListHosts" + - "codestar-connections:PassConnection" + - "codestar-connections:UseConnection" + Resource: "*" Roles: - !Ref PipelineProvisionerCodeBuildRole CloudFormationRole: @@ -894,6 +903,16 @@ Resources: - elasticbeanstalk.amazonaws.com - ec2.amazonaws.com - ecs-tasks.amazonaws.com + - Effect: Allow + Sid: "AllowCodeStarConnections" + Action: + - "codestar-connections:GetConnection" + - "codestar-connections:GetHost" + - "codestar-connections:ListConnections" + - "codestar-connections:ListHosts" + - "codestar-connections:PassConnection" + - "codestar-connections:UseConnection" + Resource: "*" Roles: - !Ref CodePipelineRole PipelineBucketPolicy: diff --git a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/lambda_codebase/initial_commit/pipelines_repository/example-deployment_map.yml b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/lambda_codebase/initial_commit/pipelines_repository/example-deployment_map.yml index c1967af31..81c7c4b16 100644 --- a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/lambda_codebase/initial_commit/pipelines_repository/example-deployment_map.yml +++ b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/lambda_codebase/initial_commit/pipelines_repository/example-deployment_map.yml @@ -59,6 +59,18 @@ pipelines: - path: /banking/testing name: fancy-name + - name: sample-ecs-app + default_providers: # if we omit build and deploy type we get a default of codebuild as the build and cloudformation as the deploy. if using codecommit, account_id is required + source: + provider: codestar + properties: + repository: my-ecs-app # Optional, above name property will be used if this is not specified + owner: github-enterprise-team-org + codestar_connection_path: /path/to/parameter # The path in AWS Systems Manager Parameter Store that holds the AWS CodeStar Connection arn + params: + notification_endpoint: team@example.com + targets: + - [ /banking/testing, /banking/production ] - name: sample-custom # using a custom pipeline, we can execute code within CodeBuild to perform whichever tasks are required. default_providers: diff --git a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/cdk_constructs/adf_codepipeline.py b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/cdk_constructs/adf_codepipeline.py index e3368f930..7741a55cd 100644 --- a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/cdk_constructs/adf_codepipeline.py +++ b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/cdk_constructs/adf_codepipeline.py @@ -6,6 +6,7 @@ import os import json +import boto3 from aws_cdk import ( aws_codepipeline as _codepipeline, @@ -13,6 +14,7 @@ ) from cdk_constructs import adf_events +from logger import configure_logger ADF_DEPLOYMENT_REGION = os.environ["AWS_REGION"] ADF_DEPLOYMENT_ACCOUNT_ID = os.environ["ACCOUNT_ID"] @@ -20,6 +22,8 @@ ADF_PIPELINE_PREFIX = os.environ.get("ADF_PIPELINE_PREFIX", "") ADF_DEFAULT_BUILD_TIMEOUT = 20 +LOGGER = configure_logger(__name__) + class Action: _version = "1" @@ -91,6 +95,22 @@ def _generate_configuration(self): #pylint: disable=R0912, R0911, R0915 'properties', {}).get( 'object_key') } + if self.provider == "CodeStarSourceConnection": + owner = self.map_params.get('default_providers', {}).get('source').get('properties', {}).get('owner', {}) + repo = self.map_params.get('default_providers', {}).get('source', {}).get('properties', {}).get('repository', {}) or self.map_params['name'] + codestar_connection_path = self.map_params.get('default_providers', {}).get('source').get('properties', {}).get('codestar_connection_path', {}) + ssm_client = boto3.client('ssm') + try: + response = ssm_client.get_parameter(Name=codestar_connection_path) + except Exception as e: + LOGGER.error(f"No parameter found at {codestar_connection_path}. Check the path/value.") + raise e + connection_arn = response['Parameter']['Value'] + return { + "ConnectionArn": connection_arn, + "FullRepositoryId": f"{owner}/{repo}", + "BranchName": self.map_params.get('default_providers', {}).get('source', {}).get('properties', {}).get('branch', {}) or 'master' + } if self.provider == "GitHub": return { "Owner": self.map_params.get('default_providers', {}).get('source').get('properties', {}).get('owner', {}), @@ -238,6 +258,8 @@ def _generate_codepipeline_access_role(self): #pylint: disable=R0911 return "arn:aws:iam::{0}:role/adf-codecommit-role".format(self.map_params['default_providers']['source']['properties']['account_id']) if self.provider == "GitHub": return None + if self.provider == "CodeStarSourceConnection": + return None if self.provider == "CodeBuild": return None if self.provider == "S3" and self.category == "Source": diff --git a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/cdk_constructs/adf_codestar.py b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/cdk_constructs/adf_codestar.py new file mode 100644 index 000000000..c0b1e9e02 --- /dev/null +++ b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/cdk_constructs/adf_codestar.py @@ -0,0 +1,37 @@ +# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 + +"""Construct related to CodeStarConnection Codepipeline Input +""" + +import os + +from aws_cdk import ( + aws_codepipeline as _codepipeline, + core +) + +from cdk_constructs.adf_codepipeline import Action + +ADF_DEPLOYMENT_REGION = os.environ["AWS_REGION"] +ADF_DEPLOYMENT_ACCOUNT_ID = os.environ["ACCOUNT_ID"] +ADF_DEFAULT_BUILD_TIMEOUT = 20 + + +class CodeStar(core.Construct): + def __init__(self, scope: core.Construct, id: str, map_params: dict, **kwargs): #pylint: disable=W0622 + super().__init__(scope, id, **kwargs) + self.source = _codepipeline.CfnPipeline.StageDeclarationProperty( + name="Source-CodeStar", + actions=[ + Action( + name="source", + provider="CodeStarSourceConnection", + owner="AWS", + category="Source", + run_order=1, + map_params=map_params, + action_name="source" + ).config + ] + ) diff --git a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/cdk_stacks/main.py b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/cdk_stacks/main.py index faaade4ff..5a71cdb2c 100644 --- a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/cdk_stacks/main.py +++ b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/cdk_stacks/main.py @@ -15,6 +15,7 @@ from cdk_constructs import adf_jenkins from cdk_constructs import adf_codecommit from cdk_constructs import adf_github +from cdk_constructs import adf_codestar from cdk_constructs import adf_s3 from cdk_constructs import adf_cloudformation from cdk_constructs import adf_notifications @@ -50,6 +51,14 @@ def __init__(self, scope: core.Construct, stack_input: dict, **kwargs) -> None: stack_input['input'] ).source ) + elif 'codestar' in _source_name: + _stages.append( + adf_codestar.CodeStar( + self, + 'source', + stack_input['input'] + ).source + ) elif 's3' in _source_name: _stages.append( adf_s3.S3( diff --git a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/schema_validation.py b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/schema_validation.py index 6dd00dc00..d36e71aa7 100644 --- a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/schema_validation.py +++ b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/schema_validation.py @@ -68,6 +68,19 @@ "properties": GITHUB_SOURCE_PROPS } +# CodeStar Source +CODESTAR_SOURCE_PROPS = { + Optional("repository"): str, + Optional("branch"): str, + "owner": str, + "codestar_connection_path": str +} + +CODESTAR_SOURCE = { + "provider": 'codestar', + "properties": CODESTAR_SOURCE_PROPS +} + # S3 Source S3_SOURCE_PROPS = { "account_id": AWS_ACCOUNT_ID_SCHEMA, @@ -227,6 +240,7 @@ 'codecommit': Schema(CODECOMMIT_SOURCE), 'github': Schema(GITHUB_SOURCE), 's3': Schema(S3_SOURCE), + 'codestar': Schema(CODESTAR_SOURCE), } PROVIDER_BUILD_SCHEMAS = { 'codebuild': Schema(DEFAULT_CODEBUILD_BUILD), @@ -243,7 +257,7 @@ PROVIDER_SCHEMA = { 'source': And( { - 'provider': Or('codecommit', 'github', 's3'), + 'provider': Or('codecommit', 'github', 's3', 'codestar'), 'properties': dict, }, lambda x: PROVIDER_SOURCE_SCHEMAS[x['provider']].validate(x), #pylint: disable=W0108