How can I use Terraform to manage my GitHub repositories?
This article is highly inspired and overlaps with "Using Terraform to Manage Git Repositories" by Chris Wahl. You can also read the original (opens in a new tab) text.
Motivation
I want to learn and share my vision of working with Infrastructure as Code tooling like Terraform. Having my repositories managed in this manner is a good outcome.
Prerequisites
Before you start, you need
- GitHub account,
- a GitHub repository,
- Terraform CLI.
Structure of the repository
At the moment of writing, I already had a repository for all my personal development: this blog, my previous attempts to configure my private GitHub with Terraform, etc.
I tried to structure and figure out the way I should structure my management repository.
After several iterations, I realised that the most convenient for me layout should look like this:
.
├── README.MD
└── infrastructure
└── terraform
The infrastructure
folder has all the required
and necessary code to manage my personal
infrastructure: integration with Cloud Providers,
management of my version control, etc.
terraform
is a tool-specific subfolder for
infrastructure. I might want to test Pulumi
or other IaC tooling in the future.
This project structure allows me to try
it flexibly.
If you want to follow the suggested structure, then run in the root of your repository:
mkdir -p infrastructure/terraform
Creating a boilerplate for our Terraform code
To configure Terraform to work with GitHub, we need to:
- configure Terraform backend,
- configure GitHub Terraform provider.
Configure Terraform backend and Terraform version
For simplicity, I started with the
local
(opens in a new tab) backend.
It has its own downsides, but I can improve
it later.
Create backend.tf
file in infrastructure/terraform
folder with
the following content:
terraform {
backend "local" {}
}
To configure preferred Terraform version I created versions.tf
terraform {
required_version = ">= 1.0"
}
Configure Terraform providers
We need to configure GitHub Integration (opens in a new tab) Terraform provider.
First, let's add the provider. To do this,
change the content of versions.tf
to:
terraform {
required_version = ">= 1.0"
required_providers {
github = {
source = "integrations/github"
version = "~> 5.9"
}
}
}
GitHub Integration Terraform provider also requires authentication (opens in a new tab). In this article, I am going to use token based authentication.
Create a file providers.tf
and put these lines of code there
provider "github" {
owner = "<change-me-name-of-github-profile>"
token = var.github_oauth_token
}
Instead of <change-me-name-of-github-profile>
put your GitHub profile user name. In my case
it is nikitabarskov
.
As you can see, I use Terraform variables (opens in a new tab)
to cofigure provider. Before I used to configure
them in a separate file variables.tf
.
variable "github_oauth_token" {
type = string
sensitive = true
}
Run Terraform
Run a command
terraform init
and then
terraform plan
and you should be able to see the expected output:
var.github_oauth_token
Enter a value:
You need to submit a PAT for GitHub. You can follow
the instruction "Creating a personal access token" (opens in a new tab)
from GitHub. I will just list a set of permission
I used, when I was creating one: admin:gpg_key
,
admin:org
, admin:public_key
, admin:repo_hook
,
admin:ssh_signing_key
, delete_repo
, repo
, user
.
Once you created a PAT, run terraform plan
again, and submit the PAT as an input.
Great job!
Import the repository
Let's bring your empty repository you are working on now to Terraform.
In my case, I have a repository dev
with some ClickOps changes I made before.
First, I am trying to structure the things I am doing. There are several ways how you can structure your Terraform code.
For me, the most suitable one is to keep all Cloud resources related to the actual resource I am using together.
In the case of GitHub repositories, I use
a file called github_repositories.tf
.
So, to import the repository to Terraform, I make this list of actions:
-
I put these lines in
github_repositories.tf
resource "github_repository" "dev" { name = "dev" }
-
I import
dev
repository to Terraform stateterraform import github_repository.dev dev
It will ask you to submit your GitHub PAT again. The successfull output of
terraform import
command should look like thatgithub_repository.dev: Importing from ID "dev"... github_repository.dev: Import prepared! Prepared github_repository for import github_repository.dev: Refreshing state... [id=dev] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
-
I run
terraform plan
again to see the differences between the actual configuration and the configuration I described in my Terraform code.terraform plan
And the output for me looks like
github_repository.dev: Refreshing state... [id=dev] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: ~ update in-place Terraform will perform the following actions: # github_repository.dev will be updated in-place ~ resource "github_repository" "dev" { ~ allow_auto_merge = true -> false ~ allow_merge_commit = false -> true ~ delete_branch_on_merge = true -> false id = "dev" name = "dev" ~ topics = [ - "github", - "infrastructure", - "terraform", ] - vulnerability_alerts = true -> null # (26 unchanged attributes hidden) } Plan: 0 to add, 1 to change, 0 to destroy.
-
I fix my Terraform code to aligh with the actual configuration
resource "github_repository" "dev" { name = "dev" allow_auto_merge = true allow_merge_commit = false allow_rebase_merge = true delete_branch_on_merge = true topics = [ "github", "infrastructure", "terraform", ] vulnerability_alerts = true }
-
Run
terraform plan
again and paste your PAT again. The output should be close to the example below.github_repository.dev: Refreshing state... [id=dev] No changes. Your infrastructure matches the configuration. Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
-
Optionally: run
terraform apply
and check the output.Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed. Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
-
Commit your changes and push them to GitHub!
Conclusion
Managing infrastructure with Terraform is not hard at all, and even you can use it for your personal projects.
I learned how to use Terraform with GitHub and how to structure Terraform code.
In the following articles, I will describe the usage of Terraform Cloud and how to configure CI for your Terraform code.
Happy Terraforming!
Links
The changes you can find in my PR: nikitbarskov/dev#217 (opens in a new tab).