Central Repository for Attini Distributions
Description
You often want to have a central repository for your build artifacts. This example shows how to configure an S3 bucket to act as a central repository for Attini distributions.
Prerequisites
- AWS account that is a member of an AWS organization.
- Install the AWS CLI and Configure CLI credentials.
- Install the Attini CLI.
- A GitHub repository.
We will go through:
- How to configure the S3 bucket.
- How to configure GitHub actions to build the Attini distribution. using the Attini CLI.
- How to push the Attini distributions to S3 using the AWS CLI.
- How to fetch the Attini distribution from the S3 bucket and deploy. it to a different AWS Account using the Attini CLI.
This example is for GitHub actions, but the general architecture will work with any build server that integrates with git and AWS. You will just have to reconfigure a few things.
Create the S3 Bucket
First, we need an S3 bucket with the following configuration.
Ensure you have AWS CloudTrail data events enabled for this bucket if you plan to use it in Production. If the distributions are tampered with, you want to know who did it.
-
We need a life cycle policy for the objects. There will always be a copy of the distributions inside every individual environment using it, so you don’t need to worry about removing distributions that might be needed for a rollback.
In the example below, we will delete the distributions after 365 days.
-
We need a bucket policy allowing application accounts to get the distributions.
The example below opens the bucket for the entire AWS Organization.
-
We need to give GitHub actions permission to upload an object to the bucket.
In the example below, I create a Managed Policy that I will use for an IAM User or an IAM Role.
Example bucket CloudFormation template
AWSTemplateFormatVersion: 2010-09-09
Description: Example of and S3 bucket that can act as a central repository for attini distributions.
Parameters:
BucketName:
Type: String
Description: The repository (s3 bucket) name.
OrganizationId:
Type: String
Description: The id of your AWS Organization (o-xxxxxxxxxx). This will allow all AWS Accounts in your AWS Organization to get objects from the bucket.
Resources:
AttiniRepository:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketName
BucketEncryption:
ServerSideEncryptionConfiguration:
-
ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
VersioningConfiguration:
Status: Enabled
LifecycleConfiguration:
Rules:
-
Id: ExpirationInDays
Status: Enabled
ExpirationInDays: 356
-
Id: MultipartUploadLifecycleRule
Status: Enabled
AbortIncompleteMultipartUpload:
DaysAfterInitiation: 7
-
Id: NoncurrentVersionExpirationInDays
Status: Enabled
NoncurrentVersionExpirationInDays: 30
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref AttiniRepository
PolicyDocument:
Statement:
-
Action:
- s3:GetObject
- s3:ListBucket
Effect: Allow
Resource:
- !GetAtt AttiniRepository.Arn
- !Sub ${AttiniRepository.Arn}/*
Principal: "*"
Condition:
StringEquals:
aws:PrincipalOrgID: !Ref OrganizationId
PushAttiniDistribution:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: push-attini-distribution
Description: This policy allows an IAM User or IAM Role to push distribution to the repository bucket
PolicyDocument:
Version: 2012-10-17
Statement:
- Action:
- s3:PutObject
Effect: Allow
Resource: !Sub ${AttiniRepository.Arn}/*
Outputs:
AttiniRepository:
Description: The name of the S3 bucket
Value: !Ref AttiniRepository
Configure your Git Repository
Configure access to the S3 bucket
If your build server already has access to S3, you can skip this step.
You can give GitHub actions AWS access in 2 ways using IAM Role (OIDC) or with an IAM User.
Using the IAM Role is better because you want to have to manage API keys, so this is recommended for production use.
Using the IAM User is fast and easy, so for a POC, this opinion is ok.
IAM Role (recommend)
- Follow the steps in this guide.
- Attach the
push-attini-distribution
Managed Policy to your role.
IAM User (old way)
- Create an AWS IAM User that has “s3:PutObject” access to the
bucket we just created. You can use the
push-attini-distribution
Managed Policy in the template if you want to. Temporarily save the “Access key ID” and “Secret access key” somewhere safe. - Go to your Gihub repository > Settings > Secrets > Actions secrets.
- Add 2 new secrets, one called
AWS_ACCESS_KEY_ID
and the otherAWS_SECRET_ACCESS_KEY
and populate the values that you saved from step 1.
Configure the Attini distribution
Create a file called attini-config.yaml
in the root of the repository.
It should look something like this:
distributionName: hello-world
package:
prePackage:
commands:
- attini configure set-dist-id --id ${GITHUB_SHA} # this command will set the Attini distribution to the git commit id
If you ever need to package (attini distribution package
) the
distribution on your local computer when doing development, you can mock
the GITHUB_SHA
environment variable using the flag
--environment-config-script
. In this script, you can add the shell
command export GITHUB_SHA=test-commit-id
.
Configure the GitHub action
In the root of your repository, create a file called
.github/workflows/build.yml
Now add the following code to the file:
on:
push:
branches:
- main
name: Build and push Attini distribution
jobs:
deploy:
name: Build and push
runs-on: ubuntu-latest
steps:
- 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: eu-west-1
- name: Install Attini CLI # Better to do this in the container image if it's possible
shell: bash
run: |
curl -fsSO https://docs.attini.io/blob/attini-cli/install-cli.sh
bash install-cli.sh -s
- name: Check out repository code
uses: actions/checkout@v2
- name: Package and upload the Attini distribution
shell: bash
run: |
# GITHUB_SHA is an environment variable which is our git commit id, which is a good value to use for the distribution id.
DISTRIBUTION_ID="${GITHUB_SHA}"
DISTRIBUTION_NAME="hello-world"
REPOSITORY_BUCKET_NAME="attini-repository-bucket"
attini distribution package . --name ${DISTRIBUTION_NAME}.zip
# If you upload the distribution to the path "/latest/" it easy to find the latest version.
aws s3 cp ${DISTRIBUTION_NAME}.zip s3://${REPOSITORY_BUCKET_NAME}/${DISTRIBUTION_NAME}/latest/${DISTRIBUTION_NAME}.zip
# You also want to save a copy with the DISTRIBUTION_ID in path so that you can easily get old versions.
aws s3 cp ${DISTRIBUTION_NAME}.zip s3://${REPOSITORY_BUCKET_NAME}/${DISTRIBUTION_NAME}/${DISTRIBUTION_ID}/${DISTRIBUTION_NAME}.zip
At the very least you want to change the values for aws-region
and
REPOSITORY_BUCKET_NAME
in the file.
Next time you push a change to the main branch, your distribution
will be packaged and uploaded to the s3 bucket to the location
/hello-world/${DISTRIBUTION_ID}/hello-world.zip
and
/hello-world/latest/hello-world.zip
.
You can, of course, name your distributions whatever you want and use any prefix or path in S3 that makes sense for your way of working, but having the distribution name and id in the S3 key is a good place to start.
You can also add additional steps that automatically log in to your Development AWS account and deploy the distribution there.
Deploy the Attini distribution from the repository
Now log in to your application account (for example, Development or Production) from your terminal, build server, or AWS CloudShell and run the following command:
attini deploy run s3://${REPOSITORY_BUCKET_NAME}/hello-world/${DISTRIBUTION_ID}/hello-world.zip
This will pull the distribution from the repository and deploy it to your current environment.