Skip to content

Commit

Permalink
AWS Elastic Beanstalk Blue/Green deployment with Ansible
Browse files Browse the repository at this point in the history
  • Loading branch information
yohanbeschi committed Feb 18, 2021
1 parent 7884add commit 2bc5095
Show file tree
Hide file tree
Showing 14 changed files with 914 additions and 0 deletions.
46 changes: 46 additions & 0 deletions aws-eb-bluegreen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Testing the code

## Requirements

- [An AWS Account](https://aws.amazon.com/account/)
- An IAM user with [programmatic access](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html)
- The AWS CLI with a [profile](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) configured
- [Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) (on Windows you will need [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10))

## Configuration

cd eb-bluegreen-infra
# Update the file `vars/common-vars.asb.yml` with appropriate values
ansible-playbook init/main.asb.yml --check -v
ansible-playbook init/main.asb.yml

ansible-playbook infra/main.asb.yml --check -v
ansible-playbook infra/main.asb.yml

# Insert secrets into SSM Parameter Store
# Create a Python script from .vault/ssm-parameters/parameters.py.template (change the profile and the values) named ssm-labs.py
cd .vault/ssm-parameters
python ssm-labs.py
python ssm-labs.py --nodryrun

cd ../../../eb-bluegreen-app
git init
git remote add origin codecommit::us-east-1://spikeseed-labs@eb-bluegreen-app
git add -A
git commit -m "Demo application"
git push origin master

cd ../eb-bluegreen-infra
ansible-playbook cicd/main.asb.yml --check -v
ansible-playbook cicd/main.asb.yml

# Wait for the Elastic BeanStalk to be created, then:

curl -i -H "x-com-token: 0123456789" https://<aws_accounts.labs.backend_dns>/api/v1/hello # FQDN configured in common-vars.asb.yml

### Cleanup

1. Remove the S3 Buckets
1. Remove the stacks
1. Remove the CodeCommit repositories
1. Remove SSM Parameters
2 changes: 2 additions & 0 deletions aws-eb-bluegreen/eb-bluegreen-infra/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
__pycache__
ssm-*.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
PROFILE_NAME=spikeseed-labs
AWS_REGION=us-east-1
BUCKET_NAME=$(aws ssm get-parameter --name /eb-bluegreen/cfn/bucket/vault --output text --query Parameter.Value --profile $PROFILE_NAME --region $AWS_REGION)
aws s3 sync --profile $PROFILE_NAME s3://$BUCKET_NAME/ssm-parameters . --include "*.py"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from .ssm_utils import SsmParameterUpdater

ssm = SsmParameterUpdater('spikeseed-labs', 'us-east-1')

ssm.put_ssm_parameter('/cicd/deploy/color' , 'blue', value_type='String') # should only be executed the first time
ssm.put_ssm_parameter('/eb-bluegreen/database/password/1', 'TODO value')
ssm.put_ssm_parameter('/eb-bluegreen/database/password/2', 'TODO value')
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import sys
import boto3

class SsmParameterUpdater:

def __init__(self, profile_name, region_name):
if len(sys.argv) == 2 and sys.argv[1] == '--nodryrun':
self._dry_run = False
print('==================')
print('Update Mode')
print('==================')
else:
self._dry_run = True
print('==================')
print('Dry Run Mode')
print('==================')
session = boto3.Session(profile_name=profile_name, region_name=region_name)
self._ssm_client = session.client('ssm')

def get_ssm_parameter(self, name: str):
try:
return self._ssm_client.get_parameter(Name=name, WithDecryption=True)['Parameter']
except:
return None

def put_ssm_parameter(self, name: str, value: str, value_type: str = 'SecureString'):
param = self.get_ssm_parameter(name)
if not param or param['Value'] != value or param['Type'] != value_type:
if not self._dry_run:

self._ssm_client.put_parameter(
Name=name,
Value=value,
Type=value_type,
Overwrite=True
)

print(f'[modified] {name}')

else:
print(f'DR - [modified] {name}')
elif not self._dry_run:
print(f'[no change] {name}')
else:
print(f'DR - [no change] {name}')
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
PROFILE_NAME=spikeseed-labs
AWS_REGION=us-east-1
BUCKET_NAME=$(aws ssm get-parameter --name /eb-bluegreen/cfn/bucket/vault --output text --query Parameter.Value --profile $PROFILE_NAME --region $AWS_REGION)
aws s3 sync --profile $PROFILE_NAME . s3://$BUCKET_NAME/ssm-parameters --exclude "*" --include "ssm-*.py"
34 changes: 34 additions & 0 deletions aws-eb-bluegreen/eb-bluegreen-infra/cicd/main.asb.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
- hosts: localhost
connection: local
gather_facts: false

vars_files:
- ../vars/common-vars.asb.yml

tasks:

- name: "Deploy CloudFormation stack {{ local_stack_name }}"
amazon.aws.cloudformation:
stack_name: "{{ local_stack_name }}"
state: present
region: "{{ local_region_name }}"
profile: "{{ local_account_name }}"
template: "templates/cicd-app.cfn.yml"
tags: "{{ local_aws_tags }}"
template_parameters:
CodeCommitRepoName: "{{ repo_app }}"
SsmAssetsBucketNameKey: "{{ ssm_assets_bucket_name_key }}"
vars:
local_account: "{{ aws_accounts.labs }}"
local_account_name: "{{ local_account.account_name }}"
local_account_code: "{{ local_account.account_code }}"
local_region_name: "{{ default_aws_region }}"
local_region_code: "{{ default_aws_region_code }}"
local_stack_name: "{{ local_account_code }}-{{ local_region_code }}-{{ application }}-cicd-app"
local_aws_tags:
Application: "{{ application }}"
Environment: "{{ local_account.environment }}"
Name: "{{ local_stack_name }}"
tags:
- app
210 changes: 210 additions & 0 deletions aws-eb-bluegreen/eb-bluegreen-infra/cicd/templates/cicd-app.cfn.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
Parameters:

CodeCommitRepoName:
Type: String
SsmAssetsBucketNameKey:
Type: AWS::SSM::Parameter::Value<String>

Resources:

CodeBuildDeployRole:
Type: AWS::IAM::Role
Properties:
RoleName: eb-bluegreen-codebuild-deploy-assumable-role
Path: /
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSElasticBeanstalkFullAccess
Policies:
- PolicyName: eb-bluegreen-codebuild-deploy-assumable-role-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- iam:*
- lambda:GetFunction
- lambda:CreateFunction
- lambda:DeleteFunction
- lambda:UpdateFunction*
- lambda:InvokeFunction
- ssm:AddTagsToResource
- ssm:GetParameters
- ssm:PutParameter
- ssm:DeleteParameter
- route53:GetHostedZone
- route53:GetChange
- route53:ChangeResourceRecordSets
Resource: '*'

#================
# CodePipeline S3 Bucket
#================

CicdAppArtifactsBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
Properties:
AccessControl: Private
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256

#================
# IAM Permissions
#================

CodeBuildServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName: eb-bluegreen-codebuild-app-role
Path: /
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- codebuild.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: eb-bluegreen-codebuild-app-role-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Resource: !GetAtt CodeBuildDeployRole.Arn
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: '*'
- Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
- s3:GetObjectVersion
Resource:
- !Sub arn:aws:s3:::${CicdAppArtifactsBucket}/*
- !Sub arn:aws:s3:::${SsmAssetsBucketNameKey}/*

CodePipelineServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName: eb-bluegreen-codepipeline-app-role
Path: /
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: eb-bluegreen-codepipeline-app-role-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:PutObject
- s3:GetObject
- s3:GetObjectVersion
- s3:GetBucketVersioning
Resource:
- !Sub arn:aws:s3:::${CicdAppArtifactsBucket}/*
- Effect: Allow
Action:
- codebuild:StartBuild
- codebuild:BatchGetBuilds
Resource: '*'
- Action:
- codecommit:GetBranch
- codecommit:GetCommit
- codecommit:UploadArchive
- codecommit:GetUploadArchiveStatus
- codecommit:CancelUploadArchive
Effect: Allow
Resource: !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${CodeCommitRepoName}

#================
# CodeBuild
#================

CodeBuildProject:
Type: AWS::CodeBuild::Project
Properties:
Name: eb-bluegreen-app
ServiceRole: !Ref CodeBuildServiceRole
Artifacts:
Type: CODEPIPELINE
Source:
Type: CODEPIPELINE
Environment:
Type: LINUX_CONTAINER
ComputeType: BUILD_GENERAL1_MEDIUM
Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0
EnvironmentVariables:
- Type: PLAINTEXT
Name: ASSETS_BUCKET_NAME
Value: !Ref SsmAssetsBucketNameKey
- Type: PLAINTEXT
Name: ROLE_ARN
Value: !GetAtt CodeBuildDeployRole.Arn

#================
# CodePipeline
#================

Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
RoleArn: !GetAtt CodePipelineServiceRole.Arn
RestartExecutionOnUpdate: False
ArtifactStore:
Type: S3
Location: !Ref CicdAppArtifactsBucket
Name: eb-bluegreen-app
Stages:
- Name: Source
Actions:
- Name: App
ActionTypeId:
Category: Source
Owner: AWS
Version: 1
Provider: CodeCommit
Configuration:
RepositoryName: !Ref CodeCommitRepoName
BranchName: master
OutputArtifacts:
- Name: App
RunOrder: 1
- Name: Build
Actions:
- Name: Build
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref CodeBuildProject
InputArtifacts:
- Name: App
OutputArtifacts:
- Name: BuildOutput
RunOrder: 1
Loading

0 comments on commit 2bc5095

Please sign in to comment.