Cloud Consultant | AWS & Azure | DevOps |Infrastructure Automation with Ansible & Jenkins | Docker & Kubernetes Enthusiast| Passionate about Scalable & Secure Cloud Solutions

Blog-1
Introduction

Dynamically register a GitHub Actions self-hosted runner using Terraform and a shell script. This approach ensures that sensitive tokens are never hardcoded and that runners are registered securely and automatically using the GitHub API.

Learning Objectives

  • Why dynamic runner registration is important
  • How to securely generate and use a GitHub API token
  • Project structure overview
  • Terraform configuration to trigger a shell script
  • Secure and automated runner registration using GitHub API

Why Dynamic Runner Token Fetching?

GitHub requires a registration token to register a self-hosted runner, which is valid for only 60 minutes. Hardcoding this token poses a security risk and is inefficient. Instead, we fetch it dynamically during deployment using GitHub’s REST API, ensuring security and flexibility.

Visual workflow

Blog-2
Blog-3

Step 1: Generate a GitHub Personal Access Token (PAT)

  • Go to GitHub > Settings > Developer settings > Personal access tokens
  • Click “Generate new token” (Classic or Fine-grained)
  • Required scopes:
    • repo
    • admin:repo_hook


This token will be used to authenticate API calls to GitHub. Keep it secret!

Step 2: Project Structure

  • main.tf
  • variables.tf
  • get-runner-token.sh

Step 3: Define Variables (variables.tf)

variable "github_repo" {
description = "GitHub repository (e.g., your-org/nodejs-app)"
type        = string
}
variable "github_pat" {
  description = "GitHub Personal Access Token"
  type        = string
  sensitive   = true
}

Step 4: Bash Script to Fetch Token and Use Token (get-runner-token.sh)

#!/bin/bash


REPO_OWNER="your-org"
REPO_NAME="your-repo"
GITHUB_PAT=$1  # Pass token securely as parameter
LABELS="ec2-runner"
RUNNER_NAME="ec2-runner-$(hostname)"


sudo apt update && sudo apt install -y jq curl


REG_TOKEN=$(curl -s -X POST \
  -H "Authorization: token $GITHUB_PAT" \
  https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/actions/runners/registration-token \
  | jq .token --raw-output)


mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64.tar.gz -L https://github.com/actions/runner/releases/latest/download/actions-runner-linux-x64.tar.gz
tar xzf actions-runner-linux-x64.tar.gz


./config.sh --url https://github.com/$REPO_OWNER/$REPO_NAME \
            --token $REG_TOKEN \
            --name $RUNNER_NAME \
            --labels $LABELS \
            --unattended


sudo ./svc.sh install
sudo ./svc.sh start

Important : To provide the script execute permission:

chmod +x get-runner-token.sh

Step 5: Terraform Code (main.tf)

provider "azurerm" {
  features {}
}
provider "local" {}
resource "null_resource" "fetch_runner_token" {
  provisioner "local-exec" {
    command = "bash ./get-runner-token.sh ${var.github_pat} > token.txt"
  }
}
data "local_file" "runner_token" {
  depends_on = [null_resource.fetch_runner_token]
  filename   = "${path.module}/token.txt"
}
output "runner_token" {
  value     = data.local_file.runner_token.content
 sensitive = true
}
resource "azurerm_resource_group" "runner_rg" {
  name     = "runner-rg"
  location = "UAE North"
}
resource "azurerm_virtual_network" "vnet" {
  name                = "runner-vnet"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.runner_rg.location
  resource_group_name = azurerm_resource_group.runner_rg.name
  }