Terraform and GitHub
Find out how we use Terraform to manage our GitHub organisation, control users and teams and create repositories.
Introduction
As part of our ongoing mission to minimise ClickOps (it’s a thing!) we recently decided to use Terraform to manage our GitHub organisation. While, in theory, this is a relatively simple process there was always the risk of destroying all our repositories and losing months of hard work. This meant we had to ensure the configuration was spot on before we applied any changes.
Our goal
Our goal was to create something that allowed us to easily manage users, teams and repositories in a concise way allowing anyone to make changes within minutes. We also wanted to ensure branch protection was consistently applied across all our repositories including any that are created in the future.
We had already made the decision to use Terraform and I was given the task of writing the configuration as my first official Terraform project.
What is Terraform?
Terraform is an infrastructure as code (IaC) tool that lets you define both cloud and on-prem resources in human-readable configuration files that you can version, reuse, and share. You can then use a consistent workflow to provision and manage all of your infrastructure throughout its lifecycle. Terraform can manage low-level components like compute, storage, and networking resources, as well as high-level components like DNS entries and SaaS features.
Writing the configuration
In order to keep things as simple as possible we broke down the configuration files into multiple smaller modules. One for users, one for teams and one for repositories.
The modules themselves define which resources we want to create. Using the “repo” module as an example we can see that we want to create a GitHub Repository and apply branch protection to it.
resource "github_repository" "repo" {
name = var.name
description = var.description
visibility = var.private ? "private" : "public"
has_issues = true
has_projects = false
has_wiki = false
is_template = false
auto_init = true
lifecycle {
ignore_changes = [pages, auto_init]
}
archived = var.archived
allow_auto_merge = false
delete_branch_on_merge = false
vulnerability_alerts = !var.private
}
resource "github_branch_protection" "protect_main" {
repository_id = github_repository.repo.node_id
pattern = "main"
enforce_admins = true
allows_deletions = false
require_signed_commits = true
required_linear_history = false
require_conversation_resolution = true
push_restrictions = []
required_pull_request_reviews {
dismiss_stale_reviews = true
required_approving_review_count = var.reviewers_count
dismissal_restrictions = []
pull_request_bypassers = []
}
allows_force_pushes = false
}
In order to create a new repository we pass through a module similar to the one below. If we need to remove a repository we can simply delete the module and Terraform will recognise the change and remove the repository without impacting anything else.
module "module_name" {
reviewers_count = 1
source = "./repo"
name = "repo_name"
team = "team_name"
description = " "
}
Instead of relying on a human to click around in GitHub’s web interface (ClickOps), we rely on Terraform to build, change, and manage our organisation in a safe, consistent, and repeatable way.
Whether you are managing a massive enterprise with hundreds of GitHub users or implementing a consistent labeling scheme across your personal projects, Terraform is the right tool for the job.