From b4efa3016ce51e7813f415b6d61f5598dcc95cc7 Mon Sep 17 00:00:00 2001 From: Alexander Jelinek Date: Thu, 13 Jun 2024 14:59:47 +0200 Subject: [PATCH 1/9] update mig module to v11 --- modules/gh-runner-mig-vm/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gh-runner-mig-vm/main.tf b/modules/gh-runner-mig-vm/main.tf index b03e92b..6ce2cad 100644 --- a/modules/gh-runner-mig-vm/main.tf +++ b/modules/gh-runner-mig-vm/main.tf @@ -154,7 +154,7 @@ module "mig_template" { *****************************************/ module "mig" { source = "terraform-google-modules/vm/google//modules/mig" - version = "~> 7.0" + version = "~> 11.0" project_id = var.project_id subnetwork_project = var.project_id hostname = local.instance_name From a3330ce6b6109c9ac9a5df9319a5e9f9de36ac27 Mon Sep 17 00:00:00 2001 From: Alexander Jelinek Date: Mon, 17 Jun 2024 14:17:42 +0200 Subject: [PATCH 2/9] add possibility to authenticate with github app and add runner group configuration --- modules/gh-runner-mig-vm/main.tf | 15 +++-- modules/gh-runner-mig-vm/scripts/startup.sh | 63 ++++++++++++++++++++- modules/gh-runner-mig-vm/variables.tf | 24 ++++++++ 3 files changed, 96 insertions(+), 6 deletions(-) diff --git a/modules/gh-runner-mig-vm/main.tf b/modules/gh-runner-mig-vm/main.tf index 6ce2cad..b6c6dc6 100644 --- a/modules/gh-runner-mig-vm/main.tf +++ b/modules/gh-runner-mig-vm/main.tf @@ -89,18 +89,23 @@ resource "google_secret_manager_secret" "gh-secret" { } } } + resource "google_secret_manager_secret_version" "gh-secret-version" { provider = google-beta secret = google_secret_manager_secret.gh-secret.id secret_data = jsonencode({ - "REPO_NAME" = var.repo_name - "REPO_OWNER" = var.repo_owner - "GITHUB_TOKEN" = var.gh_token - "LABELS" = join(",", var.gh_runner_labels) + "REPO_NAME" = var.repo_name + "REPO_OWNER" = var.repo_owner + "RUNNER_VERSION" = var.gh_runner_version + "RUNNER_GROUP" = var.gh_runner_group + "GITHUB_TOKEN" = var.gh_token + "GHA_INSTALLATION_ID" = var.gha_installation_id + "GHA_CLIENT_ID" = var.gha_client_id + "GHA_PRIVATE_KEY" = file(var.gha_private_key) + "LABELS" = join(",", var.gh_runner_labels) }) } - resource "google_secret_manager_secret_iam_member" "gh-secret-member" { provider = google-beta project = var.project_id diff --git a/modules/gh-runner-mig-vm/scripts/startup.sh b/modules/gh-runner-mig-vm/scripts/startup.sh index 2f3c52d..4546b20 100644 --- a/modules/gh-runner-mig-vm/scripts/startup.sh +++ b/modules/gh-runner-mig-vm/scripts/startup.sh @@ -17,6 +17,51 @@ apt-get update apt-get -y install jq +generate_gha_jwt () { + #################### + # Generate JWT token + # Doc: https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app + #################### + + client_id="$GHA_CLIENT_ID" # Client ID as first argument + + pem=$( cat "$GHA_PRIVATE_KEY" ) # file path of the private key as second argument + + now=$(date +%s) + iat=$((now - 60)) # Issues 60 seconds in the past + exp=$((now + 600)) # Expires 10 minutes in the future + + #b64enc() { tr -d '\n' | tr -d '\r' | base64 | tr '+/' '-_' | tr -d '='; } + b64enc() { openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n'; } + + header_json='{ + "typ":"JWT", + "alg":"RS256" + }' + # Header encode + header=$( echo -n "${header_json}" | b64enc ) + + payload_json='{ + "iat":'"${iat}"', + "exp":'"${exp}"', + "iss":"'"${client_id}"'" + }' + # Payload encode + payload=$( echo -n "${payload_json}" | b64enc ) + + # Signature + header_payload="${header}"."${payload}" + signature=$( + openssl dgst -sha256 -sign <(echo -n "${pem}") \ + <(echo -n "${header_payload}") | b64enc + ) + + # Create JWT + JWT="${header_payload}"."${signature}" + + #printf "%s\n" "$JWT" +} + secretUri=$(curl -sS "http://metadata.google.internal/computeMetadata/v1/instance/attributes/secret-id" -H "Metadata-Flavor: Google") #secrets URI is of the form projects/$PROJECT_NUMBER/secrets/$SECRET_NAME/versions/$SECRET_VERSION #split into array based on `/` delimeter @@ -31,7 +76,23 @@ secrets=$(gcloud secrets versions access "$SECRET_VERSION" --secret="$SECRET_NAM # we want to use wordsplitting export $(echo "$secrets" | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]") #github runner version -GH_RUNNER_VERSION="2.283.2" +GH_RUNNER_VERSION=${RUNNER_VERSION:-2.283.3} + +#only execute when client_id and private_key are not empty +#use as check to see if we want to use github app for authentication +#because we are overwriting the GITHUB_TOKEN variable +if [[ ! -z $GHA_CLIENT_ID ]] && [[ ! -z $GHA_PRIVATE_KEY ]]; then + generate_gha_jwt + + #Get access token + #Docs: https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-an-installation-access-token-for-a-github-app + GITHUB_TOKEN=$(curl --request POST \ + --url "https://api.github.com/app/installations/${GHA_INSTALLATION_ID}/access_tokens" \ + --header "Accept: application/vnd.github+json" \ + --header "Authorization: Bearer ${JWT_ENCODED}" \ + --header "X-GitHub-Api-Version: 2022-11-28" | jq -r .token) +fi + #get actions binary curl -o actions.tar.gz --location "https://github.com/actions/runner/releases/download/v${GH_RUNNER_VERSION}/actions-runner-linux-x64-${GH_RUNNER_VERSION}.tar.gz" mkdir /runner diff --git a/modules/gh-runner-mig-vm/variables.tf b/modules/gh-runner-mig-vm/variables.tf index 5641c98..b49545c 100644 --- a/modules/gh-runner-mig-vm/variables.tf +++ b/modules/gh-runner-mig-vm/variables.tf @@ -71,6 +71,12 @@ variable "repo_owner" { description = "Owner of the repo for the Github Action" } +variable "gh_runner_version" { + type = string + description = "Version of the runner to deploy" + default = "2.283.2" +} + variable "gh_runner_labels" { type = set(string) description = "GitHub runner labels to attach to the runners. Docs: https://docs.github.com/en/actions/hosting-your-own-runners/using-labels-with-self-hosted-runners" @@ -94,6 +100,24 @@ variable "gh_token" { description = "Github token that is used for generating Self Hosted Runner Token" } +variable "gha_client_id" { + type = string + description = "Github App ID" + default = "" +} + +variable "gha_installation_id" { + type = string + description = "Github Installation ID" + default = "" +} + +variable "gha_private_key" { + type = string + description = "Github App private key" + default = "./gha_private-key.pem" +} + variable "service_account" { description = "Service account email address" type = string From 730afe76040d5a110c80732b0b6381a9239ca65a Mon Sep 17 00:00:00 2001 From: Alexander Jelinek Date: Mon, 17 Jun 2024 14:46:27 +0200 Subject: [PATCH 3/9] encode private key to generate valid json for jq --- modules/gh-runner-mig-vm/main.tf | 2 +- modules/gh-runner-mig-vm/scripts/startup.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/gh-runner-mig-vm/main.tf b/modules/gh-runner-mig-vm/main.tf index b6c6dc6..2d96576 100644 --- a/modules/gh-runner-mig-vm/main.tf +++ b/modules/gh-runner-mig-vm/main.tf @@ -101,7 +101,7 @@ resource "google_secret_manager_secret_version" "gh-secret-version" { "GITHUB_TOKEN" = var.gh_token "GHA_INSTALLATION_ID" = var.gha_installation_id "GHA_CLIENT_ID" = var.gha_client_id - "GHA_PRIVATE_KEY" = file(var.gha_private_key) + "GHA_PRIVATE_KEY" = base64encode(file(var.gha_private_key)) "LABELS" = join(",", var.gh_runner_labels) }) } diff --git a/modules/gh-runner-mig-vm/scripts/startup.sh b/modules/gh-runner-mig-vm/scripts/startup.sh index 4546b20..a8bd52c 100644 --- a/modules/gh-runner-mig-vm/scripts/startup.sh +++ b/modules/gh-runner-mig-vm/scripts/startup.sh @@ -25,7 +25,7 @@ generate_gha_jwt () { client_id="$GHA_CLIENT_ID" # Client ID as first argument - pem=$( cat "$GHA_PRIVATE_KEY" ) # file path of the private key as second argument + pem=$(echo -n "$GHA_PRIVATE_KEY" | base64 --decode) # file path of the private key as second argument now=$(date +%s) iat=$((now - 60)) # Issues 60 seconds in the past From 025e493abe26a4b9608768eaf0da75ca92c42934 Mon Sep 17 00:00:00 2001 From: Alexander Jelinek Date: Mon, 17 Jun 2024 15:02:06 +0200 Subject: [PATCH 4/9] add missing JWT_ENCODED variable --- modules/gh-runner-mig-vm/scripts/startup.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/gh-runner-mig-vm/scripts/startup.sh b/modules/gh-runner-mig-vm/scripts/startup.sh index a8bd52c..24887d3 100644 --- a/modules/gh-runner-mig-vm/scripts/startup.sh +++ b/modules/gh-runner-mig-vm/scripts/startup.sh @@ -58,6 +58,7 @@ generate_gha_jwt () { # Create JWT JWT="${header_payload}"."${signature}" + JWT_ENCODED=$(echo -n "$JWT" | base64) #printf "%s\n" "$JWT" } @@ -81,7 +82,7 @@ GH_RUNNER_VERSION=${RUNNER_VERSION:-2.283.3} #only execute when client_id and private_key are not empty #use as check to see if we want to use github app for authentication #because we are overwriting the GITHUB_TOKEN variable -if [[ ! -z $GHA_CLIENT_ID ]] && [[ ! -z $GHA_PRIVATE_KEY ]]; then +if [[ -n $GHA_CLIENT_ID ]] && [[ -n $GHA_PRIVATE_KEY ]]; then generate_gha_jwt #Get access token From 70566f8aa870cc022b966d6e2cc53aa31a47a4d2 Mon Sep 17 00:00:00 2001 From: Alexander Jelinek Date: Mon, 17 Jun 2024 15:13:22 +0200 Subject: [PATCH 5/9] remove bas64 encoding for jwt, isnt necessary --- modules/gh-runner-mig-vm/scripts/startup.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/gh-runner-mig-vm/scripts/startup.sh b/modules/gh-runner-mig-vm/scripts/startup.sh index 24887d3..f094fde 100644 --- a/modules/gh-runner-mig-vm/scripts/startup.sh +++ b/modules/gh-runner-mig-vm/scripts/startup.sh @@ -58,7 +58,6 @@ generate_gha_jwt () { # Create JWT JWT="${header_payload}"."${signature}" - JWT_ENCODED=$(echo -n "$JWT" | base64) #printf "%s\n" "$JWT" } @@ -90,7 +89,7 @@ if [[ -n $GHA_CLIENT_ID ]] && [[ -n $GHA_PRIVATE_KEY ]]; then GITHUB_TOKEN=$(curl --request POST \ --url "https://api.github.com/app/installations/${GHA_INSTALLATION_ID}/access_tokens" \ --header "Accept: application/vnd.github+json" \ - --header "Authorization: Bearer ${JWT_ENCODED}" \ + --header "Authorization: Bearer ${JWT}" \ --header "X-GitHub-Api-Version: 2022-11-28" | jq -r .token) fi From b84f48271ef94d89e85630480bbd367011609fb4 Mon Sep 17 00:00:00 2001 From: Alexander Jelinek Date: Mon, 17 Jun 2024 15:19:09 +0200 Subject: [PATCH 6/9] make shutdown script github app compatible --- modules/gh-runner-mig-vm/scripts/shutdown.sh | 62 ++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/modules/gh-runner-mig-vm/scripts/shutdown.sh b/modules/gh-runner-mig-vm/scripts/shutdown.sh index 420ca36..aefe1bb 100644 --- a/modules/gh-runner-mig-vm/scripts/shutdown.sh +++ b/modules/gh-runner-mig-vm/scripts/shutdown.sh @@ -13,6 +13,52 @@ # See the License for the specific language governing permissions and # limitations under the License. +generate_gha_jwt () { + #################### + # Generate JWT token + # Doc: https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app + #################### + + client_id="$GHA_CLIENT_ID" # Client ID as first argument + + pem=$(echo -n "$GHA_PRIVATE_KEY" | base64 --decode) # file path of the private key as second argument + + now=$(date +%s) + iat=$((now - 60)) # Issues 60 seconds in the past + exp=$((now + 600)) # Expires 10 minutes in the future + + #b64enc() { tr -d '\n' | tr -d '\r' | base64 | tr '+/' '-_' | tr -d '='; } + b64enc() { openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n'; } + + header_json='{ + "typ":"JWT", + "alg":"RS256" + }' + # Header encode + header=$( echo -n "${header_json}" | b64enc ) + + payload_json='{ + "iat":'"${iat}"', + "exp":'"${exp}"', + "iss":"'"${client_id}"'" + }' + # Payload encode + payload=$( echo -n "${payload_json}" | b64enc ) + + # Signature + header_payload="${header}"."${payload}" + signature=$( + openssl dgst -sha256 -sign <(echo -n "${pem}") \ + <(echo -n "${header_payload}") | b64enc + ) + + # Create JWT + JWT="${header_payload}"."${signature}" + + #printf "%s\n" "$JWT" +} + + secretUri=$(curl -sS "http://metadata.google.internal/computeMetadata/v1/instance/attributes/secret-id" -H "Metadata-Flavor: Google") #secrets URI is of the form projects/$PROJECT_NUMBER/secrets/$SECRET_NAME/versions/$SECRET_VERSION #split into array based on `/` delimeter @@ -37,5 +83,21 @@ else # Remove action runner from the repo POST_URL="https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/actions/runners/remove-token" fi + +#only execute when client_id and private_key are not empty +#use as check to see if we want to use github app for authentication +#because we are overwriting the GITHUB_TOKEN variable +if [[ -n $GHA_CLIENT_ID ]] && [[ -n $GHA_PRIVATE_KEY ]]; then + generate_gha_jwt + + #Get access token + #Docs: https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-an-installation-access-token-for-a-github-app + GITHUB_TOKEN=$(curl --request POST \ + --url "https://api.github.com/app/installations/${GHA_INSTALLATION_ID}/access_tokens" \ + --header "Accept: application/vnd.github+json" \ + --header "Authorization: Bearer ${JWT}" \ + --header "X-GitHub-Api-Version: 2022-11-28" | jq -r .token) +fi + #remove the runner configuration RUNNER_ALLOW_RUNASROOT=1 /runner/config.sh remove --unattended --token "$(curl -sS --request POST --url "$POST_URL" --header "authorization: Bearer ${GITHUB_TOKEN}" --header "content-type: application/json" | jq -r .token)" From efec967eb963970f6e7df2f70eba87cf68cfe0a2 Mon Sep 17 00:00:00 2001 From: Alexander Jelinek Date: Mon, 5 Aug 2024 07:44:40 +0200 Subject: [PATCH 7/9] add gh_runner_group variable --- modules/gh-runner-mig-vm/main.tf | 13 ++++++------- modules/gh-runner-mig-vm/variables.tf | 6 ++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/modules/gh-runner-mig-vm/main.tf b/modules/gh-runner-mig-vm/main.tf index 2d96576..ffefe67 100644 --- a/modules/gh-runner-mig-vm/main.tf +++ b/modules/gh-runner-mig-vm/main.tf @@ -158,13 +158,12 @@ module "mig_template" { Runner MIG *****************************************/ module "mig" { - source = "terraform-google-modules/vm/google//modules/mig" - version = "~> 11.0" - project_id = var.project_id - subnetwork_project = var.project_id - hostname = local.instance_name - region = var.region - instance_template = module.mig_template.self_link + source = "terraform-google-modules/vm/google//modules/mig" + version = "~> 11.0" + project_id = var.project_id + hostname = local.instance_name + region = var.region + instance_template = module.mig_template.self_link /* autoscaler */ autoscaling_enabled = true diff --git a/modules/gh-runner-mig-vm/variables.tf b/modules/gh-runner-mig-vm/variables.tf index b49545c..1f30126 100644 --- a/modules/gh-runner-mig-vm/variables.tf +++ b/modules/gh-runner-mig-vm/variables.tf @@ -83,6 +83,12 @@ variable "gh_runner_labels" { default = [] } +variable "gh_runner_group" { + type = string + description = "GitHub runner group to attach to the runners. Docs: https://docs.github.com/en/actions/hosting-your-own-runners/adding-self-hosted-runners#adding-more-self-hosted-runners" + default = "" +} + variable "min_replicas" { type = number description = "Minimum number of runner instances" From a4d15ac851085aec2cc5324142374eac84261b14 Mon Sep 17 00:00:00 2001 From: Alexander Jelinek Date: Mon, 5 Aug 2024 07:59:07 +0200 Subject: [PATCH 8/9] add scripts with runnergroup parameters --- modules/gh-runner-mig-vm/scripts/shutdown.sh | 2 +- modules/gh-runner-mig-vm/scripts/startup.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/gh-runner-mig-vm/scripts/shutdown.sh b/modules/gh-runner-mig-vm/scripts/shutdown.sh index aefe1bb..2a5c184 100644 --- a/modules/gh-runner-mig-vm/scripts/shutdown.sh +++ b/modules/gh-runner-mig-vm/scripts/shutdown.sh @@ -100,4 +100,4 @@ if [[ -n $GHA_CLIENT_ID ]] && [[ -n $GHA_PRIVATE_KEY ]]; then fi #remove the runner configuration -RUNNER_ALLOW_RUNASROOT=1 /runner/config.sh remove --unattended --token "$(curl -sS --request POST --url "$POST_URL" --header "authorization: Bearer ${GITHUB_TOKEN}" --header "content-type: application/json" | jq -r .token)" +RUNNER_ALLOW_RUNASROOT=1 /runner/config.sh remove --unattended --token "$(curl -sS --request POST --url "$POST_URL" --header "authorization: Bearer ${GITHUB_TOKEN}" --header "content-type: application/json" | jq -r .token)" --runnergroup "${RUNNER_GROUP}" diff --git a/modules/gh-runner-mig-vm/scripts/startup.sh b/modules/gh-runner-mig-vm/scripts/startup.sh index f094fde..d99dd71 100644 --- a/modules/gh-runner-mig-vm/scripts/startup.sh +++ b/modules/gh-runner-mig-vm/scripts/startup.sh @@ -117,7 +117,7 @@ fi # Register runner ACTIONS_RUNNER_INPUT_TOKEN="$(curl -sS --request POST --url "$POST_URL" --header "authorization: Bearer ${GITHUB_TOKEN}" --header 'content-type: application/json' | jq -r .token)" #configure runner -RUNNER_ALLOW_RUNASROOT=1 /runner/config.sh --unattended --replace --work "/runner-tmp" --url "$GH_URL" --token "$ACTIONS_RUNNER_INPUT_TOKEN" --labels "$LABELS" +RUNNER_ALLOW_RUNASROOT=1 /runner/config.sh --unattended --replace --work "/runner-tmp" --url "$GH_URL" --token "$ACTIONS_RUNNER_INPUT_TOKEN" --labels "$LABELS" --runnergroup "${RUNNER_GROUP}" #install and start runner service cd /runner || exit From bedd2964fd25f29a7acdac2bee8794e96417e6b7 Mon Sep 17 00:00:00 2001 From: Alexander Jelinek Date: Tue, 6 Aug 2024 10:22:47 +0200 Subject: [PATCH 9/9] update instance_template module to v11 to avoid destroying because of total_egress_bandwidth_tier --- modules/gh-runner-mig-vm/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gh-runner-mig-vm/main.tf b/modules/gh-runner-mig-vm/main.tf index ffefe67..d7868d6 100644 --- a/modules/gh-runner-mig-vm/main.tf +++ b/modules/gh-runner-mig-vm/main.tf @@ -124,7 +124,7 @@ locals { module "mig_template" { source = "terraform-google-modules/vm/google//modules/instance_template" - version = "~> 7.0" + version = "~> 11.0" project_id = var.project_id machine_type = var.machine_type network = local.network_name