diff --git a/.circleci/config.yml b/.circleci/config.yml index d3986a5d..ba018841 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,11 +1,12 @@ -version: 2 +version: 3 jobs: build: # Variable expansion in working_directory not supported at this time # You will need to modify the code below to reflect your github account/repo setup - working_directory: /go/src/github.com/Securing-DevOps/invoicer-chapter3 + # let's trigger a build + working_directory: /go/src/github.com/daghan/invoicer-chapter3 docker: - - image: circleci/golang:1.8 + - image: circleci/golang:1.10 environment: GO15VENDOREXPERIMENT: 1 branches: @@ -66,4 +67,3 @@ jobs: docker images --no-trunc | awk '/^app/ {print $3}' | sudo tee $CIRCLE_ARTIFACTS/docker-image-shasum256.txt; docker push ${DOCKER_REPO}/${CIRCLE_PROJECT_REPONAME}; fi - diff --git a/create_ebs_env.sh b/create_ebs_env.sh index a9a955c6..5de65afb 100755 --- a/create_ebs_env.sh +++ b/create_ebs_env.sh @@ -135,4 +135,3 @@ aws elasticbeanstalk update-environment \ url="$(jq -r '.CNAME' tmp/$identifier/$apieid.json)" echo "Environment is being deployed. Public endpoint is http://$url" - diff --git a/create_ebs_env_macos.sh b/create_ebs_env_macos.sh new file mode 100755 index 00000000..e754c335 --- /dev/null +++ b/create_ebs_env_macos.sh @@ -0,0 +1,140 @@ +#!/usr/bin/env bash + +# requires: pip install awscli awsebcli + +# uncomment to debug +#set -x + +fail() { + echo configuration failed + exit 1 +} + +export AWS_DEFAULT_REGION=${AWS_REGION:-us-west-2} + +datetag=$(date +%Y%m%d%H%M) +identifier=$(whoami)-invoicer-$datetag +mkdir -p tmp/$identifier + +echo "Creating EBS application $identifier" + +# Find the ID of the default VPC +aws ec2 describe-vpcs --filters Name=isDefault,Values=true > tmp/$identifier/defaultvpc.json || fail +vpcid=$(jq -r '.Vpcs[0].VpcId' tmp/$identifier/defaultvpc.json) +echo "default vpc is $vpcid" + +# Create a security group for the database +aws ec2 create-security-group \ + --group-name $identifier \ + --description "access control to Invoicer Postgres DB" \ + --vpc-id $vpcid > tmp/$identifier/dbsg.json || fail +dbsg=$(jq -r '.GroupId' tmp/$identifier/dbsg.json) +echo "DB security group is $dbsg" + +# Create the database +dbinstclass="db.t2.micro" +dbstorage=5 +dbpass=$(dd if=/dev/urandom bs=128 count=1 2>/dev/null| LC_CTYPE=C tr -dc _A-Z-a-z-0-9) +aws rds create-db-instance \ + --db-name invoicer \ + --db-instance-identifier "$identifier" \ + --vpc-security-group-ids "$dbsg" \ + --allocated-storage "$dbstorage" \ + --db-instance-class "$dbinstclass" \ + --engine postgres \ + --engine-version 9.6.2 \ + --auto-minor-version-upgrade \ + --publicly-accessible \ + --master-username invoicer \ + --master-user-password "$dbpass" \ + --no-multi-az > tmp/$identifier/rds.json || fail +echo "RDS Postgres database is being created. username=invoicer; password='$dbpass'" + +# Retrieve the database hostname +while true; +do + aws rds describe-db-instances --db-instance-identifier $identifier > tmp/$identifier/rds.json + dbhost=$(jq -r '.DBInstances[0].Endpoint.Address' tmp/$identifier/rds.json) + if [ "$dbhost" != "null" ]; then break; fi + echo -n '.' + sleep 10 +done +echo "dbhost=$dbhost" + +# tagging rds instance +aws rds add-tags-to-resource \ + --resource-name $(jq -r '.DBInstances[0].DBInstanceArn' tmp/$identifier/rds.json) \ + --tags "Key=environment-name,Value=invoicer-api" +aws rds add-tags-to-resource \ + --resource-name $(jq -r '.DBInstances[0].DBInstanceArn' tmp/$identifier/rds.json) \ + --tags "Key=Owner,Value=$(whoami)" + +# Create an elasticbeantalk application +aws elasticbeanstalk create-application \ + --application-name $identifier \ + --description "Invoicer $env $datetag" > tmp/$identifier/ebcreateapp.json || fail +echo "ElasticBeanTalk application created" + +# Get the name of the latest Docker solution stack +dockerstack="$(aws elasticbeanstalk list-available-solution-stacks | \ + jq -r '.SolutionStacks[]' | egrep '.+Amazon Linux.+Docker.+' | head -1)" +echo "dockerstack=$dockerstack" + +# Create the EB API environment +echo "replacing dbpass" +sed "s/POSTGRESPASSREPLACEME/$dbpass/" ebs-options.json > tmp/$identifier/ebs-options.json || fail +echo "replacing dbhost in place" +sed -i ".bak" "s/POSTGRESHOSTREPLACEME/$dbhost/" tmp/$identifier/ebs-options.json || fail +aws elasticbeanstalk create-environment \ + --application-name $identifier \ + --environment-name $identifier-invoicer-api \ + --description "Invoicer API environment" \ + --tags "Key=Owner,Value=$(whoami)" \ + --solution-stack-name "$dockerstack" \ + --option-settings file://tmp/$identifier/ebs-options.json \ + --tier "Name=WebServer,Type=Standard,Version=''" > tmp/$identifier/ebcreateapienv.json || fail +apieid=$(jq -r '.EnvironmentId' tmp/$identifier/ebcreateapienv.json) +echo "API environment $apieid is being created" + +# grab the instance ID of the API environment, then its security group, and add that to the RDS security group +while true; +do + aws elasticbeanstalk describe-environment-resources --environment-id $apieid > tmp/$identifier/ebapidesc.json || fail + ec2id=$(jq -r '.EnvironmentResources.Instances[0].Id' tmp/$identifier/ebapidesc.json) + if [ "$ec2id" != "null" ]; then break; fi + echo -n '.' + sleep 10 +done +echo +aws ec2 describe-instances --instance-ids $ec2id > tmp/$identifier/${ec2id}.json || fail +sgid=$(jq -r '.Reservations[0].Instances[0].SecurityGroups[0].GroupId' tmp/$identifier/${ec2id}.json) +aws ec2 authorize-security-group-ingress --group-id $dbsg --source-group $sgid --protocol tcp --port 5432 || fail +echo "API security group $sgid authorized to connect to database security group $dbsg" + +# Upload the application version +aws s3 mb s3://$identifier +aws s3 cp app-version.json s3://$identifier/ +aws elasticbeanstalk create-application-version \ + --application-name "$identifier" \ + --version-label invoicer-api \ + --source-bundle "S3Bucket=$identifier,S3Key=app-version.json" > tmp/$identifier/app-version-s3.json + +# Wait for the environment to be ready (green) +echo -n "waiting for environment" +while true; do + aws elasticbeanstalk describe-environments --environment-id $apieid > tmp/$identifier/$apieid.json + health="$(jq -r '.Environments[0].Health' tmp/$identifier/$apieid.json)" + if [ "$health" == "Green" ]; then break; fi + echo -n '.' + sleep 10 +done +echo + +# Deploy the docker container to the instances +aws elasticbeanstalk update-environment \ + --application-name $identifier \ + --environment-id $apieid \ + --version-label invoicer-api > tmp/$identifier/$apieid.json + +url="$(jq -r '.CNAME' tmp/$identifier/$apieid.json)" +echo "Environment is being deployed. Public endpoint is http://$url" \ No newline at end of file diff --git a/update_docker.sh b/update_docker.sh new file mode 100755 index 00000000..0809ce1d --- /dev/null +++ b/update_docker.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + + +fail() { + echo configuration failed + exit 1 +} + +export AWS_DEFAULT_REGION=${AWS_REGION:-us-west-2} +identifier='daghanaltasivcr202003291657' + +# Get the EB API environment value +apieid=$(jq -r '.EnvironmentId' tmp/$identifier/ebcreateapienv.json) +echo "API environment is $apieid" + + +# Deploy the new docker container to the instances +aws elasticbeanstalk update-environment \ + --application-name $identifier \ + --environment-id $apieid \ + --version-label invoicer-api > tmp/$identifier/$apieid.json + +url="$(jq -r '.CNAME' tmp/$identifier/$apieid.json)" +echo "Environment is being deployed. Public endpoint is http://$url" + +# Wait for the environment to be ready (green) +echo -n "waiting for environment" +while true; do + aws elasticbeanstalk describe-environments --environment-id $apieid > tmp/$identifier/$apieid.json + health="$(jq -r '.Environments[0].Health' tmp/$identifier/$apieid.json)" + if [ "$health" == "Green" ]; then break; fi + echo -n '.' + sleep 10 +done +echo +cat tmp/$identifier/$apieid.json +echo "Environment is deployed. Public endpoint is http://$url" \ No newline at end of file