Managing Terraform Modules in a Monorepo

Jul 17, 2023Terraform

Motivation

Our organization uses a Monorepo. Chances are, if you have found this article, you use a Monorepo as well.

While building out our cloud infrastructure modules in Terraform, we realized that we wanted to preserve our Monorepo, while at the same time build our modules with some best practices. Primarily, we were concerned about making modules that are: Accessible to developers within our organization for viewing and use, and have versioned releases so that we can test and then “promote” infrastructure across development and production environments.

Existing solutions we investigated did not meet both our mono-repo and module-versioning requirements:

  1. Using a remote module registry, like HashiCorp’s Terraform Registry. Placing modules in HashiCorp’s remote Terraform registry is great for versioning modules, and sharing them either publicly or privately with a private registry. Better yet, it is free! Unfortunately, a module hosted on a public or private registry must live within its own individual repository, thus breaking our Monorepo.
  2. Building modules within the Monorepo. This solution preserves the Monorepo structure, but we don’t have access to versioning. Modules are just defined and can be continuously updated. This leads to difficulties when wanting to confidently test a module update in dev without a change accidently making its way into prod. Without versioning, every module reference is always fully up to date, even when just testing out new changes.

New Approach — Versioning modules within our Monorepo

The key change was to build modules locally within our Monorepo, but on push to dev, create versioned releases of each module in S3. Then, when we want to actually test the module in dev, we can upgrade the module reference. Once satisfied with the latest module version, we promote it to higher environments (staging, production, etc.).

Implementation

Our infrastructure directory within our Monorepo looks as follows:

    We essentially define our modules within a single sub-directory. Then, using a small deployment script, upon merge to a major branch deploy the new module version to s3 using GitHub Actions.

    modules/config/versions.yml:

    module_deployment/main.py (Note how each module gets a sub directory in the defined s3 bucket):

    GitHub Action to deploy new module versions (essentially no more than calling the above defined python script within GitHub Actions):

    We now have multiple versioned modules defined and deployed from our Monorepo. In order to call our versioned module from within Terraform, we simply call:

    Possible Downsides

    • Discoverability is potentially limited: Discoverability with this approach comes down to your organizations ability to document well each module within your Monorepo, and key-word search with the repository.
    • Cross-account credentialing can quickly become an issue: If the S3 bucket containing your module .zip files is in one account, but infrastructure is being deployed to a different account, then the credentials that Terraform uses will require cross-account access.

    Conclusion

    Using a simple Python script in conjunction with a GitHub Action, we now can support an arbitrary number of versioned modules within our existing Monorepo.

    Have questions or see something that we missed? Let us know in the comments!

    dragondrop.cloud’s mission is to automate developer best practices while working with Infrastructure as Code. Our flagship OSS product, cloud-concierge, allows developers to codify their cloud, detect drift, estimate cloud costs and security risks, and more — while delivering the results via a Pull Request. For enterprises running cloud-concierge at scale, we provide a management platform. To learn more, schedule a demo or get started today!

    Learn More About Terraform

    Everything Everywhere All as Code

    “Everything as Code” Definition Everything as Code is a philosophy for managing IT infrastructure where all components of infrastructure are created, managed, and deleted using code. This applies to container definitions, cloud infrastructure, on-premise server...

    read more

    Open Source driftctl Alternatives

    What is driftctl? driftctl is an OSS CLI tool that enables users to identify Terraform drift as well as unmanaged resources within a cloud environment. It is a quite popular tool and has collected over two thousand stars on GitHub. Why Would We Want a Replacement?...

    read more

    Why We Are Not Supporting OpenTF

    Background On August 10, HashiCorp changed the license to their previously “Open Source” projects to a Business Source License (BSL), making them now “source available” for all future releases. We discusssed in detail reasons and motivations for this change here. On...

    read more