Skip to content

GurdipSCode/devops-terraform-services-github

Repository files navigation

devops-terraform-services-github

Terraform GitHub Lynx License Maintained

Manage GitHub repositories, teams, and settings as code using Terraform with Lynx backend for collaborative state management.

πŸ“‹ Table of Contents

🌟 Overview

This repository uses the GitHub Terraform Provider to manage GitHub resources declaratively. Perfect for organizations that want to:

  • Standardize repository configurations
  • Enforce security policies across all repos
  • Automate repository creation and setup
  • Manage team access and permissions at scale
  • Version control your GitHub organization settings

✨ Features

  • Repository Management: Create, configure, and manage GitHub repositories
  • Branch Protection: Enforce branch protection rules and required reviews
  • Team Management: Manage teams and repository access levels
  • Secret Management: Provision repository and organization secrets
  • Webhook Configuration: Automate webhook setup for CI/CD
  • Issue Labels: Standardize labels across repositories
  • Actions Settings: Configure GitHub Actions permissions and runners
  • Organization Settings: Manage organization-wide policies
  • Lynx State Backend: Collaborative state management with versioning and rollback

πŸ”§ Prerequisites

Required

  • Terraform >= 1.5.0
  • Lynx Backend - For state management
  • GitHub account with appropriate permissions:
    • Organization Owner (for org-level resources)
    • Admin access (for repository management)
  • GitHub Personal Access Token (PAT) or GitHub App
  • Lynx API credentials (API URL and API Key)

Required Token Scopes

For Classic PAT, enable these scopes:

  • repo (Full control of private repositories)
  • admin:org (Full control of orgs and teams)
  • delete_repo (Delete repositories)
  • admin:repo_hook (Full control of repository hooks)
  • workflow (Update GitHub Action workflows)

For Fine-grained PAT, grant:

  • Repository permissions: Administration (Read/Write)
  • Organization permissions: Administration (Read/Write), Members (Read/Write)

πŸš€ Quick Start

1. Clone the Repository

git clone https://github.com/yourusername/terraform-github-management.git
cd terraform-github-management

2. Set Environment Variables

# GitHub authentication
export GITHUB_TOKEN="ghp_your_personal_access_token"

# Or use GitHub App authentication
export GITHUB_APP_ID="your_app_id"
export GITHUB_APP_INSTALLATION_ID="your_installation_id"
export GITHUB_APP_PEM_FILE="path/to/app-private-key.pem"

# Lynx backend credentials
export LYNX_API_URL="https://lynx.company.com/api/v1"
export LYNX_API_KEY="your-lynx-api-key"

3. Configure Backend

Create or update backend.tf:

terraform {
  backend "http" {
    address        = "https://lynx.company.com/api/v1/terraform/state/github-management/production"
    lock_address   = "https://lynx.company.com/api/v1/terraform/lock/github-management/production"
    unlock_address = "https://lynx.company.com/api/v1/terraform/lock/github-management/production"
    lock_method    = "POST"
    unlock_method  = "DELETE"
    
    # Authentication via headers
    username = "api-key"
    password = var.lynx_api_key
  }
}

4. Configure Variables

Create terraform.tfvars:

github_organization = "your-org-name"
github_owner        = "your-username"

default_branch_protection = {
  require_code_owner_reviews       = true
  required_approving_review_count  = 2
  dismiss_stale_reviews            = true
  require_conversation_resolution  = true
}

5. Initialize and Apply

terraform init
terraform plan
terraform apply

πŸ“ Repository Structure

.
β”œβ”€β”€ modules/
β”‚   β”œβ”€β”€ repository/
β”‚   β”‚   β”œβ”€β”€ main.tf              # Repository resource
β”‚   β”‚   β”œβ”€β”€ variables.tf
β”‚   β”‚   β”œβ”€β”€ outputs.tf
β”‚   β”‚   └── README.md
β”‚   β”œβ”€β”€ team/
β”‚   β”‚   β”œβ”€β”€ main.tf              # Team management
β”‚   β”‚   β”œβ”€β”€ variables.tf
β”‚   β”‚   └── outputs.tf
β”‚   β”œβ”€β”€ branch-protection/
β”‚   β”‚   └── ...
β”‚   └── webhooks/
β”‚       └── ...
β”œβ”€β”€ environments/
β”‚   β”œβ”€β”€ organization/
β”‚   β”‚   β”œβ”€β”€ main.tf              # Org-wide settings
β”‚   β”‚   β”œβ”€β”€ repositories.tf      # All repositories
β”‚   β”‚   β”œβ”€β”€ teams.tf             # Team definitions
β”‚   β”‚   └── terraform.tfvars
β”‚   └── personal/
β”‚       └── ...
β”œβ”€β”€ templates/
β”‚   β”œβ”€β”€ repository/
β”‚   β”‚   β”œβ”€β”€ standard-repo.tf    # Template for new repos
β”‚   β”‚   └── microservice.tf     # Microservice template
β”‚   └── policies/
β”‚       └── branch-protection.tf
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ generate-repo.sh         # Helper script
β”‚   └── bulk-import.sh           # Import existing repos
β”œβ”€β”€ .gitignore
β”œβ”€β”€ backend.tf                   # Lynx backend configuration
β”œβ”€β”€ providers.tf
β”œβ”€β”€ variables.tf
β”œβ”€β”€ outputs.tf
└── README.md

βš™οΈ Complete Configuration Example

providers.tf

terraform {
  required_version = ">= 1.5.0"
  
  required_providers {
    github = {
      source  = "integrations/github"
      version = "~> 6.0"
    }
  }
}

provider "github" {
  token = var.github_token
  owner = var.github_organization
}

backend.tf

terraform {
  backend "http" {
    address        = "https://lynx.company.com/api/v1/terraform/state/platform/github-management/production"
    lock_address   = "https://lynx.company.com/api/v1/terraform/lock/platform/github-management/production"
    unlock_address = "https://lynx.company.com/api/v1/terraform/lock/platform/github-management/production"
    
    lock_method    = "POST"
    unlock_method  = "DELETE"
    
    username = "api-key"
    password = var.lynx_api_key
  }
}

variables.tf

variable "github_token" {
  description = "GitHub Personal Access Token"
  type        = string
  sensitive   = true
}

variable "lynx_api_key" {
  description = "Lynx API Key for backend authentication"
  type        = string
  sensitive   = true
}

variable "github_organization" {
  description = "GitHub organization name"
  type        = string
}

terraform.tfvars.example

# Copy to terraform.tfvars and fill in your values
github_organization = "your-org-name"

# Set via environment variables:
# export TF_VAR_github_token="ghp_..."
# export TF_VAR_lynx_api_key="..."

πŸ’» Usage

Create a New Repository

module "new_repository" {
  source = "./modules/repository"

  name        = "my-new-repo"
  description = "Repository description"
  visibility  = "private"
  
  has_issues      = true
  has_projects    = true
  has_wiki        = false
  has_downloads   = true
  
  auto_init          = true
  gitignore_template = "Python"
  license_template   = "mit"
  
  topics = ["python", "api", "microservice"]
  
  # Team access
  teams = {
    "developers" = "push"
    "admins"     = "admin"
  }
}

Configure Branch Protection

module "branch_protection" {
  source = "./modules/branch-protection"

  repository = "my-repo"
  branch     = "main"
  
  require_code_owner_reviews      = true
  required_approving_review_count = 2
  dismiss_stale_reviews           = true
  require_conversation_resolution = true
  
  require_signed_commits = true
  
  required_status_checks = {
    strict = true
    contexts = [
      "ci/test",
      "ci/lint",
      "security/scan"
    ]
  }
  
  restrictions = {
    users = ["admin-user"]
    teams = ["platform-team"]
  }
}

Manage Teams

module "engineering_team" {
  source = "./modules/team"

  name        = "engineering"
  description = "Engineering team"
  privacy     = "closed"
  
  members = {
    "user1" = "maintainer"
    "user2" = "member"
    "user3" = "member"
  }
  
  repositories = {
    "backend-api"     = "push"
    "frontend-app"    = "push"
    "infrastructure"  = "pull"
  }
}

Add Repository Secrets

resource "github_actions_secret" "api_key" {
  repository      = "my-repo"
  secret_name     = "API_KEY"
  plaintext_value = var.api_key
}

resource "github_actions_organization_secret" "shared_token" {
  secret_name     = "SHARED_TOKEN"
  visibility      = "all"
  plaintext_value = var.shared_token
}

πŸ“¦ Examples

Standard Application Repository

module "api_service" {
  source = "./modules/repository"

  name        = "payment-api"
  description = "Payment processing API service"
  visibility  = "private"
  
  # Repository settings
  has_issues    = true
  has_projects  = false
  has_wiki      = false
  auto_init     = true
  
  # Templates
  gitignore_template = "Node"
  license_template   = "apache-2.0"
  
  # Topics for discoverability
  topics = ["nodejs", "api", "payments", "microservice"]
  
  # Default branch
  default_branch = "main"
  
  # Enable vulnerability alerts
  vulnerability_alerts = true
  
  # Team permissions
  teams = {
    "backend-team"    = "push"
    "platform-team"   = "admin"
    "security-team"   = "pull"
  }
}

# Branch protection for main
resource "github_branch_protection" "api_main" {
  repository_id = module.api_service.repository_id
  pattern       = "main"
  
  required_pull_request_reviews {
    dismiss_stale_reviews           = true
    require_code_owner_reviews      = true
    required_approving_review_count = 2
    require_last_push_approval      = true
  }
  
  required_status_checks {
    strict = true
    contexts = [
      "ci/build",
      "ci/test", 
      "ci/lint",
      "security/sast"
    ]
  }
  
  enforce_admins = true
  require_signed_commits = true
  
  require_conversation_resolution = true
  
  push_restrictions = [
    "/platform-team"
  ]
}

Organization-Wide Settings

# Default labels for all repositories
resource "github_issue_label" "bug" {
  repository  = each.value
  for_each    = toset(var.all_repositories)
  
  name        = "bug"
  color       = "d73a4a"
  description = "Something isn't working"
}

# Organization settings
resource "github_organization_settings" "main" {
  billing_email = "billing@company.com"
  company       = "Your Company"
  blog          = "https://blog.company.com"
  email         = "github@company.com"
  
  has_organization_projects = true
  has_repository_projects   = true
  
  default_repository_permission = "read"
  members_can_create_repositories = false
  
  members_can_create_public_repositories  = false
  members_can_create_private_repositories = false
  
  web_commit_signoff_required = true
}

# Organization security settings
resource "github_organization_security_manager" "security_team" {
  team_slug = "security"
}

Webhook Configuration

resource "github_repository_webhook" "ci_webhook" {
  repository = "my-repo"

  configuration {
    url          = "https://ci.company.com/webhook"
    content_type = "json"
    insecure_ssl = false
    secret       = var.webhook_secret
  }

  active = true

  events = [
    "push",
    "pull_request",
    "release"
  ]
}

🎯 Modules

Repository Module

Creates and configures a GitHub repository with all settings.

Inputs:

  • name - Repository name
  • description - Repository description
  • visibility - public/private/internal
  • has_issues - Enable issues
  • has_wiki - Enable wiki
  • teams - Team access map

Outputs:

  • repository_id - Repository ID
  • full_name - Full repository name
  • html_url - Repository URL
  • ssh_clone_url - SSH clone URL

Team Module

Manages GitHub teams and their repository permissions.

Inputs:

  • name - Team name
  • description - Team description
  • privacy - secret/closed
  • members - Map of members and roles
  • repositories - Map of repos and permissions

Outputs:

  • team_id - Team ID
  • team_slug - Team slug
  • members_count - Number of members

Branch Protection Module

Configures branch protection rules.

Inputs:

  • repository - Repository name
  • branch - Branch pattern
  • require_code_owner_reviews - Require CODEOWNERS review
  • required_approving_review_count - Number of required reviews
  • required_status_checks - Status checks that must pass

Outputs:

  • protection_id - Protection rule ID

πŸ›‘οΈ Best Practices

Repository Naming

Use consistent naming conventions:

<team>-<project>-<type>
backend-api-service
frontend-web-app
infrastructure-terraform

Branch Protection

Always protect your main branch:

  • βœ… Require pull request reviews (minimum 2)
  • βœ… Require status checks to pass
  • βœ… Require conversation resolution
  • βœ… Require signed commits
  • βœ… Include administrators in restrictions

Team Management

Organize teams by function:

  • platform-team - Infrastructure and platform
  • backend-team - Backend services
  • frontend-team - Frontend applications
  • security-team - Security reviews
  • data-team - Data engineering

Secret Management

  • βœ… Use organization secrets for shared values
  • βœ… Use repository secrets for service-specific values
  • βœ… Never commit secrets to Terraform files
  • βœ… Use Terraform variables marked as sensitive
  • βœ… Store secrets in secure vault (HashiCorp Vault, AWS Secrets Manager)

State Management

Use Lynx backend for collaborative state management:

terraform {
  backend "http" {
    address        = "https://lynx.company.com/api/v1/terraform/state/platform/github-management/production"
    lock_address   = "https://lynx.company.com/api/v1/terraform/lock/platform/github-management/production"
    unlock_address = "https://lynx.company.com/api/v1/terraform/lock/platform/github-management/production"
    
    lock_method    = "POST"
    unlock_method  = "DELETE"
    
    username = "api-key"
    password = var.lynx_api_key
  }
}

Benefits of Lynx:

  • Team collaboration with RBAC
  • Built-in state locking
  • State versioning and rollback
  • Web-based dashboard
  • Snapshot support

Security Scanning

Enable security features for all repositories:

vulnerability_alerts             = true
security_and_analysis {
  secret_scanning {
    status = "enabled"
  }
  secret_scanning_push_protection {
    status = "enabled"
  }
}

πŸ”„ Import Existing Repositories

To import existing GitHub repositories into Terraform:

# Import repository
terraform import module.existing_repo.github_repository.main your-org/repo-name

# Import team
terraform import github_team.developers 1234567

# Import branch protection
terraform import github_branch_protection.main repo-name:main

Or use the bulk import script:

./scripts/bulk-import.sh your-org

πŸš€ Automation Examples

Bulk Repository Creation

locals {
  microservices = [
    "user-service",
    "payment-service",
    "notification-service",
    "analytics-service"
  ]
}

module "microservice_repos" {
  source   = "./modules/repository"
  for_each = toset(local.microservices)
  
  name        = each.value
  description = "${each.value} microservice"
  visibility  = "private"
  
  topics = ["microservice", "api", "nodejs"]
  
  # Standard configuration
  has_issues     = true
  has_wiki       = false
  auto_init      = true
  license_template = "mit"
  
  teams = {
    "backend-team" = "push"
    "platform-team" = "admin"
  }
}

Standard Labels Across All Repos

locals {
  standard_labels = {
    bug = {
      color       = "d73a4a"
      description = "Something isn't working"
    }
    enhancement = {
      color       = "a2eeef"
      description = "New feature or request"
    }
    documentation = {
      color       = "0075ca"
      description = "Improvements or additions to documentation"
    }
    security = {
      color       = "ee0701"
      description = "Security vulnerability or issue"
    }
  }
}

resource "github_issue_label" "standard" {
  for_each = {
    for pair in setproduct(var.all_repositories, keys(local.standard_labels)) :
    "${pair[0]}-${pair[1]}" => {
      repo  = pair[0]
      label = pair[1]
    }
  }
  
  repository  = each.value.repo
  name        = each.value.label
  color       = local.standard_labels[each.value.label].color
  description = local.standard_labels[each.value.label].description
}

πŸ“Š Outputs

After applying Terraform, you can view outputs:

# List all repositories
terraform output repositories

# Get specific repository URL
terraform output -json | jq '.repositories.value["my-repo"].html_url'

# List all teams
terraform output teams

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/new-template)
  3. Make your changes
  4. Test with terraform plan
  5. Commit your changes (git commit -am 'feat: add new repository template')
  6. Push to the branch (git push origin feature/new-template)
  7. Open a Pull Request

πŸ”’ Security

  • Never commit tokens to version control
  • Use environment variables for authentication (GitHub and Lynx)
  • Enable branch protection on this repository
  • Use Lynx encrypted state backend with access controls
  • Enable secret scanning on all repositories
  • Implement CODEOWNERS file for review requirements
  • Regular audit of team permissions
  • Lynx RBAC: Control who can access and modify state

πŸ“š Resources

GitHub

Lynx Backend

Terraform

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ‘₯ Maintainers

πŸ“ Changelog

See CHANGELOG.md for version history.


Manage GitHub at scale with Infrastructure as Code

Made with ❀️ by the Platform Team

About

Terraform services for GitHub

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published