From 19efb45f7941bcdfbf3daf864275a88559442f8a Mon Sep 17 00:00:00 2001 From: samhstn Date: Sun, 17 Sep 2023 15:47:19 +0100 Subject: [PATCH] gha to codedeploy --- .github/workflows/deploy.yml | 51 +++++++++++++++ appspec.yml | 23 +++++++ deploy.sh | 2 +- main.yml | 117 ++++++++++++++++++++++++++++++----- note.txt | 3 + start.sh | 5 ++ stop.sh | 6 ++ 7 files changed, 191 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/deploy.yml create mode 100644 appspec.yml create mode 100644 note.txt create mode 100644 start.sh create mode 100644 stop.sh diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..7d3fb3f --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,51 @@ +name: deploy + +on: push + +permissions: + contents: read + id-token: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + cache: npm + node-version: 16 + - run: npm install + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: artifact + path: node_modules/ + + deploy-infra: + needs: build + if: github.ref_name == 'hello-world' + steps: + - uses: actions/checkout@v3 + - uses: aws-actions/configure-aws-credentials@v1 + with: + role-to-assume: ${{ secrets.IAMROLE_GITHUB }} + role-session-name: GitHub-Action-Role + aws-region: eu-west-1 + - run: | + aws cloudformation deploy \ + --region eu-west-1 \ + --stack-name website \ + --template-file main.yml \ + --no-fail-on-empty-changeset \ + --capabilities CAPABILITY_NAMED_IAM \ + --parameter-overrides \ + EC2InstanceType=t2.micro + + deploy: + needs: deploy-infra + if: github.ref_name == 'hello-world' + steps: + - uses: actions/checkout@v3 + - run: | + echo 'hello world' diff --git a/appspec.yml b/appspec.yml new file mode 100644 index 0000000..bd3fa9d --- /dev/null +++ b/appspec.yml @@ -0,0 +1,23 @@ +version: 0.0 + os: linux + files: + # unzip the build artifact in ~/app + - source: / + destination: /home/ec2-user/app/release + permissions: + # change permissions from root to ec2-user + - object: /home/ec2-user/app/release + pattern: "**" + owner: ec2-user + group: ec2-user + hooks: + ApplicationStart: + # start the application + - location: start.sh + timeout: 300 + runas: ec2-user + ApplicationStop: + # stop the application + - location: stop.sh + timeout: 300 + runas: ec2-user diff --git a/deploy.sh b/deploy.sh index 9d88a3b..32832b8 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,5 +1,5 @@ #!/bin/bash -# + EC2_INSTANCE_TYPE=t2.micro echo -e "\n\n=========== Deploying main.yml ===========" diff --git a/main.yml b/main.yml index c736afc..8899712 100644 --- a/main.yml +++ b/main.yml @@ -5,6 +5,10 @@ Parameters: EC2AMI: Type: 'AWS::SSM::Parameter::Value' Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' + ThumbprintList: + Type: String + Default: 6938fd4d98bab03faadb97b34396831e3780aea1 + Description: A thumbprint of an Open ID Connector is a SHA1 hash of the public certificate of the host Resources: SecurityGroup: Type: AWS::EC2::SecurityGroup @@ -23,6 +27,49 @@ Resources: - Key: Name Value: !Ref AWS::StackName + IDCProvider: + Type: AWS::IAM::OIDCProvider + Properties: + Url: https://token.actions.githubusercontent.com + ClientIdList: + - sts.amazonaws.com + ThumbprintList: + - !Ref ThumbprintList + + GitHubIAMRole: + Type: AWS::IAM::Role + Properties: + Path: / + RoleName: CodeDeployRoleforGitHub + AssumeRolePolicyDocument: + Statement: + - Effect: Allow + Action: sts:AssumeRoleWithWebIdentity + Principal: + Federated: !Ref IDCProvider + Condition: + StringLike: + token.actions.githubusercontent.com:sub: samhstn/website:* + MaxSessionDuration: 3600 + Description: Github Actions role + Policies: + - PolicyName: CodeDeployRoleforGitHub-policy + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'codedeploy:Get*' + - 'codedeploy:Batch*' + - 'codedeploy:CreateDeployment' + - 'codedeploy:RegisterApplicationRevision' + - 'codedeploy:List*' + Resource: + - !Sub 'arn:${AWS::Partition}:codedeploy:*:${AWS::AccountId}:*' + - Effect: Allow + Action: 'cloudformation:*' + Resource: '*' + InstanceRole: Type: AWS::IAM::Role Properties: @@ -36,10 +83,38 @@ Resources: Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/CloudWatchFullAccess + - arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforAWSCodeDeploy Tags: - Key: Name Value: !Ref AWS::StackName + DeploymentRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + Effect: Allow + Principal: + Service: + - codedeploy.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/PowerUserAccess + + DeploymentGroup: + Type: AWS::CodeDeploy::DeploymentGroup + DependsOn: Instance + Properties: + DeploymentGroupName: website + ApplicationName: !Ref DeploymentApplication + DeploymentConfigName: CodeDeployDefault.AllAtOnce + ServiceRoleArn: !GetAtt DeploymentRole.Arn + Ec2TagFilters: + - Key: aws:cloudformation:stack-name + Type: KEY_AND_VALUE + Value: !Ref AWS::StackName + InstanceProfile: Type: "AWS::IAM::InstanceProfile" Properties: @@ -57,8 +132,15 @@ Resources: config: packages: yum: - wget: [] - unzip: [] + ruby: [] + files: + /home/ec2-user/install: + source: !Sub "https://aws-codedeploy-${AWS::Region}.s3.amazonaws.com/latest/install" + mode: "000755" # executable + commands: + 00-install-cd-agent: + command: "./install auto" + cwd: "/home/ec2-user/" Properties: ImageId: !Ref EC2AMI InstanceType: !Ref EC2InstanceType @@ -80,9 +162,6 @@ Resources: # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/bestpractices.html#cfninit yum install -y aws-cfn-bootstrap - # Have CloudFormation install any files and packages from the metadata - /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --region ${AWS::Region} --resource Instance - cat > /tmp/install_script.sh << EOF # START echo "Setting up NodeJS Environment" @@ -97,32 +176,40 @@ Resources: nvm install v16.18.1 nvm use v16.18.1 - # Download latest code, unzip it into /home/ec2-user/app - wget https://github.com/samhstn/website/archive/hello-world.zip - unzip hello-world.zip - mv website-hello-world app - # Create log directory mkdir -p /home/ec2-user/app/logs - - # Run server - cd app - npm install - npm start EOF chown ec2-user:ec2-user /tmp/install_script.sh && chmod a+x /tmp/install_script.sh sleep 1; su - ec2-user -c "/tmp/install_script.sh" + # Have CloudFormation install any files and packages from the metadata + /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --region ${AWS::Region} --resource Instance + # Signal to CloudFormation that the instance is ready /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --region ${AWS::Region} --resource Instance Tags: - Key: Name Value: !Ref AWS::StackName + DeploymentApplication: + Type: AWS::CodeDeploy::Application + Properties: + ApplicationName: !Ref AWS::StackName + ComputePlatform: Server + Outputs: InstanceEndpoint: Description: The DNS name for the created instance Value: !Sub "http://${Instance.PublicDnsName}:8080" Export: Name: InstanceEndpoint + GithubIAMRoleArn: + Description: IAM role for GitHub + Value: !GetAtt GitHubIAMRole.Arn + DeploymentGroup: + Description: Deployment Group + Value: !Ref DeploymentGroup + ApplicationName: + Description: CodeDeploy Application name + Value: !Ref DeploymentApplication diff --git a/note.txt b/note.txt new file mode 100644 index 0000000..eaa7f72 --- /dev/null +++ b/note.txt @@ -0,0 +1,3 @@ +Reference this: + +https://github.com/aws-samples/aws-codedeploy-github-actions-deployment/blob/main/cloudformation/template.yaml diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..94c7f1a --- /dev/null +++ b/start.sh @@ -0,0 +1,5 @@ +#!/bin/bash -xe + +source /home/ec2-user/.bash_profile +cd /home/ec2-user/app/release +npm run start diff --git a/stop.sh b/stop.sh new file mode 100644 index 0000000..c31a903 --- /dev/null +++ b/stop.sh @@ -0,0 +1,6 @@ + #!/bin/bash -xe + +source /home/ec2-user/.bash_profile +[ -d "/home/ec2-user/app/release" ] && \ +cd /home/ec2-user/app/release && \ +npm stop