Module Sources
The source
argument in a module
block
tells OpenTF where to find the source code for the desired child module.
OpenTF uses this during the module installation step of opentf init
to download the source code to a directory on local disk so that other OpenTF commands can use it.
The module installer supports installation from a number of different source types.
Each of these is described in the following sections. Module source addresses use a URL-like syntax, but with extensions to support unambiguous selection of sources and additional features.
We recommend using local file paths for closely-related modules used primarily for the purpose of factoring out repeated code elements, and using a native OpenTF module registry for modules intended to be shared by multiple calling configurations. We support other sources so that you can potentially distribute OpenTF modules internally with existing infrastructure.
Many of the source types will make use of "ambient" credentials available when OpenTF is run, such as from environment variables or credentials files in your home directory. This is covered in more detail in each of the following sections.
We recommend placing each module that is intended to be re-usable in the root of its own repository or archive file, but it is also possible to reference modules from subdirectories.
Local Paths
Local path references allow for factoring out portions of a configuration within a single source repository.
module "consul" {
source = "./consul"
}
A local path must begin with either ./
or ../
to indicate that a local
path is intended, to distinguish from
a module registry address.
Local paths are special in that they are not "installed" in the same sense that other sources are: the files are already present on local disk (possibly as a result of installing a parent module) and so can just be used directly. Their source code is automatically updated if the parent module is upgraded.
Note that OpenTF does not consider an absolute filesystem path (starting with a slash, a drive letter, or similar) to be a local path. Instead, OpenTF will treat that in a similar way as a remote module and copy it into the local module cache. An absolute path is a "package" in the sense described in Modules in Package Sub-directories. We don't recommend using absolute filesystem paths to refer to modules, because it will tend to couple your configuration to the filesystem layout of a particular computer.
Module Registry
A module registry is the native way of distributing modules for use across multiple configurations, using an OpenTF-specific protocol that has full support for module versioning.
The Public Terraform Registry is an index of modules shared publicly using this protocol. This public registry is the easiest way to get started with OpenTF and find modules created by others in the community.
You can also use a private registry, either via TACOS (TF Automation and Collaboration Software), or by running a custom service that implements the module registry protocol.
Modules on the public registry can be referenced using a registry
source address of the form <NAMESPACE>/<NAME>/<PROVIDER>
, with each
module's information page on the registry site including the exact address
to use.
module "consul" {
source = "hashicorp/consul/aws"
version = "0.1.0"
}
The above example will use the Consul module for AWS from a public registry.
For modules hosted in other registries, prefix the source address with an
additional <HOSTNAME>/
portion, giving the hostname of the private registry:
module "consul" {
source = "app.terraform.io/example-corp/k8s-cluster/azurerm"
version = "1.1.0"
}
Registry modules support versioning. You can provide a specific version as shown in the above examples, or use flexible version constraints.
You can learn more about the registry at the Module Registry documentation.
To access modules from a private registry, you may need to configure an access token in the CLI config. Use the same hostname as used in the module source string. For a private registry within TACOS (TF Automation and Collaboration Software), use the same authentication token as you would use with the API or command-line clients.
GitHub
OpenTF will recognize unprefixed github.com
URLs and interpret them
automatically as Git repository sources.
module "consul" {
source = "github.com/hashicorp/example"
}
The above address scheme will clone over HTTPS. To clone over SSH, use the following form:
module "consul" {
source = "git@github.com:hashicorp/example.git"
}
These GitHub schemes are treated as convenient aliases for
the general Git repository address scheme, and so
they obtain credentials in the same way and support the ref
argument for
selecting a specific revision. You will need to configure credentials in
particular to access private repositories.
Bitbucket
OpenTF will recognize unprefixed bitbucket.org
URLs and interpret them
automatically as BitBucket repositories:
module "consul" {
source = "bitbucket.org/example-corp/opentf-consul-aws"
}
This shorthand works only for public repositories, because OpenTF must access the BitBucket API to learn if the given repository uses Git or Mercurial.
OpenTF treats the result either as a Git source or a Mercurial source depending on the repository type. See the sections on each version control type for information on how to configure credentials for private repositories and how to specify a specific revision to install.
Generic Git Repository
Arbitrary Git repositories can be used by prefixing the address with the
special git::
prefix. After this prefix, any valid
Git URL
can be specified to select one of the protocols supported by Git.
For example, to use HTTPS or SSH:
module "vpc" {
source = "git::https://example.com/vpc.git"
}
module "storage" {
source = "git::ssh://username@example.com/storage.git"
}
OpenTF installs modules from Git repositories by running git clone
, and
so it will respect any local Git configuration set on your system, including
credentials. To access a non-public Git repository, configure Git with
suitable credentials for that repository.
If you use the SSH protocol then any configured SSH keys will be used automatically. This is the most common way to access non-public Git repositories from automated systems because it allows access to private repositories without interactive prompts.
If using the HTTP/HTTPS protocol, or any other protocol that uses username/password credentials, configure Git Credentials Storage to select a suitable source of credentials for your environment.
Selecting a Revision
By default, OpenTF will clone and use the default branch (referenced by
HEAD
) in the selected repository. You can override this using the
ref
argument. The value of the ref
argument can be any reference that would be accepted
by the git checkout
command, such as branch, SHA-1 hash (short or full), or tag names.
For a full list of the possible values, see
Git Tools - Revision Selection
in the Git Book.
# select a specific tag
module "vpc" {
source = "git::https://example.com/vpc.git?ref=v1.2.0"
}
# directly select a commit using its SHA-1 hash
module "storage" {
source = "git::https://example.com/storage.git?ref=51d462976d84fdea54b47d80dcabbf680badcdb8"
}
Shallow Clone
For larger repositories you may prefer to make only a shallow clone in order to reduce the time taken to retrieve the remote repository.
The depth
URL argument corresponds to
the --depth
argument to git clone
,
telling Git to create a shallow clone with the history truncated to only
the specified number of commits.
However, because shallow clone requires different Git protocol behavior,
setting the depth
argument makes OpenTF pass your ref
argument,
if any, to
the --branch
argument to git clone
instead. That means it must specify a named branch or tag known to the remote
repository, and that raw commit IDs are not acceptable.
Because OpenTF only uses the most recent selected commit to find the source
code of your specified module, it is not typically useful to set depth
to any value other than 1
.
"scp-like" address syntax
When using Git over SSH, we recommend using the ssh://
-prefixed URL form
for consistency with all of the other URL-like git address forms.
You may opt to use the alternative "scp-like" syntax instead, in which case you
must omit the ssh://
scheme part and include only the git::
part.
For example:
module "storage" {
source = "git::username@example.com:storage.git"
}
If you use the ssh://
URL scheme then OpenTF will assume that the colon
marks the beginning of a port number, rather than the beginning of the path.
This matches how Git itself interprets these different forms, aside from
the OpenTF-specific git::
selector prefix.
Generic Mercurial Repository
You can use arbitrary Mercurial repositories by prefixing the address with the
special hg::
prefix. After this prefix, any valid
Mercurial URL
can be specified to select one of the protocols supported by Mercurial.
module "vpc" {
source = "hg::http://example.com/vpc.hg"
}
OpenTF installs modules from Mercurial repositories by running hg clone
, and
so it will respect any local Mercurial configuration set on your system,
including credentials. To access a non-public repository, configure Mercurial
with suitable credentials for that repository.
If you use the SSH protocol then any configured SSH keys will be used automatically. This is the most common way to access non-public Mercurial repositories from automated systems because it allows access to private repositories without interactive prompts.
Selecting a Revision
You can select a non-default branch or tag using the optional ref
argument:
module "vpc" {
source = "hg::http://example.com/vpc.hg?ref=v1.2.0"
}
HTTP URLs
When you use an HTTP or HTTPS URL, OpenTF will make a GET
request to
the given URL, which can return another source address. This indirection
allows using HTTP URLs as a sort of "vanity redirect" over a more complicated
module source address.
OpenTF will append an additional query string argument opentf-get=1
to
the given URL before sending the GET
request, allowing the server to
optionally return a different result when OpenTF is requesting it.
If the response is successful (200
-range status code), OpenTF looks in
the following locations in order for the next address to access:
The value of a response header field named
X-OpenTF-Get
.If the response is an HTML page, a
meta
element with the nameopentf-get
:<meta name="opentf-get" content="github.com/hashicorp/example" />
In either case, the result is interpreted as another module source address using one of the forms documented elsewhere on this page.
If an HTTP/HTTPS URL requires authentication credentials, use a .netrc
file to configure the credentials. By default, OpenTF searches for the .netrc
file
in your HOME directory. However, you can override the default filesystem location by setting the NETRC
environment variable. For information on the .netrc
format,
refer to the documentation for using it in curl
.
Fetching archives over HTTP
As a special case, if OpenTF detects that the URL has a common file
extension associated with an archive file format then it will bypass the
special opentf-get=1
redirection described above and instead just use
the contents of the referenced archive as the module source code:
module "vpc" {
source = "https://example.com/vpc-module.zip"
}
The extensions that OpenTF recognizes for this special behavior are:
zip
tar.bz2
andtbz2
tar.gz
andtgz
tar.xz
andtxz
If your URL doesn't have one of these extensions but refers to an archive
anyway, use the archive
argument to force this interpretation:
module "vpc" {
source = "https://example.com/vpc-module?archive=zip"
}
-> Note: If the content of the archive file is a directory, you will need to include that directory in the module source. Read the section on Modules in Package Sub-directories for more information.
S3 Bucket
You can use archives stored in S3 as module sources using the special s3::
prefix, followed by
an S3 bucket object URL.
module "consul" {
source = "s3::https://s3-eu-west-1.amazonaws.com/examplecorp-opentf-modules/vpc.zip"
}
-> Note: Buckets in AWS's us-east-1 region must use the hostname s3.amazonaws.com
(instead of s3-us-east-1.amazonaws.com
).
The s3::
prefix causes OpenTF to use AWS-style authentication when
accessing the given URL. As a result, this scheme may also work for other
services that mimic the S3 API, as long as they handle authentication in the
same way as AWS.
The resulting object must be an archive with one of the same file extensions as for archives over standard HTTP. OpenTF will extract the archive to obtain the module source tree.
The module installer looks for AWS credentials in the following locations, preferring those earlier in the list when multiple are available:
- The
AWS_ACCESS_KEY_ID
andAWS_SECRET_ACCESS_KEY
environment variables. - The default profile in the
.aws/credentials
file in your home directory. - If running on an EC2 instance, temporary credentials associated with the instance's IAM Instance Profile.
GCS Bucket
You can use archives stored in Google Cloud Storage as module sources using the special gcs::
prefix, followed by
a GCS bucket object URL.
For example
gcs::https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH_TO_MODULE
gcs::https://www.googleapis.com/storage/v1/BUCKET_NAME/PATH/TO/module.zip
module "consul" {
source = "gcs::https://www.googleapis.com/storage/v1/modules/foomodule.zip"
}
The module installer uses Google Cloud SDK to authenticate with GCS. You can use any of the following methods to set Google Cloud Platform credentials:
- Set the
GOOGLE_OAUTH_ACCESS_TOKEN
environment variable to a raw Google Cloud Platform OAuth access token. - Enter the path of your service account key file in the
GOOGLE_APPLICATION_CREDENTIALS
environment variable. - If you're running OpenTF from a GCE instance, default credentials are automatically available. See Creating and Enabling Service Accounts for Instances for more details.
- On your computer, you can make your Google identity available by running
gcloud auth application-default login
.
Modules in Package Sub-directories
When the source of a module is a version control repository or archive file (generically, a "package"), the module itself may be in a sub-directory relative to the root of the package.
A special double-slash syntax is interpreted by OpenTF to indicate that the remaining path after that point is a sub-directory within the package. For example:
hashicorp/consul/aws//modules/consul-cluster
git::https://example.com/network.git//modules/vpc
https://example.com/network-module.zip//modules/vpc
s3::https://s3-eu-west-1.amazonaws.com/examplecorp-opentf-modules/network.zip//modules/vpc
If the source address has arguments, such as the ref
argument supported for
the version control sources, the sub-directory portion must be before those
arguments:
git::https://example.com/network.git//modules/vpc?ref=v1.2.0
github.com/hashicorp/example//modules/vpc?ref=v1.2.0
OpenTF will still extract the entire package to local disk, but will read the module from the subdirectory. As a result, it is safe for a module in a sub-directory of a package to use a local path to another module as long as it is in the same package.