Terraform module registry

Introduced in GitLab 14.0.

Publish Terraform modules in your project’s Infrastructure Registry, then reference them using GitLab as a Terraform module registry.

Authenticate to the Terraform module registry

To authenticate to the Terraform module registry, you need either:

Publish a Terraform Module

When you publish a Terraform Module, if it does not exist, it is created.

Prerequisites:

PUT /projects/:id/packages/terraform/modules/:module-name/:module-system/:module-version/file
Attribute Type Required Description
id integer/string yes The ID or URL-encoded path of the project.
module-name string yes The package name. Supported syntax: One to 64 ASCII characters, including lowercase letters (a-z) and digits (0-9). The package name can’t exceed 64 characters.
module-system string yes The package system. Supported syntax: One to 64 ASCII characters, including lowercase letters (a-z) and digits (0-9). The package system can’t exceed 64 characters. More information can be found in the Terraform Module Registry Protocol documentation.
module-version string yes The package version. It must be valid according to the Semantic Versioning Specification.

Provide the file content in the request body.

As the following example shows, requests must end with /file. If you send a request ending with something else, it results in a 404 error {"error":"404 Not Found"}.

Example request using a personal access token:

curl --fail-with-body --header "PRIVATE-TOKEN: <your_access_token>" \
     --upload-file path/to/file.tgz \
     "https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/terraform/modules/my-module/my-system/0.0.1/file"

Example response:

{
  "message":"201 Created"
}

Example request using a deploy token:

curl --fail-with-body --header "DEPLOY-TOKEN: <deploy_token>" \
     --upload-file path/to/file.tgz \
     "https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/terraform/modules/my-module/my-system/0.0.1/file"

Example response:

{
  "message":"201 Created"
}

Reference a Terraform Module

Prerequisites:

  • You need to authenticate with the API. If authenticating with a personal access token, it must be configured with the read_api scope.

Authentication tokens (Job Token or Personal Access Token) can be provided for terraform in your ~/.terraformrc file:

credentials "gitlab.com" {
  token = "<TOKEN>"
}

Where gitlab.com can be replaced with the hostname of your self-managed GitLab instance.

You can then refer to your Terraform Module from a downstream Terraform project:

module "<module>" {
  source = "gitlab.com/<namespace>/<module-name>/<module-system>"
}

Where <namespace> is the namespace of the Terraform module registry.

Publish a Terraform module by using CI/CD

CI/CD template introduced in GitLab 15.9.

You can use the Terraform-Module.gitlab-ci.yml or the advanced Terraform/Module-Base.gitlab-ci.yml CI/CD template to publish a Terraform module to the GitLab Terraform Registry:

include:
  template: Terraform-Module.gitlab-ci.yml

The pipeline contains the following jobs:

  • fmt - Validate the formatting of the Terraform module.
  • kics-iac-sast - Test the Terraform module for security issues.
  • deploy - For tag pipelines only. Deploy the Terraform module to the GitLab Terraform Registry.

Pipeline variables

You can configure the pipeline with the following variables:

Variable Default Description
TERRAFORM_MODULE_DIR ${CI_PROJECT_DIR} The relative path to the root directory of the Terraform project.
TERRAFORM_MODULE_NAME ${CI_PROJECT_NAME} The name of your Terraform module. Must not contain any spaces or underscores.
TERRAFORM_MODULE_SYSTEM local The system or provider of your Terraform module targets. For example, local, aws, google.
TERRAFORM_MODULE_VERSION ${CI_COMMIT_TAG} The Terraform module version. You should follow the semantic versioning specification.

Deploy manually via CI/CD

To work with Terraform modules in GitLab CI/CD, you can use CI_JOB_TOKEN in place of the personal access token in your commands.

For example, this job uploads a new module for the local system provider and uses the module version from the Git commit tag:

stages:
  - deploy

upload:
  stage: deploy
  image: curlimages/curl:latest
  variables:
    TERRAFORM_MODULE_DIR: ${CI_PROJECT_DIR}    # The relative path to the root directory of the Terraform project.
    TERRAFORM_MODULE_NAME: ${CI_PROJECT_NAME}  # The name of your Terraform module, must not have any spaces or underscores (will be translated to hyphens).
    TERRAFORM_MODULE_SYSTEM: local             # The system or provider your Terraform module targets (ex. local, aws, google).
    TERRAFORM_MODULE_VERSION: ${CI_COMMIT_TAG} # The version - it's recommended to follow SemVer for Terraform Module Versioning.
  script:
    - TERRAFORM_MODULE_NAME=$(echo "${TERRAFORM_MODULE_NAME}" | tr " _" -) # module-name must not have spaces or underscores, so translate them to hyphens
    - tar -vczf /tmp/${TERRAFORM_MODULE_NAME}-${TERRAFORM_MODULE_SYSTEM}-${TERRAFORM_MODULE_VERSION}.tgz -C ${TERRAFORM_MODULE_DIR} --exclude=./.git .
    - 'curl --fail-with-body --location --header "JOB-TOKEN: ${CI_JOB_TOKEN}"
         --upload-file /tmp/${TERRAFORM_MODULE_NAME}-${TERRAFORM_MODULE_SYSTEM}-${TERRAFORM_MODULE_VERSION}.tgz
         ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/terraform/modules/${TERRAFORM_MODULE_NAME}/${TERRAFORM_MODULE_SYSTEM}/${TERRAFORM_MODULE_VERSION}/file'
  rules:
    - if: $CI_COMMIT_TAG

To trigger this upload job, add a Git tag to your commit. Ensure the tag follows the Semantic Versioning Specification that Terraform requires. The rules:if: $CI_COMMIT_TAG ensures that only tagged commits to your repository trigger the module upload job. For other ways to control jobs in your CI/CD pipeline, refer to the .gitlab-ci.yml keyword reference.

Example projects

For examples of the Terraform module registry, check the projects below:

Troubleshooting

  • Publishing a module with a duplicate name results in a {"message":"Access Denied"} error. There’s an ongoing discussion about allowing duplicate module names in this issue.