DEV Community

Cover image for Automating your Cloud Infrastructure with Github Actions
Charlie Thomas
Charlie Thomas

Posted on • Originally published at charliethomas.codes

Automating your Cloud Infrastructure with Github Actions

Managing cloud resources for a production application can be a major pain. To help teams manage resources, AWS provides the Infrastructure as Code solution Cloudformation, but sometimes automating workflows with cloudformation can be painful in and of itself. Luckily, Github actions and Amazon's out of the box actions kit can make your life much easier!

In this guide we will walk through a series of steps to get a simple pipeline up and running.

Step 1: Define your Cloudformation Stack!

For this example, we will define a simple Cloudformation Stack containing a single dynamo table.

AWSTemplateFormatVersion: '2010-09-09'
Description: My Cloud Resource

Parameters:
  Environment:
    Type: String
    Default: stage

Resources:
  SimpleTable:
    Type: 'AWS::DynamoDB::Table'
    Properties:
      BillingMode: PAY_PER_REQUEST
      TableName: !Sub ${Environment}-tablename
      AttributeDefinitions:
        - AttributeName: id
          AttributeType: S        
      KeySchema:
        - AttributeName: id
          KeyType: HASH          
Enter fullscreen mode Exit fullscreen mode

Notice that we have a parameter in the template defined for environment. You can use this if your pipeline needs to deploy to multiple environments.

Step 2: Add permissions keys to your infrastructure github repo!

Next up, you'll want to create some IAM permissions for Github actions to use. As a secure approach, I recommend you create a dedicated user and role for your pipeline to assume when running. In this guide we will define it all in a reusable template to make this a bit future-proof.

Start by defining a user with correlating access keys that we can reference later.

Resources:
  User:
    Type: AWS::IAM::User
    Properties:
      UserName: github-actions-user
  AccessKey:
    Type: AWS::IAM::AccessKey
    Properties:
      UserName: github-actions-user
      Serial: 1
  Credentials:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: github-actions-user
      SecretString: !Sub |
        {
          "AccessKeyId":"${AccessKey}",
          "SecretAccessKey":"${AccessKey.SecretAccessKey}"
        }
Enter fullscreen mode Exit fullscreen mode

Once you have a the User defined, create a Role that we will allow this User to assume, giving it the permissions it needs to manage the resources in our infrastructure templates.

Resources:
  # ... previous User resources from above
  Role:
    Type: AWS::IAM::Role
    Properties:
      RoleName: github-actions-deployer-role
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - cloudformation.amazonaws.com
            Action:
              - "sts:AssumeRole"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess
        # Any other resources you need to manage should be listed here
Enter fullscreen mode Exit fullscreen mode

Notice that we are giving exact permissions for the deployer to only manage DynamoDB resources in this case. You may even want to restrict it even tighter with your own more specific policies.

Finally, tie the User and Role together with a UserPolicy that allows the User to manage Cloudformation stacks and pass our defined Role to Cloudformation.

Resources:
  # ... previous User and Role resources from above
  UserPolicy:
    Type: AWS::IAM::Policy
    Properties:
      Users:
        - github-actions-user
      PolicyName: github-cloudformation-deploy
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Action:
              - "cloudformation:*"
            Effect: Allow
            Resource: "*"
          - Action: "iam:PassRole"
            Effect: Allow
            Resource: !GetAtt Role.Arn
Enter fullscreen mode Exit fullscreen mode

Once you have all of your IAM written you can manually deploy this with the AWS CLI and subsequently fetch the access credentials.

aws cloudformation deploy \
  --stack-name github-actions-cloudformation-deployer \
  --template-file path/to/your/yaml \
  --capabilities CAPABILITY_NAMED_IAM \
  --region us-east-1

aws secretsmanager get-secret-value \
  --secret-id github-actions-user \
  --region us-east-1 \
  --query SecretString \
  --output text
Enter fullscreen mode Exit fullscreen mode

Then take the output credentials and set up 2 secrets in your github repository under Setting > Secrets > Actions Secrets.

Step 3: Create the pipeline in Github!

Finally, now that you have all the permissions set up and a Cloudformation template ready to deploy, create a Github actions workflow in the .github/workflows directory of your project.

on:
  push:
    branches:
      - master

name: Deploy Cloudformation

jobs:
  deploy-cfn:
    name: Deploy Cloudformation Template
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: "us-east-1"
    - name: Execute Changeset
      uses: aws-actions/aws-cloudformation-github-deploy@v1
      with:
        name: my-cloudformation-stack
        template: path/to/my/yaml
        role-arn: arn:aws:iam::${{ steps.creds.outputs.aws-account-id }}:role/github-actions-deployer-role
        no-fail-on-empty-changeset: "1"
        parameter-overrides: >-
          Environment=dev
Enter fullscreen mode Exit fullscreen mode

Using the aws-actions actions kit allows us to assume the proper IAM roles and the execute cloudformation changes with ease. Make sure to point to the right yaml file and pass all your parameters that you defined on the stack from Step 1 (in this example we just override the Environment param). Once in place, every commit to the repo will result in your cloudformation template being deployed automatically to the correlating AWS account. From here, you can expand on these workflows to support more advanced features.

Such as:

References

Top comments (0)