Infrastructure as Code (IaC) teams frequently encounter challenges when sharing Terraform modules across multiple projects and repositories. Organizations often resort to copying and pasting module code between repositories, creating maintenance overhead and version drift issues. This article examines strategies for establishing a centralized module management system similar to package management approaches used in application development.
The Module Sharing Challenge
In distributed repository architectures, teams commonly define reusable infrastructure components such as Route53 configurations, Web Application Firewalls (WAF), and Virtual Private Clouds (VPC) as Terraform modules. Without a formal sharing mechanism, these modules are often duplicated across repositories through manual copying, leading to several issues:
- Version drift: Different projects may use outdated or inconsistent versions of the same module
- Maintenance overhead: Bug fixes and improvements must be manually propagated across repositories
- Lack of discoverability: Teams may unknowingly recreate existing functionality
Solution Approaches
Private Terraform Registry
Terraform supports private module registries that function similarly to package managers in application development. This approach allows modules to be referenced with semantic versioning:
module "route53" {
source = "your-company.com/terraform/route53"
version = "~> 2.1.0"
domain_name = "example.com"
}
Private registries can be implemented through:
- Terraform Cloud or Terraform Enterprise
- Self-hosted solutions
- Git-based package registries provided by platforms like GitLab and GitHub
Git-Based Module Sourcing
Terraform natively supports referencing modules directly from Git repositories with version pinning through Git references:
module "route53" {
source = "git::https://git.company.com/org/terraform-modules.git//route53?ref=v2.1.0"
domain_name = "example.com"
}
This approach provides immediate value without requiring additional infrastructure setup. Teams can use Git tags for version management or reference specific branches for different deployment strategies.
Third-Party Dependency Management
Tools like Terragrunt extend Terraform’s dependency management capabilities, providing features such as dependency resolution and advanced configuration management.
Implementation Strategy: Phased Approach
A pragmatic implementation strategy involves starting with Git-based module sourcing and migrating to a private registry system. This approach provides immediate relief from copy-paste workflows while establishing a foundation for more sophisticated dependency management.
Phase 1: Git-Based Implementation
For organizations using trunk-based development, modules can reference the main branch directly:
module "route53" {
source = "git::https://git.company.com/org/terraform-modules.git//route53?ref=main"
domain_name = "example.com"
}
This configuration automatically retrieves the latest module version while maintaining the ability to pin to specific commits for production environments.
Phase 2: Registry Migration
GitLab provides built-in Terraform module registry functionality that integrates with existing Git workflows. Modules can be automatically published through CI/CD pipelines:
publish:
stage: publish
script:
- |
for module_dir in modules/*/; do
module_name=$(basename "$module_dir")
tar -czf ${module_name}-${CI_COMMIT_TAG}.tar.gz -C modules ${module_name}/
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" \
--upload-file ${module_name}-${CI_COMMIT_TAG}.tar.gz \
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/terraform/modules/${module_name}/${CI_COMMIT_TAG}/file"
done
only:
- tags
Centralized Module Repository Architecture
The optimal organizational structure involves maintaining a dedicated repository serving as a centralized module library:
terraform-modules/
├── modules/
│ ├── route53/
│ ├── waf/
│ ├── vpc/
│ └── rds/
├── examples/
├── .gitlab-ci.yml
└── README.md
This architecture provides several advantages:
- Single source of truth for all shared infrastructure components
- Centralized governance and code review processes
- Consistent versioning across the entire module ecosystem
- Enhanced discoverability through a unified module catalog
Module Consumption Patterns
Teams can consume modules using consistent patterns across different projects:
# Using registry approach
module "route53" {
source = "git.company.com/org/terraform-modules/route53"
version = "~> 1.2.0"
domain_name = var.domain_name
}
# Using Git approach
module "waf" {
source = "git::https://git.company.com/org/terraform-modules.git//modules/waf?ref=v1.3.0"
web_acl_name = var.application_name
}
Authentication and Access Control
Module registries typically integrate with existing authentication systems. GitLab’s implementation leverages project access controls and supports both personal access tokens and CI/CD job tokens for automated environments.
The phased implementation approach allows organizations to immediately address module sharing challenges while building toward a more sophisticated dependency management system. This strategy minimizes disruption to existing workflows while establishing patterns that scale across large development organizations.