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
AttributeTypeRequiredDescription
idinteger/stringyesThe ID or URL-encoded path of the project.
module-namestringyesThe 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-systemstringyesThe 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-versionstringyesThe 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:

VariableDefaultDescription
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_SYSTEMlocalThe 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.