Skip to content

Commit d88ea64

Browse files
Merge pull request #879 from NHSDigital/feature/made14-NRL-1179-codebuild-runners
[NRL-1179] Add CodeBuild Runners
2 parents 95f515e + c63a5a4 commit d88ea64

File tree

11 files changed

+296
-71
lines changed

11 files changed

+296
-71
lines changed

.github/workflows/daily-build.yml

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,35 +18,19 @@ on:
1818

1919
jobs:
2020
build:
21-
name: Build - develop
22-
runs-on: [self-hosted, ci]
21+
name: Build - ${{ github.ref }}
22+
runs-on: codebuild-nhsd-nrlf-ci-build-project-${{ github.run_id }}-${{ github.run_attempt }}
2323

2424
steps:
25-
- name: Git clone - develop
25+
- name: Git clone - ${{ github.ref }}
2626
uses: actions/checkout@v4
2727
with:
28-
ref: develop
28+
ref: ${{ github.ref }}
2929

30-
- name: Setup asdf cache
31-
uses: actions/cache@v4
32-
with:
33-
path: ~/.asdf
34-
key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }}
35-
restore-keys: |
36-
${{ runner.os }}-asdf-
37-
38-
- name: Install asdf
39-
uses: asdf-vm/actions/[email protected]
40-
with:
41-
asdf_branch: v0.13.1
42-
43-
- name: Install zip
44-
run: sudo apt-get install zip
45-
46-
- name: Setup Python environment
30+
- name: Setup environment
4731
run: |
32+
echo "${HOME}/.asdf/bin" >> $GITHUB_PATH
4833
poetry install --no-root
49-
source $(poetry env info --path)/bin/activate
5034
5135
- name: Run Linting
5236
run: make lint
@@ -55,7 +39,13 @@ jobs:
5539
run: make test
5640

5741
- name: Build Project
58-
run: make build
42+
run: |
43+
echo "PATH: ${PATH}"
44+
echo "HOME: ${HOME}"
45+
echo "python: $(which python)"
46+
echo "asdf: $(which asdf)"
47+
echo "/usr/local/bin: $(ls -la /usr/local/bin)"
48+
make build
5949
6050
- name: Configure Management Credentials
6151
uses: aws-actions/configure-aws-credentials@v4

Dockerfile.ci-build

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
FROM ubuntu:22.04
2+
3+
RUN apt update && \
4+
apt upgrade -y && \
5+
DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt install -y \
6+
build-essential \
7+
ca-certificates \
8+
curl \
9+
git \
10+
gnupg \
11+
libbz2-dev \
12+
libffi-dev \
13+
libicu70 \
14+
liblzma-dev \
15+
libncursesw5-dev \
16+
libreadline-dev \
17+
libsqlite3-dev \
18+
libssl-dev \
19+
libxml2-dev \
20+
libxmlsec1-dev \
21+
llvm \
22+
lsb-release \
23+
make \
24+
python3 \
25+
tar \
26+
tk-dev \
27+
unzip \
28+
wget \
29+
xz-utils \
30+
zip \
31+
zlib1g-dev && \
32+
apt clean && \
33+
rm -rf /var/lib/apt/lists/*
34+
35+
WORKDIR /root
36+
RUN git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.13.1 && \
37+
echo ". $HOME/.asdf/asdf.sh" >> ~/.bashrc && \
38+
echo ". $HOME/.asdf/completions/asdf.bash" >> ~/.bashrc && \
39+
echo "export ASDF_DIR=$HOME/.asdf" >> ~/.bashrc && \
40+
echo "export PATH=\$ASDF_DIR/bin:\$PATH" >> ~/.bashrc && \
41+
echo "export PATH=\$ASDF_DIR/shims:\$PATH" >> ~/.bashrc
42+
43+
COPY .tool-versions .
44+
RUN for plugin in $(cat .tool-versions | cut -d' ' -f1); do \
45+
./.asdf/bin/asdf plugin add "${plugin}"; \
46+
done && \
47+
./.asdf/bin/asdf install && \
48+
ln -s $(pwd)/.asdf/shims/* /usr/local/bin/.
49+
50+
CMD [ "/bin/bash" ]

Makefile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,28 @@ build-api-packages: ./api/consumer/* ./api/producer/*
7474
./scripts/build-lambda-package.sh $${api} $(DIST_PATH); \
7575
done
7676

77+
build-ci-image: ## Build the CI image
78+
@echo "Building the CI image"
79+
docker build \
80+
-t nhsd-nrlf-ci-build:latest \
81+
-f Dockerfile.ci-build
82+
83+
ecr-login: ## Login to NRLF ECR repo
84+
@echo "Logging into ECR"
85+
$(eval AWS_REGION := $(shell aws configure get region))
86+
$(eval AWS_ACCOUNT_ID := $(shell aws sts get-caller-identity | jq -r .Account))
87+
@aws ecr get-login-password --region "$(AWS_REGION)" \
88+
| docker login --username AWS --password-stdin \
89+
$(AWS_ACCOUNT_ID).dkr.ecr.$(AWS_REGION).amazonaws.com
90+
91+
publish-ci-image: ## Publish the CI image
92+
@echo "Publishing the CI image"
93+
$(eval AWS_REGION := $(shell aws configure get region))
94+
$(eval AWS_ACCOUNT_ID := $(shell aws sts get-caller-identity | jq -r .Account))
95+
@docker tag nhsd-nrlf-ci-build:latest \
96+
$(AWS_ACCOUNT_ID).dkr.ecr.$(AWS_REGION).amazonaws.com/nhsd-nrlf-ci-build:latest
97+
@docker push $(AWS_ACCOUNT_ID).dkr.ecr.$(AWS_REGION).amazonaws.com/nhsd-nrlf-ci-build:latest
98+
7799
test: check-warn ## Run the unit tests
78100
@echo "Running unit tests"
79101
pytest --ignore=tests/smoke $(TEST_ARGS)

scripts/bootstrap.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ TERRAFORM_ROLE_NAME="terraform"
88
MGMT_ACCOUNT_ID_LOCATION="${PROFILE_PREFIX}--mgmt--mgmt-account-id"
99
PROD_ACCOUNT_ID_LOCATION="${PROFILE_PREFIX}--mgmt--prod-account-id"
1010
TEST_ACCOUNT_ID_LOCATION="${PROFILE_PREFIX}--mgmt--test-account-id"
11+
TEST_BACKUP_ACCOUNT_ID_LOCATION="${PROFILE_PREFIX}--mgmt--test-backup-account-id"
1112
DEV_ACCOUNT_ID_LOCATION="${PROFILE_PREFIX}--mgmt--dev-account-id"
1213

1314

@@ -59,7 +60,9 @@ function _bootstrap() {
5960
aws secretsmanager create-secret --name "${MGMT_ACCOUNT_ID_LOCATION}"
6061
aws secretsmanager create-secret --name "${DEV_ACCOUNT_ID_LOCATION}"
6162
aws secretsmanager create-secret --name "${TEST_ACCOUNT_ID_LOCATION}"
63+
aws secretsmanager create-secret --name "${TEST_BACKUP_ACCOUNT_ID_LOCATION}"
6264
aws secretsmanager create-secret --name "${PROD_ACCOUNT_ID_LOCATION}"
65+
aws secretsmanager create-secret --name "${PROFILE_PREFIX}--codebuild-github-pat"
6366
;;
6467
#----------------
6568
"delete-mgmt")
@@ -80,7 +83,9 @@ function _bootstrap() {
8083
aws secretsmanager delete-secret --secret-id "${MGMT_ACCOUNT_ID_LOCATION}"
8184
aws secretsmanager delete-secret --secret-id "${DEV_ACCOUNT_ID_LOCATION}"
8285
aws secretsmanager delete-secret --secret-id "${TEST_ACCOUNT_ID_LOCATION}"
86+
aws secretsmanager delete-secret --secret-id "${TEST_BACKUP_ACCOUNT_ID_LOCATION}"
8387
aws secretsmanager delete-secret --secret-id "${PROD_ACCOUNT_ID_LOCATION}"
88+
aws secretsmanager delete-secret --secret-id "${PROFILE_PREFIX}--codebuild-github-pat"
8489
;;
8590
#----------------
8691
"create-non-mgmt")

terraform/account-wide-infrastructure/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,28 @@ Once you're happy with your planned changes, you can apply them with:
4343
terraform apply
4444
```
4545
46+
### Build and publish the container image for CI build
47+
48+
Once all the mgmt infra has been deployed, you need to build and publish the CI image to the ECR repo.
49+
50+
To do this, first build the image as follows:
51+
52+
```
53+
make build-ci-image
54+
```
55+
56+
and then login to ECR:
57+
58+
```
59+
make ecr-login
60+
```
61+
62+
and push the image:
63+
64+
```
65+
make publish-ci-image
66+
```
67+
4668
## Deploy account wide resources
4769
4870
To deploy the account wide resources, first login to the AWS mgmt account on the CLI.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
data "aws_iam_policy_document" "codebuild_assume_role" {
2+
statement {
3+
effect = "Allow"
4+
5+
principals {
6+
type = "Service"
7+
identifiers = ["codebuild.amazonaws.com"]
8+
}
9+
10+
actions = [
11+
"sts:AssumeRole",
12+
"sts:AssumeRoleWithWebIdentity",
13+
"sts:TagSession"
14+
]
15+
16+
condition {
17+
test = "StringEquals"
18+
variable = "aws:SourceAccount"
19+
values = ["${data.aws_caller_identity.current.account_id}"]
20+
}
21+
}
22+
}
23+
24+
resource "aws_iam_role" "codebuild_service_role" {
25+
name = "${local.project}-codebuild-service-role"
26+
assume_role_policy = data.aws_iam_policy_document.codebuild_assume_role.json
27+
}
28+
29+
data "aws_iam_policy_document" "codebuild_policy" {
30+
statement {
31+
effect = "Allow"
32+
33+
actions = [
34+
"logs:CreateLogGroup",
35+
"logs:CreateLogStream",
36+
"logs:PutLogEvents",
37+
]
38+
39+
resources = ["*"]
40+
}
41+
42+
statement {
43+
effect = "Allow"
44+
actions = [
45+
"codeconnections:GetConnectionToken",
46+
"codeconnections:GetConnection"
47+
]
48+
resources = ["arn:aws:codestar-connections:us-east-1:123456789012:connection/guid-string"]
49+
}
50+
51+
statement {
52+
effect = "Allow"
53+
actions = [
54+
"secretsmanager:GetSecretValue",
55+
"secretsmanager:DescribeSecret",
56+
"secretsmanager:ListSecretVersionIds"
57+
]
58+
resources = [
59+
"arn:aws:secretsmanager:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:secret:${local.project}--codebuild-github-pat-*",
60+
]
61+
}
62+
63+
statement {
64+
effect = "Allow"
65+
actions = [
66+
"ecr:*"
67+
]
68+
resources = [
69+
"${aws_ecr_repository.repository.arn}",
70+
"${aws_ecr_repository.repository.arn}:*"
71+
]
72+
}
73+
}
74+
75+
resource "aws_iam_role_policy" "codebuild_policy" {
76+
role = aws_iam_role.codebuild_service_role.name
77+
policy = data.aws_iam_policy_document.codebuild_policy.json
78+
}
79+
80+
resource "aws_codebuild_project" "project" {
81+
name = "${local.project}-ci-build-project"
82+
description = "NRLF CI Build Project"
83+
service_role = aws_iam_role.codebuild_service_role.arn
84+
85+
artifacts {
86+
type = "NO_ARTIFACTS"
87+
}
88+
89+
environment {
90+
compute_type = "BUILD_GENERAL1_SMALL"
91+
image = "${aws_ecr_repository.repository.repository_url}:latest"
92+
type = "LINUX_CONTAINER"
93+
image_pull_credentials_type = "CODEBUILD"
94+
}
95+
96+
logs_config {
97+
cloudwatch_logs {
98+
group_name = "${local.project}-ci-build-logs"
99+
stream_name = "build-log-stream"
100+
}
101+
}
102+
103+
source {
104+
type = "GITHUB"
105+
location = "https://github.com/NHSDigital/NRLF"
106+
git_clone_depth = 1
107+
}
108+
109+
source_version = "main"
110+
project_visibility = "PRIVATE"
111+
}
112+
113+
resource "aws_codebuild_webhook" "github_workflow" {
114+
project_name = aws_codebuild_project.project.name
115+
build_type = "BUILD"
116+
filter_group {
117+
filter {
118+
type = "EVENT"
119+
pattern = "WORKFLOW_JOB_QUEUED"
120+
}
121+
}
122+
depends_on = [aws_codebuild_project.project, aws_iam_role.codebuild_service_role]
123+
}

terraform/account-wide-infrastructure/mgmt/data.tf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
data "aws_caller_identity" "current" {}
2+
3+
data "aws_region" "current" {}
4+
15
data "aws_dynamodb_table" "terraform_state_lock" {
26
name = "${local.project}--terraform-state-lock"
37
}
@@ -30,10 +34,18 @@ data "aws_secretsmanager_secret" "test_account_id" {
3034
name = "${local.project}--mgmt--test-account-id"
3135
}
3236

37+
data "aws_secretsmanager_secret" "test_backup_account_id" {
38+
name = "${local.project}--mgmt--test-backup-account-id"
39+
}
40+
3341
data "aws_secretsmanager_secret_version" "dev_account_id" {
3442
secret_id = data.aws_secretsmanager_secret.dev_account_id.name
3543
}
3644

3745
data "aws_secretsmanager_secret_version" "test_account_id" {
3846
secret_id = data.aws_secretsmanager_secret.test_account_id.name
3947
}
48+
49+
data "aws_secretsmanager_secret_version" "test_backup_account_id" {
50+
secret_id = data.aws_secretsmanager_secret.test_backup_account_id.name
51+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
resource "aws_ecr_repository" "repository" {
2+
name = "${local.project}-ci-build"
3+
image_tag_mutability = "MUTABLE"
4+
}
5+
6+
data "aws_iam_policy_document" "codebuild_access_policy" {
7+
statement {
8+
sid = "CodeBuildEcrAccess"
9+
effect = "Allow"
10+
11+
principals {
12+
type = "Service"
13+
identifiers = ["codebuild.amazonaws.com"]
14+
}
15+
16+
actions = [
17+
"ecr:GetDownloadUrlForLayer",
18+
"ecr:BatchGetImage",
19+
"ecr:BatchCheckLayerAvailability",
20+
]
21+
22+
condition {
23+
test = "StringEquals"
24+
variable = "aws:SourceAccount"
25+
values = ["${data.aws_caller_identity.current.account_id}"]
26+
}
27+
}
28+
}
29+
30+
resource "aws_ecr_repository_policy" "codebuild_access_policy" {
31+
repository = aws_ecr_repository.repository.name
32+
policy = data.aws_iam_policy_document.codebuild_access_policy.json
33+
}

terraform/account-wide-infrastructure/mgmt/iam__developer-role.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ module "developer_policy" {
6363
Resource = [
6464
"arn:aws:iam::${data.aws_secretsmanager_secret_version.dev_account_id.secret_string}:role/terraform",
6565
"arn:aws:iam::${data.aws_secretsmanager_secret_version.test_account_id.secret_string}:role/terraform",
66+
"arn:aws:iam::${data.aws_secretsmanager_secret_version.test_backup_account_id.secret_string}:role/terraform"
6667
]
6768
},
6869
{

0 commit comments

Comments
 (0)