Continuous Integration with CircleCI 2.0, GitHub and Elastic Beanstalk

Simon McClive
Jun 19, 2017 · 7 min read
CircleCI, GitHub and Elastic Beanstalk

  1. Create a machine user and invite them as read only collaborators on each project.
Adding an SSH Key to your machine user

{
"Id": "Policy1497534632804",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1497534629565",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::gradient-deployment-key/*",
"Principal": {
"AWS": [
"arn:aws:iam::<ACCOUNT_ID>:role/aws-elasticbeanstalk-ec2-role"
]
}
},
{
"Sid": "Stmt1497534629566",
"Action": [
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::gradient-deployment-key",
"Principal": {
"AWS": [
"arn:aws:iam::<ACCOUNT_ID>:role/aws-elasticbeanstalk-ec2-role"
]
}
}
]
}

{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"elasticbeanstalk:CreateApplicationVersion",
"elasticbeanstalk:DescribeEnvironments",
"elasticbeanstalk:DeleteApplicationVersion",
"elasticbeanstalk:UpdateEnvironment",
"elasticbeanstalk:CreateStorageLocation"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"sns:CreateTopic",
"sns:GetTopicAttributes",
"sns:ListSubscriptionsByTopic",
"sns:Subscribe"
],
"Effect": "Allow",
"Resource": "arn:aws:sns:<REGION>:<ACCOUNT_ID>:*"
},
{
"Action": [
"autoscaling:SuspendProcesses",
"autoscaling:DescribeScalingActivities",
"autoscaling:ResumeProcesses",
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:UpdateAutoScalingGroup",
"autoscaling:DescribeLaunchConfigurations"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"cloudformation:GetTemplate",
"cloudformation:DescribeStacks",
"cloudformation:CreateStack",
"cloudformation:CancelUpdateStack",
"cloudformation:ListStackResources",
"cloudformation:DescribeStackResource",
"cloudformation:DescribeStackResources",
"cloudformation:DescribeStackEvents",
"cloudformation:DeleteStack",
"cloudformation:UpdateStack"
],
"Effect": "Allow",
"Resource": "arn:aws:cloudformation:us-east-1:525824562834:*"
},
{
"Action": [
"ec2:DescribeImages",
"ec2:DescribeKeyPairs",
"ec2:describeVpcs",
"ec2:*"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:ListBucket",
"s3:DeleteObject",
"s3:GetBucketPolicy",
"s3:Get*",
"s3:List*"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::elasticbeanstalk-<REGION>-<ACCOUNT_ID>",
"arn:aws:s3:::elasticbeanstalk-<REGION>-<ACCOUNT_ID>/*"
]
},
{
"Action": [
"s3:CreateBucket",
"s3:GetObject",
"s3:ListAllMyBuckets"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"elasticloadbalancing:DescribeInstanceHealth",
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
"elasticloadbalancing:RegisterInstancesWithLoadBalancer"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"autoscaling:DescribeScheduledActions",
"autoscaling:TerminateInstanceInAutoScalingGroup"
],
"Effect": "Allow",
"Resource": "*"
}
}

Circle CI AWS settings menu

files:
"/root/.ssh/config":
owner: root
group: root
mode: "000600"
content: |
Host github.com
User git
Hostname github.com
IdentityFile /root/.ssh/<username>-github-deploy
"/root/.ssh/known_hosts":
owner: root
group: root
mode: "000644"
content: |
#
# paste output of `ssh-keyscan -H github.com` here
#
commands:
01-command:
command: sudo aws s3 cp s3://gradient-deployment-key/<username>-github-deploy /root/.ssh
02-command:
command: sudo chmod 600 /root/.ssh/<username>-github-deploy

version: 2
jobs:
build:
working_directory: ~/build
docker:
- image: gradientco/node-elastic-beanstalk:7.10.0
steps:
- checkout

- run:
name: Run tests
command: yarn test
- run:
name: Setup AWS credentials
command: |
mkdir ~/.aws && printf "[profile eb-cli]\naws_access_key_id = ${AWS_ACCESS_KEY_ID}\naws_secret_access_key = ${AWS_SECRET_ACCESS_KEY}" > ~/.aws/config
- deploy:
name: Deploy to Elastic Beanstalk
command: |
eb deploy environment-name
  1. Install dependencies using Yarn.
  2. Run our Test Suite.
  3. Create the ~/.aws/config file that the eb cli relies upon for authentication. As stated earlier, despite claiming that it is, this file does not appear to be created by CircleCI automatically so we just need to pull in the environment variables from a file.
  4. Deploy the code where environment-name is the name of your Elastic Beanstalk environment.

Engineering on the incline

Engineering blog by the team at Gradient

Simon McClive

Written by

Co-Founder of Gradient - makers of www.gurn.io

Engineering on the incline

Engineering blog by the team at Gradient