Skip to content

Migrate Terraform to use Github App #19

Merged
merged 24 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions .github/workflows/terraform_plan.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:
runs-on: [ "229685449397" ]

env:
# GITHUB_APP_ID: ${{ vars.GH_APP_ID }}
# GITHUB_APP_INSTALLATION_ID: ${{ vars.GH_APP_INSTALLATION_ID }}
# GITHUB_APP_PEM_FILE: ${{ secrets.GH_APP_PEM_FILE }}
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
# GITHUB_APP_ID: ${{ vars.GH_APP_ID }}
GITHUB_APP_INSTALLATION_ID: ${{ vars.GH_APP_INSTALLATION_ID }}
GITHUB_APP_PEM_FILE: ${{ secrets.GH_APP_PEM_FILE }}
# GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
GITHUB_OWNER: CSVD
GITHUB_BASE_URL: https://github.e.it.census.gov/
TF_WORKSPACE: ${{ vars.terraform_workspace }}
Expand Down Expand Up @@ -48,7 +48,12 @@ jobs:
echo AWS_SECRET_ACCESS_KEY=`jq -r '.SecretAccessKey' aws_credentials.json` >> $GITHUB_ENV
aws configure set aws_session_token `jq -r '.Token' aws_credentials.json`
echo AWS_SESSION_TOKEN=`jq -r '.Token' aws_credentials.json` >> $GITHUB_ENV
- name: Setup GITHUB Credentials
id: github_credentials
run: |
echo GITHUB_TOKEN=$(python encode_jwt.py "$GITHUB_APP_PEM_FILE" "$GITHUB_APP_INSTALLATION_ID" "$GITHUB_BASE_URL") >> $GITHUB_ENV
- name: Terraform Init
id: init
run: /opt/tfenv/bin/terraform init -upgrade
Expand Down
2 changes: 0 additions & 2 deletions data.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
data "aws_region" "current" {}

data "github_organization_teams" "teams" {}
80 changes: 80 additions & 0 deletions encode_jwt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
## Run this script set the private key as github_app_private_key and installation_id as the installation id of the app

#export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt
#export github_app_private_key="-----BEGIN"
#export github_app_installation_id=11
#export github_app_url=https://github.e.it.census.gov
#export GITHUB_TOKEN=$(python encode_jwt.py "$github_app_private_key" "$github_app_installation_id" "$github_app_url")

import time
import json
import base64
import argparse
import requests
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.serialization import load_pem_private_key
import sys

# Set up argument parser
parser = argparse.ArgumentParser(description='Encode JWT with RS256 and get GitHub Enterprise installation access token')
parser.add_argument('private_key', type=str, help='PEM formatted private key string')
parser.add_argument('installation_id', type=str, help='GitHub App Installation ID')
parser.add_argument('enterprise_url', type=str, help='GitHub Enterprise API URL (e.g., https://github.e.it.census.gov)')
args = parser.parse_args()

# Load the PEM private key
private_key = load_pem_private_key(args.private_key.encode(), password=None)

# JWT Header
header = {
"alg": "RS256",
"typ": "JWT"
}

# JWT Payload
payload = {
"iat": int(time.time()),
"exp": int(time.time()) + (10 * 60),
"iss": "6" # Replace with your actual GitHub App ID
}

# Encode Header and Payload as Base64
header_encoded = base64.urlsafe_b64encode(json.dumps(header).encode()).decode().rstrip("=")
payload_encoded = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip("=")

# Create the message (header + payload)
message = f"{header_encoded}.{payload_encoded}".encode()

# Sign the message using RS256
signature = private_key.sign(
message,
padding.PKCS1v15(),
hashes.SHA256()
)

# Encode the signature in Base64
signature_encoded = base64.urlsafe_b64encode(signature).decode().rstrip("=")

# Construct the full JWT
jwt_token = f"{header_encoded}.{payload_encoded}.{signature_encoded}"

# Prepare the request to get the installation access token
headers = {
"Authorization": f"Bearer {jwt_token}",
"Accept": "application/vnd.github+json"
}

# Make the request to the GitHub Enterprise API to get the installation access token
url = f"{args.enterprise_url}api/v3/app/installations/{args.installation_id}/access_tokens"
response = requests.post(url, headers=headers)

# Check if the request was successful
if response.status_code == 201:
installation_access_token = response.json().get('token')
print(installation_access_token) # Output the token only
else:
# Raise an error with a message
sys.stderr.write(f"Error: Failed to get installation access token. Status code: {response.status_code}\n")
sys.stderr.write(f"{response.text}\n")
sys.exit(1) # Exit with an error code
6 changes: 3 additions & 3 deletions image-pipeline.tf
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ module "asset_releases" {
github_repo_description = "Terraform Workspace for publishing image-pipeline-assets"
repo_org = "CSVD"
name = "image-pipeline-asset-releases"
github_org_teams = local.github_organization_teams
github_org_teams = local.github_organization_teams
github_repo_topics = [
"terraform"
]
Expand All @@ -68,7 +68,7 @@ module "aws_image_pipeline" {
github_repo_description = "Terraform Workspace for creating and managing AWS Image Pipelines"
repo_org = "CSVD"
name = "aws-image-pipeline"
github_org_teams = local.github_organization_teams
github_org_teams = local.github_organization_teams
github_repo_topics = [
"terraform"
]
Expand Down Expand Up @@ -112,7 +112,7 @@ module "terraform_aws_image_pipeline" {
github_repo_description = "Terraform Module that creates codepipeline and codebuild jobs and other resources for building and deploying images"
repo_org = "CSVD"
name = "terraform-aws-image-pipeline"
github_org_teams = local.github_organization_teams
github_org_teams = local.github_organization_teams
github_repo_topics = [
"terraform"
]
Expand Down
8 changes: 4 additions & 4 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ module "elastic_beanstalk" {
enforce_prs = false
collaborators = local.collaborators
pull_request_bypassers = local.pull_request_bypassers
github_org_teams = local.github_organization_teams
github_org_teams = local.github_organization_teams
}


Expand Down Expand Up @@ -273,7 +273,7 @@ module "setup_terraform" {
create_codeowners = false
enforce_prs = false
collaborators = local.collaborators
github_org_teams = local.github_organization_teams
github_org_teams = local.github_organization_teams
}

module "setup_node" {
Expand All @@ -289,7 +289,7 @@ module "setup_node" {
create_codeowners = false
enforce_prs = false
collaborators = local.collaborators
github_org_teams = local.github_organization_teams
github_org_teams = local.github_organization_teams
}

# ghe-runner
Expand All @@ -306,7 +306,7 @@ module "ghe_runners" {
create_codeowners = false
enforce_prs = false
collaborators = local.collaborators
github_org_teams = local.github_organization_teams
github_org_teams = local.github_organization_teams
}

module "vpc_services" {
Expand Down
2 changes: 1 addition & 1 deletion morpheus.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module "morpheus_repos" {
source = "HappyPathway/repo/github"
#github_codeowners_team = "CSVD"
github_repo_description = "Repo for morpheus cloud"
github_org_teams = local.github_organization_teams
github_org_teams = local.github_organization_teams
repo_org = "CSVD"
name = each.value
github_repo_topics = [
Expand Down
18 changes: 18 additions & 0 deletions repolist.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module "repo_list" {
source = "HappyPathway/repo/github"
for_each = tomap({ for repo in var.repolist : repo.name => repo })
#github_codeowners_team = "CSVD"
github_repo_description = each.value.description
repo_org = each.value.repo_org
name = each.value.name
github_repo_topics = [
"terraform"
]
is_template = each.value.is_template
force_name = true
create_codeowners = false
enforce_prs = each.value.enforce_prs
collaborators = local.collaborators
pull_request_bypassers = local.pull_request_bypassers
github_org_teams = local.github_organization_teams
}
2 changes: 1 addition & 1 deletion sandbox.tf
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module "sandbox" {
create_codeowners = false
enforce_prs = false
collaborators = { "arnol377" : "admin" }
github_org_teams = local.github_organization_teams
github_org_teams = local.github_organization_teams
managed_extra_files = [
{
path = ".github/workflows/terraform-plan.yaml"
Expand Down
Empty file removed varfiles/default
Empty file.
14 changes: 14 additions & 0 deletions varfiles/default.tfvars
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
image_pipeline_workflows = {
"image-pipeline-goss-testing" = "./workflows/goss-testing.yaml"
}

repolist = [
{
description = "Managing AWS CSVD Secrets"
repo_org = "CSVD"
name = "aws-secrets"
},
{
description = "Tools for managing Terraform"
repo_org = "CSVD"
name = "tf-tools"
}
]

12 changes: 12 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
variable "image_pipeline_workflows" {
type = map(string)
}

variable "repolist" {
type = list(object({
description = string
repo_org = string
name = string
is_template = optional(bool, false)
create_codeowners = optional(bool, false)
enforce_prs = optional(bool, false)
}))
default = []
}
2 changes: 1 addition & 1 deletion versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ terraform {
required_providers {
random = {
source = "integrations/github"
version = ">= 6.2.2"
version = ">= 6.3.0"
}
aws = {
source = "hashicorp/aws"
Expand Down