AWS CodePipeline

AWS CodePipeline - Continuous Integration and Delivery

Published: Friday, 1 April 2022

AWS CodePipeline

AWS CodePipeline offers a way to define workflows for continuous integration and delivery (CI/CD).

Various AWS services are used to implement each stage of a pipeline.

There is no need to provision upfront infrastructure as build agents are provisioned on demand. This can be cheaper than running a dedicated build server.

Stages

A CodePipeline is divided into many stages, or steps in a workflow. A simple linear workflow might be

  • source checkout
  • build a docker image
  • deploy the image as docker container

By configuring a git webhook, a pipeline can be triggered each time a commit is pushed to source control.

Artifact store

Each stage of a pipeline is executed asynchronously, and may use output artifacts from a previous stage. Artifact storage is required to accommodate this. In 2022, S3 is only option.

Source checkout

AWS provides git hosting via CodeCommit.

Source code residing on GitHub or BitBucket can be accessed using a CodeStar connections.

An archive artifact (zip of the source code) is an output of this stage. This can be sent to a downstream build stage.

Build

This stage is handled by a AWS CodeBuild project.

Role

CodePipeline will assume a role to run. It may need access to

  • The S3 bucket for artifact storage
  • The CodeStar connection to access source code
  • The CodeBuild project to start the build job.

Terraform

Sample codepipeline

# github
resource "aws_codestarconnections_connection" "github" {
  name          = "github"
  provider_type = "GitHub"
}

# S3 bucket where artifacts are stored for the pipeline
resource "aws_s3_bucket" "example_codepipeline" {
  bucket = "example-codepipeline"
}

resource "aws_s3_bucket_public_access_block" "example_codepipeline" {
  bucket = aws_s3_bucket.example_codepipeline.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_s3_bucket_acl" "example_codepipeline" {
  bucket = aws_s3_bucket.example_codepipeline.id
  acl    = "private"
}

# pipeline role
resource "aws_iam_role" "example" {
  name               = "example-codepipeline"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "codepipeline.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
}

resource "aws_iam_role_policy" "example" {
  name = "example-codepipeline"
  role   = aws_iam_role.example.id
  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "codestar-connections:UseConnection"
      ],
      "Resource": "${aws_codestarconnections_connection.github.arn}"
    },
    {
      "Effect":"Allow",
      "Action": [
        "s3:GetObject",
        "s3:GetObjectVersion",
        "s3:GetBucketVersioning",
        "s3:PutObjectAcl",
        "s3:PutObject"
      ],
      "Resource": [
        "${aws_s3_bucket.example_codepipeline.arn}",
        "${aws_s3_bucket.example_codepipeline.arn}/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "codebuild:BatchGetBuilds",
        "codebuild:StartBuild"
      ],
      "Resource": [
        "${aws_codebuild_project.example.arn}"
      ]
    }
  ]
}
EOF
}

resource "aws_codepipeline" "example" {
  name     = "example"
  role_arn = aws_iam_role.example.arn

  artifact_store {
    location = aws_s3_bucket.example.bucket
    type     = "S3"
  }
  stage {
    name = "Source"
    action {
      category         = "Source"
      name             = "Source"
      owner            = "AWS"
      provider         = "CodeStarSourceConnection"
      version          = "1"
      output_artifacts = ["source_output"]

      configuration = {
        ConnectionArn    = aws_codestarconnections_connection.github.arn
        FullRepositoryId = "magicmonster/example"
        BranchName       = "main"
      }
    }
  }
  stage {
    name = "Build"

    action {
      name             = "Build"
      category         = "Build"
      owner            = "AWS"
      provider         = "CodeBuild"
      input_artifacts  = ["source_output"]
      output_artifacts = ["build_output"]
      version          = "1"

      configuration = {
        ProjectName = aws_codebuild_project.example.name
      }
    }
  }
}

References


More Articles