Skip to content
Draft
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions cicd/1-setup/cicd-dependencies.template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ Resources:
- codepipeline.amazonaws.com
Version: '2012-10-17'
Path: /service-role/
PermissionsBoundary: !ImportValue IAM-DevPermissions
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a tentative removal. I don't think we need it here. This stack is being deployed by an Admin anyway. I might be overlooking something though.

Policies:
- PolicyName: AiProxyPassRole
PolicyDocument:
Expand All @@ -43,7 +42,7 @@ Resources:
- "cloudformation:DescribeStacks"
- "cloudformation:CreateStack"
- "cloudformation:UpdateStack"
Resource: "*"
Resource: "*" # TODO scope to specific stacks
- PolicyName: CodeBuildResourcesAccess
PolicyDocument:
Statement:
Expand All @@ -68,11 +67,10 @@ Resources:
- s3:GetObjectVersion
Resource:
- !Sub ${ArtifactStore.Arn}/*
# TODO: Scope to specific ECR Repos?
- Effect: Allow
Action:
- ecr:GetAuthorizationToken
Resource: '*'
Resource: '*' # TODO scope to specific ECR repos
- Effect: Allow
Action: codestar-connections:UseConnection
Resource:
Expand Down Expand Up @@ -103,7 +101,6 @@ Resources:
- codebuild.amazonaws.com
Version: '2012-10-17'
Path: /service-role/
PermissionsBoundary: !ImportValue IAM-DevPermissions
Policies:
- PolicyName: PublicCodeBuildSecretsAccess
PolicyDocument:
Expand Down
31 changes: 23 additions & 8 deletions cicd/1-setup/deploy-cicd-dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,38 @@ TEMPLATE_FILE=cicd/1-setup/cicd-dependencies.template.yml
echo Validating cloudformation template...
aws cloudformation validate-template \
--template-body file://${TEMPLATE_FILE} \
| cat
> /dev/null

ACCOUNT=$(aws sts get-caller-identity --query "Account" --output text)
REGION=$(aws configure get region)

read -r -p "Would you like to deploy this template to AWS account $ACCOUNT? [y/N] " response
read -r -p "Would you like to create a change set for this template in AWS account $ACCOUNT? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]
then
echo Updating cloudformation stack...
echo "Follow along at https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks?filteringText=aiproxy-cicd-deps&filteringStatus=active&viewNested=true&hideStacks=false"
aws cloudformation deploy \
echo Creating change set...
CHANGE_SET_NAME="aiproxy-cicd-deps-changeset-$(date +%s)"
aws cloudformation create-change-set \
--stack-name aiproxy-cicd-deps \
--template-file ${TEMPLATE_FILE} \
--change-set-name $CHANGE_SET_NAME \
--template-body file://${TEMPLATE_FILE} \
--capabilities CAPABILITY_IAM \
--tags EnvType=infrastructure \
"$@"

echo Complete!
echo "Change set created. You can review it at:"
echo "https://console.aws.amazon.com/cloudformation/home?region=$REGION#/stacks/changesets/changes?stackId=arn:aws:cloudformation:$REGION:$ACCOUNT:stack/aiproxy-cicd-deps/*&changeSetId=arn:aws:cloudformation:$REGION:$ACCOUNT:changeSet/$CHANGE_SET_NAME"

read -r -p "Would you like to execute the change set? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]
then
echo Executing change set...
aws cloudformation execute-change-set \
--stack-name aiproxy-cicd-deps \
--change-set-name $CHANGE_SET_NAME
echo Complete!
else
echo Exiting...
fi
else
echo Exiting...
fi
fi
142 changes: 104 additions & 38 deletions cicd/2-cicd/cicd.template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,11 @@ Conditions:

Resources:

# The Elastic Container Registry Repository will store our built docker
# images.
#-------------------------------------
# Elastic Container Registry (ECR)
# - Store built docker images
#-------------------------------------

EcrRepository:
Type: AWS::ECR::Repository
Properties:
Expand Down Expand Up @@ -113,6 +116,10 @@ Resources:
- 'kms:GenerateDataKeyWithoutPlaintext'
Resource: '*'

#-------------------------------------
# CodeBuild Projects
#-------------------------------------

# The CodeBuild Project is triggered by pull requests targeting $GitHubBranch
# It will perform any steps defined in the pr-buildspec.yml file.
PullRequestBuildProject:
Expand Down Expand Up @@ -191,32 +198,9 @@ Resources:
Artifacts:
Type: CODEPIPELINE

# Grant the AiProxy CodeBuild Role additional permissions for resources in
# this template. This allows us to avoid granting permission to * resources.
AiProxyRolePolicy:
Type: 'AWS::IAM::Policy'
Properties:
PolicyName: !Sub "${AWS::StackName}-codebuild-policy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- codebuild:*
Resource:
- !GetAtt AppBuildProject.Arn
- !GetAtt IntegrationTestBuildProject.Arn
- Effect: Allow
Action:
- codebuild:CreateReportGroup
- codebuild:CreateReport
- codebuild:UpdateReport
- codebuild:BatchPutTestCases
- codebuild:BatchPutCodeCoverage
Resource:
- !Sub arn:aws:codebuild:us-east-1:165336972514:report-group/${AWS::StackName}-${GitHubBranch}-pr-build
Roles:
- !ImportValue AiProxyCodeBuildRoleName
#-------------------------------------
# Pipeline
#-------------------------------------

Pipeline:
Type: AWS::CodePipeline::Pipeline
Expand Down Expand Up @@ -278,11 +262,25 @@ Resources:
ActionMode: CREATE_UPDATE
TemplatePath: appBuildResults::packaged-app-template.yml
TemplateConfiguration: appBuildResults::cicd/3-app/aiproxy/dev.config.json
# ParameterOverrides must be a JSON string, not an object
ParameterOverrides: !Join
- ''
- - '{ "SubdomainName": "'
- !Sub "aiproxy-dev-${GitHubBranch}"
- '" }'
- ''
- - '{'
- !Sub '"SubdomainName": "aiproxy-dev-${GitHubBranch}",'
- !Sub '"ECRRepositoryArn": "${EcrRepository.Arn}",'
- !Sub
- '"VPC": "${VPCValue}",'
- { VPCValue: !ImportValue VPC }
- !Sub
- '"SecurityGroup": "${SecurityGroupValue}",'
- { SecurityGroupValue: !ImportValue VPC-ELBSecurityGroup }
- !Sub
- '"PublicSubnets": ${PublicSubnetsValue},'
- { PublicSubnetsValue: [!ImportValue VPC-PublicSubnetB, !ImportValue VPC-PublicSubnetC, !ImportValue VPC-PublicSubnetD, !ImportValue VPC-PublicSubnetE] }
- !Sub
- '"PrivateSubnets": ${PrivateSubnetsValue},'
- { PrivateSubnetsValue: [!ImportValue VPC-SubnetB, !ImportValue VPC-SubnetC, !ImportValue VPC-SubnetD, !ImportValue VPC-SubnetE] }
- '}'
Capabilities: CAPABILITY_AUTO_EXPAND,CAPABILITY_IAM
RoleArn: !Sub arn:aws:iam::${AWS::AccountId}:role/admin/CloudFormationService
- !Ref AWS::NoValue
Expand All @@ -304,11 +302,27 @@ Resources:
ActionMode: CREATE_UPDATE
TemplatePath: appBuildResults::packaged-app-template.yml
TemplateConfiguration: appBuildResults::cicd/3-app/aiproxy/test.config.json
# ParameterOverrides must be a JSON string, not an object
ParameterOverrides: !Join
- ''
- - '{ "SubdomainName": "'
- !If [ TargetsMainBranch, 'aiproxy-test', !Sub 'aiproxy-test-${GitHubBranch}' ]
- '" }'
- - '{'
- !Sub
- '"SubdomainName": "${SubdomainName}",'
- { SubdomainName: !If [ TargetsMainBranch, 'aiproxy-test', !Sub 'aiproxy-test-${GitHubBranch}' ] }
- !Sub '"ECRRepositoryArn": "${EcrRepository.Arn}",'
- !Sub
- '"VPC": "${VPCValue}",'
- { VPCValue: !ImportValue VPC }
- !Sub
- '"SecurityGroup": "${SecurityGroupValue}",'
- { SecurityGroupValue: !ImportValue VPC-ELBSecurityGroup }
- !Sub
- '"PublicSubnets": ${PublicSubnetsValue},'
- { PublicSubnetsValue: [!ImportValue VPC-PublicSubnetB, !ImportValue VPC-PublicSubnetC, !ImportValue VPC-PublicSubnetD, !ImportValue VPC-PublicSubnetE] }
- !Sub
- '"PrivateSubnets": ${PrivateSubnetsValue},'
- { PrivateSubnetsValue: [!ImportValue VPC-SubnetB, !ImportValue VPC-SubnetC, !ImportValue VPC-SubnetD, !ImportValue VPC-SubnetE] }
- '}'
Capabilities: CAPABILITY_AUTO_EXPAND,CAPABILITY_IAM
RoleArn: !Sub arn:aws:iam::${AWS::AccountId}:role/admin/CloudFormationService
- !Ref AWS::NoValue
Expand Down Expand Up @@ -353,11 +367,27 @@ Resources:
ActionMode: CREATE_UPDATE
TemplatePath: appBuildResults::packaged-app-template.yml
TemplateConfiguration: appBuildResults::cicd/3-app/aiproxy/production.config.json
# ParameterOverrides must be a JSON string, not an object
ParameterOverrides: !Join
- ''
- - '{ "SubdomainName": "'
- !If [ TargetsMainBranch, 'aiproxy', !Sub 'aiproxy-${GitHubBranch}' ]
- '" }'
- - '{'
- !Sub
- '"SubdomainName": "${SubdomainName}",'
- { SubdomainName: !If [ TargetsMainBranch, 'aiproxy', !Sub 'aiproxy-${GitHubBranch}' ] }
- !Sub '"ECRRepositoryArn": "${EcrRepository.Arn}",'
- !Sub
- '"VPC": "${VPCValue}",'
- { VPCValue: !ImportValue VPC }
- !Sub
- '"SecurityGroup": "${SecurityGroupValue}",'
- { SecurityGroupValue: !ImportValue VPC-ELBSecurityGroup }
- !Sub
- '"PublicSubnets": ${PublicSubnetsValue},'
- { PublicSubnetsValue: [!ImportValue VPC-PublicSubnetB, !ImportValue VPC-PublicSubnetC, !ImportValue VPC-PublicSubnetD, !ImportValue VPC-PublicSubnetE] }
- !Sub
- '"PrivateSubnets": ${PrivateSubnetsValue},'
- { PrivateSubnetsValue: [!ImportValue VPC-SubnetB, !ImportValue VPC-SubnetC, !ImportValue VPC-SubnetD, !ImportValue VPC-SubnetE] }
- '}'
Capabilities: CAPABILITY_AUTO_EXPAND,CAPABILITY_IAM
RoleArn: !Sub arn:aws:iam::${AWS::AccountId}:role/admin/CloudFormationService
- !Ref AWS::NoValue
Expand All @@ -384,6 +414,42 @@ Resources:
- Name: smokeTestResults
- !Ref AWS::NoValue


#-------------------------------------
# IAM Roles & Policies
#-------------------------------------

# Grant the AiProxy CodeBuild Role additional permissions for resources in
# this template. This allows us to avoid granting permission to * resources.
AiProxyRolePolicy:
Type: 'AWS::IAM::Policy'
Properties:
PolicyName: !Sub "${AWS::StackName}-codebuild-policy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- codebuild:*
Resource:
- !GetAtt AppBuildProject.Arn
- !GetAtt IntegrationTestBuildProject.Arn
- Effect: Allow
Action:
- codebuild:CreateReportGroup
- codebuild:CreateReport
- codebuild:UpdateReport
- codebuild:BatchPutTestCases
- codebuild:BatchPutCodeCoverage
Resource:
- !Sub arn:aws:codebuild:us-east-1:165336972514:report-group/${AWS::StackName}-${GitHubBranch}-pr-build
Roles:
- !ImportValue AiProxyCodeBuildRoleName

#-------------------------------------
# Metrics & Notifications
#-------------------------------------

# Send pipeline events to an SNS topic.
# Note:
# Integration with Slack via AWS ChatBot is configured manually via AWS
Expand Down
59 changes: 38 additions & 21 deletions cicd/2-cicd/deploy-cicd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,54 +8,71 @@ echo Deploying AiProxy CICD Pipeline
# - ENVIRONMENT_TYPE: Can be 'production' (default) or 'development', passed as a Parameter for "cicd/2-cicd/cicd.template.yml"
# - GITHUB_BADGE_ENABLED: defaults to true, passed as a Parameter for "cicd/2-cicd/cicd.template.yml"

# The branch name may become part of a domain name, so we need to validate it.
validate_branch_name() {
local branch_name=$1
if [[ ! $branch_name =~ ^[a-z0-9]([-a-z0-9]*[a-z0-9])$ ]]; then
echo "Invalid branch name '${branch_name}', branches must be alphanumeric and may contain hyphens."
exit 1
fi
}

# 'Developer' role requires a specific service role for all CloudFormation operations.
if [[ $(aws sts get-caller-identity --query Arn --output text) =~ "assumed-role/Developer/" ]]; then
# Append the role-arn option to the positional parameters $@ passed to cloudformation deploy.
set -- "$@" --role-arn "arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):role/admin/CloudFormationService"
fi

# Default to main branch, but support pipelines using other branches
TARGET_BRANCH=${TARGET_BRANCH-'main'}
ENVIRONMENT_TYPE=${ENVIRONMENT_TYPE:-'production'}
GITHUB_BADGE_ENABLED=${GITHUB_BADGE_ENABLED:-'true'}
TARGET_BRANCH=${TARGET_BRANCH:-'main'}

if [ "$TARGET_BRANCH" == "main" ]
then
STACK_NAME="aiproxy-cicd"
else
# only allow alphanumeric branch names that may contain an internal hyphen.
# to avoid complicated logic elsewhere, we're constraining it here.
if [[ "$TARGET_BRANCH" =~ ^[a-z0-9]([-a-z0-9]*[a-z0-9])$ ]]; then
STACK_NAME="aiproxy-${TARGET_BRANCH}-cicd"
else
echo "Invalid branch name '${TARGET_BRANCH}', branches must be alphanumeric and may contain hyphens."
exit
fi
validate_branch_name "$TARGET_BRANCH"
STACK_NAME="aiproxy-${TARGET_BRANCH}-cicd"
fi

ENVIRONMENT_TYPE=${ENVIRONMENT_TYPE-'production'}
GITHUB_BADGE_ENABLED=${GITHUB_BADGE_ENABLED-'true'}

TEMPLATE_FILE=cicd/2-cicd/cicd.template.yml

echo Validating cloudformation template...
aws cloudformation validate-template \
--template-body file://${TEMPLATE_FILE} \
| cat
> /dev/null

ACCOUNT=$(aws sts get-caller-identity --query "Account" --output text)
REGION=$(aws configure get region)

read -r -p "Would you like to deploy this template to AWS account $ACCOUNT? [y/N] " response
read -r -p "Would you like to create a change set for this template in AWS account $ACCOUNT? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]
then
echo Updating cloudformation stack...
aws cloudformation deploy \
echo Creating change set...
CHANGE_SET_NAME="${STACK_NAME}-changeset-$(date +%s)"
aws cloudformation create-change-set \
--stack-name $STACK_NAME \
--template-file $TEMPLATE_FILE \
--parameter-overrides GitHubBranch=$TARGET_BRANCH GitHubBadgeEnabled=$GITHUB_BADGE_ENABLED EnvironmentType=$ENVIRONMENT_TYPE \
--change-set-name $CHANGE_SET_NAME \
--template-body file://${TEMPLATE_FILE} \
--parameters ParameterKey=GitHubBranch,ParameterValue=$TARGET_BRANCH ParameterKey=GitHubBadgeEnabled,ParameterValue=$GITHUB_BADGE_ENABLED ParameterKey=EnvironmentType,ParameterValue=$ENVIRONMENT_TYPE \
--capabilities CAPABILITY_IAM \
--tags EnvType=${ENVIRONMENT_TYPE} \
--tags Key=EnvType,Value=${ENVIRONMENT_TYPE} \
"$@"

echo Complete!
echo "Change set created. You can review it at:"
echo "https://console.aws.amazon.com/cloudformation/home?region=$REGION#/stacks/changesets/changes?stackId=arn:aws:cloudformation:$REGION:$ACCOUNT:stack/$STACK_NAME/*&changeSetId=arn:aws:cloudformation:$REGION:$ACCOUNT:changeSet/$CHANGE_SET_NAME"

read -r -p "Would you like to execute the change set? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]
then
echo Executing change set...
aws cloudformation execute-change-set \
--stack-name $STACK_NAME \
--change-set-name $CHANGE_SET_NAME
echo Complete!
else
echo Exiting...
fi
else
echo Exiting...
fi
Loading