GitLab CI template for Terraform¶
This project implements a GitLab CI/CD template to manage your infrastructure with Terraform.
Usage¶
This template can be used both as a CI/CD component
or using the legacy include:project
syntax.
Use as a CI/CD component¶
Add the following to your .gitlab-ci.yml
:
include:
# 1: include the component
- component: $CI_SERVER_FQDN/to-be-continuous/terraform/gitlab-ci-terraform@5.5.5
# 2: set/override component inputs
inputs:
# β this is only an example
image: registry.hub.docker.com/hashicorp/terraform:5.3.0
review-enabled: true
staging-enabled: true
prod-enabled: true
Use as a CI/CD template (legacy)¶
Add the following to your .gitlab-ci.yml
:
include:
# 1: include the template
- project: 'to-be-continuous/terraform'
ref: '5.5.5'
file: '/templates/gitlab-ci-terraform.yml'
variables:
# 2: set/override template variables
# β this is only an example
TF_IMAGE: registry.hub.docker.com/hashicorp/terraform:5.3.0
TF_REVIEW_ENABLED: "true"
TF_STAGING_ENABLED: "true"
TF_PROD_ENABLED: "true"
Understand¶
This chapter introduces key notions and principle to understand how this template works.
Managed deployment environments¶
This template implements continuous deployment on your infrastructure using Terraform.
It allows you to manage creation, update & cleanup of standard predefined environments. Each environment can be enabled/disabled by configuration. If you're not satisfied with predefined environments and/or their associated Git workflow, you may implement you own environments and workflow, by reusing/extending the base (hidden) jobs. This is advanced usage and will not be covered by this documentation.
The following chapters present the managed predefined environments and their associated Git workflow.
Review environments¶
The template supports review environments: those are dynamic and ephemeral environments to deploy your ongoing developments (a.k.a. feature or topic branches).
When enabled, it deploys the result from upstream build stages to a dedicated and temporary environment. It is only active for non-production, non-integration branches.
It is a strict equivalent of GitLab's Review Apps feature.
It also comes with a cleanup job (accessible either from the environments page, or from the pipeline view).
Integration environment¶
If you're using a Git Workflow with an integration branch (such as Gitflow), the template supports an integration environment.
When enabled, it deploys the result from upstream build stages to a dedicated environment.
It is only active for your integration branch (develop
by default).
Production environments¶
Lastly, the template supports 2 environments associated to your production branch (main
or master
by default):
- a staging environment (an iso-prod environment meant for testing and validation purpose),
- the production environment.
You're free to enable whichever or both, and you can also choose your deployment-to-production policy:
- continuous deployment: automatic deployment to production (when the upstream pipeline is successful),
- continuous delivery: deployment to production can be triggered manually (when the upstream pipeline is successful).
Template jobs¶
The Terraform template implements - for each environment presented above - the following jobs:
- environment creation/update plan: this job is optional and computes the environment changes before applying them. When enabled, the env creation has to be applied manually. By default, this job is enabled only for the production environment.
- environment creation/update apply: applies the environment changes, whether manually by applying the upstream plan (when enabled), or automatically.
- environment destruction: can be executed manually on non-production envs only.
Hook scripts¶
Terraform jobs also support optional hook scripts from your project, located in the $TF_SCRIPTS_DIR
directory (root project dir by default, but may be overridden).
tf-pre-init.sh
is executed before runningterraform init
tf-pre-apply.sh
is executed before runningterraform apply
tf-post-apply.sh
is executed after runningterraform apply
tf-pre-destroy.sh
is executed before runningterraform destroy
tf-post-destroy.sh
is executed after runningterraform destroy
Terraform commands overrides¶
Instead of creating hook scripts, you can also override and/or decorate the Terraform commands
using predefined .tf-commands
template block, referenced by the !reference
directive.
By default, the .tf-commands
, block is composed as below:
.tf-commands:
init:
- !reference [ .tf-commands, default, init ]
plan:
- !reference [ .tf-commands, default, plan ]
apply:
- !reference [ .tf-commands, default, apply ]
destroy:
- !reference [ .tf-commands, default, destroy ]
You can override it for example in the following way:
.tf-commands:
init:
- source sandbox.env
- !reference [ .tf-commands, default, init ]
- echo "I'm executed after the terraform init command"
You can use this mechanism to source to the current shell your own environmental variables.
Deployment context variables¶
In order to manage the various deployment environments, this template provides a couple of dynamic variables that you might use in your hook scripts or Terraform scripts (as input variables):
environment_type
: the current deployment environment type (review
,integration
,staging
orproduction
)environment_name
(equals$CI_ENVIRONMENT_NAME
): the full environment name (ex:review/fix-prometheus-configuration
,integration
,staging
orproduction
)environment_slug
(equals$CI_ENVIRONMENT_SLUG
): the sluggified environment name (ex:review-fix-promet-r13zmu
,integration
,staging
orproduction
)
Using variables¶
You have to be aware that your Terraform code has to be able to cope with various environments
(review
, integration
, staging
and production
), each with different application names, exposed routes, settings, ...
Part of this complexity can be handled by using Terraform variables (in your Terraform files), and environment variables (in your hook scripts):
- deployment context variables provided by the template:
environment_type
: the current deployment environment type (review
,integration
,staging
orproduction
)environment_name
(equals$CI_ENVIRONMENT_NAME
): the full environment name (ex:review/fix-prometheus-configuration
,integration
,staging
orproduction
)environment_slug
(equals$CI_ENVIRONMENT_SLUG
): the sluggified environment name (ex:review-fix-promet-r13zmu
,integration
,staging
orproduction
)
- use
tfvars
files for non-secret configuration:- default
terraform.tfvars[.json]
and*.auto.tfvars[.json]
files are obviously supported by Terraform, - the template also auto-detects any file named
$environment_type.env.tfvars[.json]
(ex:staging.env.tfvars
for staging environment) and uses it with all relatedterraform
commands.
- default
- any predefined GitLab CI variable may be freedly used in your hook scripts or extra options variables (ex:
TF_EXTRA_OPTS: "-var project_name=$CI_PROJECT_NAME"
) - you may also use custom GitLab variables to pass values to your hook script or even directly as Terraform variables using the right syntax
(ex: env variable
$TF_VAR_ssh_private_key_file
will be visible asssh_private_key_file
Terraform variable in your code)
When managing multiple environments, it is a good practice to prefix your Terraform resource names with
environment_slug
variable.Example:
resource "aws_instance" "web_server" { name = "myproj_${var.environment_slug}_web_server" ... }
How to manage separate values per environment?¶
It may happen that you need to use different configuration variables depending on the environment you are deploying.
For instance separate GOOGLE_CREDENTIALS
if you're using Google Provider.
For this, you shall either use GitLab scoped variables or our scoped variables syntax to limit/override some variables values, using $CI_ENVIRONMENT_NAME
as the conditional variable.
Example: different OpenStack provider configuration for production
variables:
# global OpenStack provider configuration
OS_AUTH_URL: "https://openstack-nonprod.api.domain/v3"
OS_TENANT_ID: "my-nonprod-tenant"
OS_TENANT_NAME: "my-project-nonprod"
OS_INSECURE: "true"
# OS_USERNAME & OS_PASSWORD are defined as secret GitLab CI variables
# overridden configuration for production
scoped__OS_AUTH_URL__if__CI_ENVIRONMENT_NAME__equals__production: "https://openstack-prod.api.domain/v3"
scoped__OS_TENANT_ID__if__CI_ENVIRONMENT_NAME__equals__production: "my-prod-tenant"
scoped__OS_TENANT_NAME__if__CI_ENVIRONMENT_NAME__equals__production: "my-project-prod"
scoped__OS_INSECURE__if__CI_ENVIRONMENT_NAME__equals__production: "false"
# OS_USERNAME & OS_PASSWORD are overridden as secret GitLab CI variables
Supported output artifacts¶
The Terraform template supports job artifacts that your Terraform code may generate and need to propagate to downstream jobs:
$TF_OUTPUT_DIR
directory and all contained files are stored as job artifacts. Allows to propagate files.- If present, the
terraform.env
file is stored as a dotenv artifact. Allows to propagate environment variables.
Examples:
- When used in conjuction with Ansible template, your Terraform script may generate the Ansible inventory file into the
$TF_OUTPUT_DIR
directory. - When dynamically obtaining a floating IP address, your Terraform script may generate the
terraform.env
file to propated it as an environment variables.
Terraform integration in Merge Requests¶
This template enables Terraform integration in Merge Requests.
As a result if you enabled your production
environment, every merge request will compute and display infrastructure changes compared to master
branch.
Terraform Backend management¶
GitLab managed Terraform State (default)¶
By default, this template enables GitLab managed Terraform State.
As mentionned in GitLab's documentation, that requires that your Terraform scripts declare the (unconfigured) Terraform HTTP backend, and the template will do the necessary to configure it automatically.
All you have to do if you want it is to add the following in one of your .tf
files:
terraform {
# using GitLab http backend
backend "http" {
# auto-configured by the template
}
}
This default behavior can also be disabled by setting $TF_GITLAB_BACKEND_DISABLED
to true
.
In that case, you'll have to declare and configure your backend and tfstate by yourself (see Implicit Backend configuration support below).
How to use GitLab backend in your development environment ?¶
First create a Project Access Token or Personal Access Token.
In your shell terminal, execute the following script:
#!/bin/bash
# TODO: replace 3 next variables
MY_PROJECT_PATH="path/to/my-project"
MY_ENV_NAME="dev"
TF_HTTP_PASSWORD="YOUR-ACCESS-TOKEN"
CI_API_V4_URL=https://gitlab.com/api/v4
CI_PROJECT_ID=${MY_PROJECT_PATH//\//%2f}
TF_HTTP_ADDRESS="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/$MY_ENV_NAME"
TF_HTTP_LOCK_ADDRESS="${TF_HTTP_ADDRESS}/lock"
TF_HTTP_LOCK_METHOD="POST"
TF_HTTP_UNLOCK_ADDRESS="${TF_HTTP_ADDRESS}/lock"
TF_HTTP_UNLOCK_METHOD="DELETE"
TF_HTTP_USERNAME="gitlab-token"
TF_HTTP_RETRY_WAIT_MIN="5"
terraform -v
terraform init \
-reconfigure \
-backend-config=address="${TF_HTTP_ADDRESS}" \
-backend-config=lock_address="${TF_HTTP_LOCK_ADDRESS}" \
-backend-config=unlock_address="${TF_HTTP_UNLOCK_ADDRESS}" \
-backend-config=username="${TF_HTTP_USERNAME}" \
-backend-config=password="${TF_HTTP_PASSWORD}" \
-backend-config=lock_method="${TF_HTTP_LOCK_METHOD}" \
-backend-config=unlock_method="${TF_HTTP_UNLOCK_METHOD}" \
-backend-config=retry_wait_min="${TF_HTTP_RETRY_WAIT_MIN}"
Implicit Backend configuration support¶
If you disabled the GitLab-managed Terraform state (by setting $TF_GITLAB_BACKEND_DISABLED
to true
),
the template supports an implicit backend configuration mechanism:
- Looks for a
$environment_type.tfbackend
file (ex:staging.tfbackend
for staging environment), - Fallbacks to
default.tfbackend
file.
If one of those files are found, it is automatically used by the template in the terraform init
command (using the -backend-config
CLI option).
Workspace management¶
You may want to make use of Terraform Workspace to ease segregating you multiple environments (tfstate management) by setting variables:
$TF_WORKSPACE
to set default workspace,$TF_REVIEW_WORKSPACE
,$TF_INTEG_WORKSPACE
,$TF_STAGING_WORKSPACE
,$TF_PROD_WORKSPACE
to override per environment.
Be aware of the following:
- each of those variables support the value
auto
: in that case, the template will use the dynamic$environment_slug
value as workspace name, - if the specified workspace doesn't exist, the template will create it,
- HTTP backend doesn't support Workspaces. See supported backends here.
- corollary as GitLab http backend is on by default workspace selection is explicitly bypassed
unless
gitlab-backend-disabled
/TF_GITLAB_BACKEND_DISABLED
is set totrue
. If kept enabled and if any of theTF_WORKSPACE
variable is set the template will warn about it. - if using another (non-Gitlab) http backend nothing will prevent from trying to use workspaces, in
that case you'll get a Terraform error
workspaces not supported
.
Using modules from private registries¶
The Terraform template supports using modules from private registries (GitLab's Registry or others).
Modules can be refered as usual in your Terraform code:
module "<module>" {
source = "tf.registry.address/organization/provider/module_name"
}
And finally authentication credentials shall be defined as secret environment variable credentials.
In the above example, that would mean defining a TF_TOKEN_tf_registry_address
project variable containing the authentication token.
by default the template automatically sets the authentication token for the GitLab Modules Registry using the $CI_JOB_TOKEN
value.
If you want to use another credential (personal access token or else), just define explicitly TF_TOKEN_gitlab_com
(or the right one for your GitLab server)
as a project variable with the desired credential.
Terraform lock file¶
As explained in Terraform documentation, you should include the .terraform.lock.hcl
file in your version control repository.
This will guarantee the Terraform template is using exactly the same dependencies version as you are using in your local development environment.
Configuration reference¶
Secrets management¶
Here are some advices about your secrets (variables marked with a ):
- Manage them as project or group CI/CD variables:
- In case a secret contains characters that prevent it from being masked,
simply define its value as the Base64 encoded value prefixed with
@b64@
: it will then be possible to mask it and the template will automatically decode it prior to using it. - Don't forget to escape special characters (ex:
$
->$$
).
Global configuration¶
The Terraform template uses some global configuration used throughout all jobs.
Input / Variable | Description | Default value |
---|---|---|
image / TF_IMAGE |
the Docker image used to run Terraform CLI commands set the version required by your project |
registry.hub.docker.com/hashicorp/terraform:latest |
gitlab-backend-disabled / TF_GITLAB_BACKEND_DISABLED |
Set to true to disable GitLab managed Terraform State |
none (enabled) |
project-dir / TF_PROJECT_DIR |
Terraform project root directory | . |
scripts-dir / TF_SCRIPTS_DIR |
Terraform (hook) scripts base directory (relative to $TF_PROJECT_DIR ) |
. |
output-dir / TF_OUTPUT_DIR |
Terraform output directory (relative to $TF_PROJECT_DIR ). Everything generated in this directory will be kept as job artifacts. |
tf-output |
extra-opts / TF_EXTRA_OPTS |
Default Terraform extra options (applies to all Terraform commands) | none |
init-opts / TF_INIT_OPTS |
Default Terraform extra init options | none |
workspace / TF_WORKSPACE |
Default Terraform project workspace | none (do not use workspaces) |
apply-opts / TF_APPLY_OPTS |
Default Terraform extra apply options | none |
destroy-opts / TF_DESTROY_OPTS |
Default Terraform extra destroy options | none |
Review environments configuration¶
Review environments are dynamic and ephemeral environments to deploy your ongoing developments (a.k.a. feature or topic branches).
They are disabled by default and can be enabled by setting the TF_REVIEW_ENABLED
variable (see below).
Here are variables supported to configure review environments:
Input / Variable | Description | Default value |
---|---|---|
review-enabled / TF_REVIEW_ENABLED |
Set to true to enable your review environments |
none (disabled) |
review-extra-opts / TF_REVIEW_EXTRA_OPTS |
Terraform extra options for review env (applies to all Terraform commands) |
$TF_EXTRA_OPTS |
review-init-opts / TF_REVIEW_INIT_OPTS |
Terraform extra init options for review env |
$TF_INIT_OPTS |
review-workspace / TF_REVIEW_WORKSPACE |
Terraform project workspace for review env |
$TF_WORKSPACE |
review-plan-enabled / TF_REVIEW_PLAN_ENABLED |
Set to true to enable separate Terraform plan job for review env. |
none (disabled) |
review-plan-opts / TF_REVIEW_PLAN_OPTS |
Terraform extra plan options for review env |
none |
review-apply-opts / TF_REVIEW_APPLY_OPTS |
Terraform extra apply options for review env |
$TF_APPLY_OPTS |
review-destroy-opts / TF_REVIEW_DESTROY_OPTS |
Terraform extra destroy options for review env |
$TF_DESTROY_OPTS |
review-autostop-duration / TF_REVIEW_AUTOSTOP_DURATION |
The amount of time before GitLab will automatically stop review environments |
4 hours |
Enabling auto-cleanup¶
GitLab provides a way to automatically Stop an environment when a merge request is merged or closed.
It is not enabled by default in the Terraform template, mainly because it is not easy to undo.
Here is what you should add to your .gitlab-ci.yml
file to enable it for review environments:
# auto cleanup review environments (when MR is merged or closed)
tf-review:
environment:
on_stop: tf-destroy-review
Integration environment configuration¶
The integration environment is the environment associated to your integration branch (develop
by default).
It is disabled by default and can be enabled by setting the TF_INTEG_ENABLED
variable (see below).
Here are variables supported to configure the integration environment:
Input / Variable | Description | Default value |
---|---|---|
integ-enabled / TF_INTEG_ENABLED |
Set to true to enable your integration env |
none (disabled) |
integ-extra-opts / TF_INTEG_EXTRA_OPTS |
Terraform extra options for integration env (applies to all Terraform commands) |
$TF_EXTRA_OPTS |
integ-init-opts / TF_INTEG_INIT_OPTS |
Terraform extra init options for integration env |
$TF_INIT_OPTS |
integ-workspace / TF_INTEG_WORKSPACE |
Terraform project workspace for integration env |
$TF_WORKSPACE |
integ-plan-enabled / TF_INTEG_PLAN_ENABLED |
Set to true to enable separate Terraform plan job for integration env. |
none (disabled) |
integ-plan-opts / TF_INTEG_PLAN_OPTS |
Terraform extra plan options for integration env |
none |
integ-apply-opts / TF_INTEG_APPLY_OPTS |
Terraform extra apply options for integration env |
$TF_APPLY_OPTS |
integ-destroy-opts / TF_INTEG_DESTROY_OPTS |
Terraform extra destroy options for integration env |
$TF_DESTROY_OPTS |
integ-autostop-duration / TF_INTEG_AUTOSTOP_DURATION |
The amount of time before GitLab will automatically stop the integration env |
never |
Staging environment configuration¶
The staging environment is an iso-prod environment meant for testing and validation purpose associated to your production
branch (main
or master
by default).
It is disabled by default and can be enabled by setting the TF_STAGING_ENABLED
variable (see below).
Here are variables supported to configure the staging environment:
Input / Variable | Description | Default value |
---|---|---|
staging-enabled / TF_STAGING_ENABLED |
Set to true to enable your staging env |
none (disabled) |
staging-extra-opts / TF_STAGING_EXTRA_OPTS |
Terraform extra options for staging env (applies to all Terraform commands) |
$TF_EXTRA_OPTS |
staging-init-opts / TF_STAGING_INIT_OPTS |
Terraform extra init options for staging env |
$TF_INIT_OPTS |
staging-workspace / TF_STAGING_WORKSPACE |
Terraform project workspace for staging env |
$TF_WORKSPACE |
staging-plan-enabled / TF_STAGING_PLAN_ENABLED |
Set to true to enable separate Terraform plan job for staging env. |
none (disabled) |
staging-plan-opts / TF_STAGING_PLAN_OPTS |
Terraform extra plan options for staging env |
none |
staging-apply-opts / TF_STAGING_APPLY_OPTS |
Terraform extra apply options for staging env |
$TF_APPLY_OPTS |
staging-destroy-opts / TF_STAGING_DESTROY_OPTS |
Terraform extra destroy options for staging env |
$TF_DESTROY_OPTS |
staging-autostop-duration / TF_STAGING_AUTOSTOP_DURATION |
The amount of time before GitLab will automatically stop the staging env |
never |
Production environment configuration¶
The production environment is the final deployment environment associated with your production branch (main
or master
by default).
It is disabled by default and can be enabled by setting the TF_PROD_ENABLED
variable (see below).
Here are variables supported to configure the production environment:
Input / Variable | Description | Default value |
---|---|---|
prod-enabled / TF_PROD_ENABLED |
Set to true to enable your production env |
none (disabled) |
prod-extra-opts / TF_PROD_EXTRA_OPTS |
Terraform extra options for production env (applies to all Terraform commands) |
$TF_EXTRA_OPTS |
prod-init-opts / TF_PROD_INIT_OPTS |
Terraform extra init options for production env |
$TF_INIT_OPTS |
prod-workspace / TF_PROD_WORKSPACE |
Terraform project workspace for production env |
$TF_WORKSPACE |
prod-plan-enabled / TF_PROD_PLAN_ENABLED |
Set to true to enable separate Terraform plan job for production env. |
true (enabled) |
prod-plan-opts / TF_PROD_PLAN_OPTS |
Terraform extra plan options for production env |
none |
prod-apply-opts / TF_PROD_APPLY_OPTS |
Terraform extra apply options for production env |
$TF_APPLY_OPTS |
tf-tflint
job¶
tflint is a Terraform Linter and uses the following variables:
Input / Variable | Description | Default value |
---|---|---|
tflint-image / TF_TFLINT_IMAGE |
the Docker image used to run tflint | ghcr.io/terraform-linters/tflint-bundle:latest |
tflint-disabled / TF_TFLINT_DISABLED |
Set to true to disable tflint |
none (enabled) |
tflint-args / TF_TFLINT_ARGS |
tflint extra options and args | --enable-plugin=google --enable-plugin=azurerm --enable-plugin=aws --recursive |
In addition to a textual report in the console, this job produces the following reports, kept for one day:
Report | Format | Usage |
---|---|---|
$TF_PROJECT_DIR/reports/tflint.xunit.xml |
xUnit test report(s) | GitLab integration |
[DEPRECATED] tf-tfsec
job¶
tfsec
has been deprecated, it is recommended to use trivy instead.
tfsec uses static analysis of your terraform templates to spot potential security issues and uses the following variables:
Input / Variable | Description | Default value |
---|---|---|
tfsec-image / TF_TFSEC_IMAGE |
the Docker image used to run tfsec | registry.hub.docker.com/aquasec/tfsec-ci |
tfsec-enabled / TF_TFSEC_ENABLED |
Set to true to enable tfsec |
none (disabled) |
tfsec-args / TF_TFSEC_ARGS |
tfsec options and args | . |
In addition to a textual report in the console, this job produces the following reports, kept for one day and only available for download by users with the Developer role or higher:
Report | Format | Usage |
---|---|---|
$TF_PROJECT_DIR/reports/tfsec.xunit.xml |
xUnit test report(s) | GitLab integration |
$TF_PROJECT_DIR/reports/tfsec.native.json |
tfsec JSON | DefectDojo integration This report is generated only if DefectDojo template is detected |
tf-trivy
job¶
trivy is used to perform static analysis of your terraform templates to spot potential security issues and uses the following variables:
Input / Variable | Description | Default value |
---|---|---|
trivy-image / TF_TRIVY_IMAGE |
the Docker image used to run trivy | registry.hub.docker.com/aquasec/trivy |
trivy-disabled / TF_TRIVY_DISABLED |
Set to true to disable trivy |
none (enabled) |
trivy-args / TF_TRIVY_ARGS |
trivy config options and args | . |
In addition to a textual report in the console, this job produces the following reports, kept for one day and only available for download by users with the Developer role or higher:
Report | Format | Usage |
---|---|---|
$TF_PROJECT_DIR/reports/tf-trivy.codeclimate.json |
Code Climate | GitLab integration |
$TF_PROJECT_DIR/reports/tf-trivy.trivy.json |
Trivy JSON report | DefectDojo integration This report is generated only if DefectDojo template is detected |
tf-checkov
job¶
checkov is a static code analysis tool for infrastructure-as-code and uses the following variables:
Input / Variable | Description | Default value |
---|---|---|
checkov-image / TF_CHECKOV_IMAGE |
the Docker image used to run checkov | registry.hub.docker.com/bridgecrew/checkov |
checkov-enabled / TF_CHECKOV_ENABLED |
Set to true to enable checkov |
none (disabled) |
checkov-args / TF_CHECKOV_ARGS |
additional checkov options and args | --framework terraform |
Command line arguments for checkov
are the result of the concatenation of --directory .
and $TF_CHECKOV_ARGS
.
As a consequence additional --directory
or --file
arguments will be ignored.
In addition to a textual report in the console, this job produces the following reports, kept for one day and only available for download by users with the Developer role or higher:
Report | Format | Usage |
---|---|---|
$TF_PROJECT_DIR/reports/checkov.xunit.xml |
JUnit XML | GitLab integration |
$TF_PROJECT_DIR/reports/checkov.native.json |
checkov JSON | DefectDojo integration This report is generated only if DefectDojo template is detected |
You can skip checkov specific check adding following comment in code :
resource "aws_s3_bucket" "foo-bucket" {
region = var.region
#checkov:skip=CKV_AWS_20:The bucket is a public static content host
bucket = local.bucket_name
force_destroy = true
acl = "public-read"
}
tf-infracost
job¶
Infracost shows cloud cost estimates for infrastructure-as-code projects and uses the following variables:
Input / Variable | Description | Default value |
---|---|---|
infracost-enabled / TF_INFRACOST_ENABLED |
Set to true to enable infracost |
none (disabled) |
infracost-image / TF_INFRACOST_IMAGE |
the infracost container image | registry.hub.docker.com/infracost/infracost |
infracost-args / TF_INFRACOST_ARGS |
infracost CLI options and args | breakdown |
infacost-usage-file / TF_INFACOST_USAGE_FILE |
infracost usage file | infracost-usage.yml |
INFRACOST_API_KEY |
the infracost API key | required |
To use infracost, an api key is needed. To obtain it run :
docker run -it --name infracost infracost/infracost register
Please enter your name and email address to get an API key.
See our FAQ (https://www.infracost.io/docs/faq) for more details.
Name: Your Name
β Email: you_email@domainβ
Thank you !
Your API key is: api_key
Save the API key as INFRACOST_API_KEY
GitLab secret variable.
Set INFRACOST_CURRENCY
variable to set currency ISO 4217 prices should be converted to. Defaults to USD.
tf-fmt
job¶
The terraform fmt
command is usually used to format Terraform source files to a canonical format and style.
This job uses the check mode, and fails if any file appears not being properly formatted. It uses the following variables:
Input / Variable | Description | Default value |
---|---|---|
fmt-enabled / TF_FMT_ENABLED |
Set to true to enable terraform fmt |
none (disabled) |
fmt-args / TF_FMT_ARGS |
terraform fmt options | -diff -recursive |
tf-validate
job¶
The terraform validate
command is usually used to validate the configuration files in a directory. It is very useful to check a terraform module.
Input / Variable | Description | Default value |
---|---|---|
validate-enabled / TF_VALIDATE_ENABLED |
Set to true to enable terraform validate |
none (disabled) |
tf-docs
job¶
Build Terraform documentation based on terraform docs.
Input / Variable | Description | Default value |
---|---|---|
docs-enabled / TF_DOCS_ENABLED |
Set to true to enable terraform docs |
none (disabled) |
docs-image / TF_DOCS_IMAGE |
terraform docs container image | quay.io/terraform-docs/terraform-docs:edge |
docs-extra-opts / TF_DOCS_EXTRA_OPTS |
Extra terraform docs option | none |
docs-config / TF_DOCS_CONFIG |
terraform docs configuration file (relative to $TF_PROJECT_DIR ) |
.terraform-docs.yml |
docs-output-dir / TF_DOCS_OUTPUT_DIR |
terraform docs output directory (relative to $TF_PROJECT_DIR ). |
docs |
In order to generate your documentation with the right format and options, you should add a terraform docs configuration file
(.terraform-docs.yml
) at the root of your Terraform project ($TF_PROJECT_DIR
) in your Git repository.
As long as you don't, this job will simply generate the pretty
doc format in the output console.
tf-publish-module
job¶
Publish your Terraform project as a module to GitLab's Terraform Module Registry.
When enabled, this job triggers on a Git tag with semantic version pattern (v?[0-9]+\.[0-9]+\.[0-9]+
, configurable) and publishes the module with the same version.
Input / Variable | Description | Default value |
---|---|---|
publish-enabled / TF_PUBLISH_ENABLED |
Set to true to enable Terraform Module Publish |
none (disabled) |
publish-image / TF_PUBLISH_IMAGE |
Container image used to publish module. | registry.hub.docker.com/curlimages/curl:latest |
module-name / TF_MODULE_NAME |
The module name. May not contain any spaces or underscores. | $CI_PROJECT_NAME |
module-system / TF_MODULE_SYSTEM |
The module system or provider (example: local , aws , google ). |
local |
module-version / TF_MODULE_VERSION |
The module version. It must be valid according to the semantic versioning specification. | $CI_COMMIT_TAG (leave default unless you have good reasons to override) |
module-files / TF_MODULE_FILES |
Glob patterns matching files to include into the Terraform module ( does not support double star). | *.tf *.tpl *.md |
Example: publish module with sub-modules¶
By default the template has the right configuration to publish a single module Terraform project (with tf
, tpl
and md
files).
If you're willing to publish a more complex module, possibly with submodules, then you'll have to override the default TF_MODULE_FILES
variable, with
something like the following:
variables:
# grab submodules from modules/*, templates from templates/ and examples from examples/
TF_MODULE_FILES: "*.tf *.md templates/* modules/*/*.tf modules/*/*.md examples/*.tf examples/*.md"
Variants¶
The Terraform template can be used in conjunction with template variants to cover specific cases.
Vault variant¶
This variant allows delegating your secrets management to a Vault server.
Configuration¶
In order to be able to communicate with the Vault server, the variant requires the additional configuration parameters:
Input / Variable | Description | Default value |
---|---|---|
TBC_VAULT_IMAGE |
The Vault Secrets Provider image to use (can be overridden) | registry.gitlab.com/to-be-continuous/tools/vault-secrets-provider:latest |
vault-base-url / VAULT_BASE_URL |
The Vault server base API url | none |
vault-oidc-aud / VAULT_OIDC_AUD |
The aud claim for the JWT |
$CI_SERVER_URL |
VAULT_ROLE_ID |
The AppRole RoleID | must be defined |
VAULT_SECRET_ID |
The AppRole SecretID | must be defined |
Usage¶
Then you may retrieve any of your secret(s) from Vault using the following syntax:
@url@http://vault-secrets-provider/api/secrets/{secret_path}?field={field}
With:
Parameter | Description |
---|---|
secret_path (path parameter) |
this is your secret location in the Vault server |
field (query parameter) |
parameter to access a single basic field from the secret JSON payload |
Example¶
include:
# main template
- component: $CI_SERVER_FQDN/to-be-continuous/terraform/gitlab-ci-terraform@5.5.5
# Vault variant
- component: $CI_SERVER_FQDN/to-be-continuous/terraform/gitlab-ci-terraform-vault@5.5.5
inputs:
# audience claim for JWT
vault-oidc-aud: "https://vault.acme.host"
vault-base-url: "https://vault.acme.host/v1"
# $VAULT_ROLE_ID and $VAULT_SECRET_ID defined as a secret CI/CD variable
variables:
# Secrets managed by Vault
AWS_ACCESS_KEY_ID: "@url@http://vault-secrets-provider/api/secrets/b7ecb6ebabc231/aws/prod/account?field=access_key_id"
AWS_SECRET_ACCESS_KEY: "@url@http://vault-secrets-provider/api/secrets/b7ecb6ebabc231/aws/prod/account?field=secret_access_key"
Google Cloud variant¶
This variant uses Application Default Credentials through the GOOGLE_APPLICATION_CREDENTIALS
variable
as explained in the Google Terraform provider configuration Running Terraform Outside of Google Cloud
using Workload Identity federation.
List of requirements before using this variant:
- You must have a Workload Identity Federation Pool and Provider configured,
- You must have a Service Account with the
roles/iam.workloadIdentityUser
IAM role granted to the Workload Identity principal matching your Gitlab project or group, - Optionally, you can set the
GOOGLE_CLOUD_PROJECT
template variable to define the default Google Cloud project.
The Gitlab documentation has some details about Workload Identity Federation integration.
This blog post about OIDC impersonation through Workload Identify Federation might also be of help.
Configuration¶
The variant requires the additional configuration parameters:
Input / Variable | Description | Default value |
---|---|---|
gcp-oidc-aud / GCP_OIDC_AUD |
The aud claim for the JWT token |
$CI_SERVER_URL |
gcp-oidc-provider / GCP_OIDC_PROVIDER |
Default Workload Identity Provider associated with GitLab to authenticate with OpenID Connect | none |
gcp-oidc-account / GCP_OIDC_ACCOUNT |
Default Service Account to which impersonate with OpenID Connect authentication | none |
gcp-review-oidc-provider / GCP_REVIEW_OIDC_PROVIDER |
Workload Identity Provider associated with GitLab to authenticate with OpenID Connect on review environment (only define to override default) |
none |
gcp-review-oidc-account / GCP_REVIEW_OIDC_ACCOUNT |
Service Account to which impersonate with OpenID Connect authentication on review environment (only define to override default) |
none |
gcp-integ-oidc-provider / GCP_INTEG_OIDC_PROVIDER |
Workload Identity Provider associated with GitLab to authenticate with OpenID Connect on integration environment (only define to override default) |
none |
gcp-integ-oidc-account / GCP_INTEG_OIDC_ACCOUNT |
Service Account to which impersonate with OpenID Connect authentication on integration environment (only define to override default) |
none |
gcp-staging-oidc-provider / GCP_STAGING_OIDC_PROVIDER |
Workload Identity Provider associated with GitLab to authenticate with OpenID Connect on staging environment (only define to override default) |
none |
gcp-staging-oidc-account / GCP_STAGING_OIDC_ACCOUNT |
Service Account to which impersonate with OpenID Connect authentication on staging environment (only define to override default) |
none |
gcp-prod-oidc-provider / GCP_PROD_OIDC_PROVIDER |
Workload Identity Provider associated with GitLab to authenticate with OpenID Connect on production environment (only define to override default) |
none |
gcp-prod-oidc-account / GCP_PROD_OIDC_ACCOUNT |
Service Account to which impersonate with OpenID Connect authentication on production environment (only define to override default) |
none |
Example¶
With a common default GCP_OIDC_PROVIDER
and GCP_OIDC_ACCOUNT
configuration for non-prod environments, and a specific one for production:
include:
# main template
- component: $CI_SERVER_FQDN/to-be-continuous/terraform/gitlab-ci-terraform@5.5.5
# Google Cloud variant
- component: $CI_SERVER_FQDN/to-be-continuous/terraform/gitlab-ci-terraform-gcp@5.5.5
inputs:
# common OIDC config for non-prod envs
gcp-oidc-provider: "projects/<gcp_nonprod_proj_id>/locations/global/workloadIdentityPools/<pool_id>/providers/<provider_id>"
gcp-oidc-account: "<name>@$<gcp_nonprod_proj_id>.iam.gserviceaccount.com"
# specific OIDC config for prod
gcp-prod-oidc-provider: "projects/<gcp_prod_proj_id>/locations/global/workloadIdentityPools/<pool_id>/providers/<provider_id>"
gcp-prod-oidc-account: "<name>@$<gcp_prod_proj_id>.iam.gserviceaccount.com"
AWS variant¶
This variant enables OpenID Connect to retrieve temporary credentials from AWS.
If you wish to use this authentication mode, please follow carefully the GitLab guide, then configure appropriately the related variables:
AWS_OIDC_ROLE_ARN
for any global/common access,AWS_REVIEW_OIDC_ROLE_ARN
and/orAWS_INTEG_OIDC_ROLE_ARN
and/orAWS_STAGING_OIDC_ROLE_ARN
and/orAWS_PROD_OIDC_ROLE_ARN
if you wish to use a separate role with any of your environments.
Provided you successfully configured the above, this variant automatically sets the appropriate Assume Role with Web Identity configuration (environment variables) supported by the AWS Provider for Terraform.
Configuration¶
The variant supports the following configuration:
Input / Variable | Description | Default value |
---|---|---|
aws-oidc-aud / AWS_OIDC_AUD |
The aud claim for the JWT |
$CI_SERVER_URL |
aws-oidc-role-arn / AWS_OIDC_ROLE_ARN |
Default IAM Role ARN associated with GitLab to authenticate using OpenID Connect | none (disabled) |
aws-review-oidc-role-arn / AWS_REVIEW_OIDC_ROLE_ARN |
IAM Role ARN associated with GitLab to authenticate using OpenID Connect on review env (only define to override default) |
none (disabled) |
aws-integ-oidc-role-arn / AWS_INTEG_OIDC_ROLE_ARN |
IAM Role ARN associated with GitLab to authenticate using OpenID Connect on integration env (only define to override default) |
none (disabled) |
aws-staging-oidc-role-arn / AWS_STAGING_OIDC_ROLE_ARN |
IAM Role ARN associated with GitLab to authenticate using OpenID Connect on staging env (only define to override default) |
none (disabled) |
aws-prod-oidc-role-arn / AWS_PROD_OIDC_ROLE_ARN |
IAM Role ARN associated with GitLab to authenticate using OpenID Connect on production env (only define to override default) |
none (disabled) |
Example¶
include:
# main template
- component: $CI_SERVER_FQDN/to-be-continuous/terraform/gitlab-ci-terraform@5.5.5
# AWS variant
- component: $CI_SERVER_FQDN/to-be-continuous/terraform/gitlab-ci-terraform-aws@5.5.5
inputs:
# audience claim for JWT
aws-oidc-aud: "https://gitlab.acme.com"
# common OIDC role ARN for non-prod envs
aws-oidc-role-arn: "arn:aws:iam::111111111111:role/cicd-role"
# specific OIDC role ARN for prod
aws-prod-oidc-role-arn: "arn:aws:iam::222222222222:role/cicd-role"