Run the Teleport Terraform Provider in CI or Cloud
This guides covers how to run the Teleport Terraform Provider from:
- your CI/CD pipelines on:
- GitHub Actions (we'll use the
github
join method) - GitlabCI (we'll use the
gitlab
join method) - CircleCI (we'll use the
circleci
join method)
- GitHub Actions (we'll use the
- a cloud VM on:
- AWS (we'll use the
aws
join method) - GCP (we'll use the
gcp
join method)
- AWS (we'll use the
Running the Terraform provider with native MachineID is supported on Azure, inside a Kubernetes pod,
and on servers with Trusted Platform Module (TPM). While those setups are not described in details in this guide,
you can follow their regular MachineID guides and replace the "Configure tbot
" step by passing the
join method and token to the provider.
HCP Terraform (Terraform Cloud) and self-hosted Terraform Enterprise are supported but require special configuration, so refer to our dedicated guide.
This guide does not cover running Teleport locally, on a dedicated server or on certain platforms. See the following more specific guides for those cases:
- Run the Terraform Provider locally
- Run the Teleport Terraform Provider on a server
- Run the Teleport Terraform Provider on Spacelift
How it works
This setup asks the runtime (the CI/CD system, cloud provider, container engine, ...) for an identity
proof. This proof is then used directly by the Terraform provider to connect to Teleport and obtain credentials.
In this setup, there is no tbot
daemon involved as the Terraform provider can natively obtain the identity proof
and join the Teleport cluster.
The setup only works for select runtimes which Teleport has a delegated join method for (e.g. GitHub Actions, GitLab CI, ...)
Prerequisites
You need either:
- A GCP or AWS VM with terraform installed
- A git repo able to run GitHub Actions, GitLab CI or CircleCI jobs
You also need:
-
A running Teleport cluster version 17.0.0-dev or above. If you want to get started with Teleport, sign up for a free trial or set up a demo environment.
-
The
tctl
admin tool andtsh
client tool.Visit Installation for instructions on downloading
tctl
andtsh
.
Step 1/4. Create the Terraform provider bot
In this step you will create a bot named terraform
.
Create a file named terraform-bot.yaml
:
kind: bot
version: v1
metadata:
name: terraform
spec:
# The terraform-provider is a default role shipped in Teleport granting access
# to every resource supported by the terraform provider.
roles: ["terraform-provider"]
Then apply it with tctl
:
$ tctl create terraform-bot.yaml
This is an admin-level action and requires MFA to complete
Tap any security key
Detected security key tap
bot "terraform" has been created
At this point, you should see your new bot:
$ tctl bots ls
Bot User Roles
--------- ------------- ------------------
terraform bot-terraform terraform-provider
Step 2/4. Create the bot join token
In this step you will create a token allowing a process to connect to Teleport as the terraform
bot you created
earlier.
The token type and configuration depends on where the Terraform provider is running. See the joining reference for more details about the joining process, the different join methods, types of tokens, and the fields they support.
- GitHub Actions
- GitLab CI
- CircleCI
- AWS
- GCP
To allow the Terraform Provider to join from GitHub Actions workflows in organization/repository,
create the following terraform-bot-token.yaml
:
kind: token
version: v2
metadata:
name: terraform-bot
spec:
roles: [Bot]
join_method: github
bot_name: terraform
github:
# allow specifies rules that control which GitHub Actions runs will be
# granted access. Those not matching any allow rule will be denied.
allow:
- repository: organization/repository
To allow the Terraform Provider to join from GitLab CI pipelines in group/project on
the gitlab.example.com GitLab instance, create the following terraform-bot-token.yaml
:
kind: token
version: v2
metadata:
name: terraform-bot
spec:
roles: [Bot]
join_method: gitlab
bot_name: terraform
gitlab:
# domain should be the domain of your GitLab instance. If you are using
# GitLab's cloud hosted offering, omit this field entirely.
domain: gitlab.example.com
# allow specifies rules that control which GitLab tokens will be accepted
# by Teleport. Tokens not matching any allow rule will be denied.
allow:
- project_path: group/project
In order to configure the rules for which CircleCI workflows will be allowed to connect to your Teleport cluster, you must determine the ID of your CircleCI organization and create a CircleCI context.
Find your organization ID
Open CircleCI and navigate to "Organization settings" from the navbar. You should be presented with an interface titled "Overview" with a section called "Organization ID". Note this value down and substitute organization-id in configuration examples with this.
Create a context
CircleCI has an organization-level concept called contexts, which allow you to configure a series of secrets that should be exposed to a workflow job. You can configure CircleCI to control which actors are allowed to trigger jobs associated with a context.
The contexts that a workflow job has been assigned are also encoded in the identity token that CircleCI creates for the job. This makes them an ideal way for Teleport to determine which CircleCI jobs should be granted access to the Teleport cluster.
In this example, you will create a CircleCI context named teleport-access
.
You will then grant this context access to your Teleport cluster.
To create the CircleCI context, open up "Organization settings" in CircleCI and navigate to "Contexts". Click "Create Context" and provide teleport-access as the name of the context you wish to create. You may substitute this value for a string that makes more sense to your organization, but ensure in future steps of this guide that you replace teleport-access with your value.
Select the context you have just created. You will now be on a page that allows you to configure the context. To determine the ID of the context to use when configuring Teleport, locate the URL of the context settings page, which should have a format similar to the following:
https://app.circleci.com/settings/organization/github/gravitational/contexts/00000000-0000-0000-0000-000000000000
In this case, the context ID is: 00000000-0000-0000-0000-000000000000
.
Note this value down and substitute context-id in configuration examples with this
Then, create the following terraform-bot-token.yaml
:
kind: token
version: v2
metadata:
name: terraform-bot
spec:
roles: [Bot]
join_method: circleci
bot_name: terraform
circleci:
organization_id: organization-id
# allow specifies the rules by which the Auth Server determines if `tbot`
# should be allowed to join.
allow:
- context_id: context-id
Make sure you have:
- An AWS IAM role that you wish to grant access to your Teleport cluster. This role must be granted
sts:GetCallerIdentity
. In this guide, this role will be named instance-iam-role. - An AWS EC2 virtual machine configured with the IAM role attached where you want to run the Terraform provider.
- The AWS account ID: 111111111111
Then, create the following terraform-bot-token.yaml
:
kind: token
version: v2
metadata:
name: terraform-bot
spec:
roles: [Bot]
bot_name: terraform
join_method: iam
allow:
- aws_account: "111111111111"
aws_arn: "arn:aws:sts::organization-id:assumed-role/instance-iam-role/i-*"
Make sure you have:
- A GCP Service Account (SA) attached to the VM you want to run the provider on. This cannot be the default compute SA. In this guide, this SA will be named my-service-account.
- The GCP project ID: my-project-123456
Then, create the following terraform-bot-token.yaml
:
kind: token
version: v2
metadata:
name: terraform-bot
spec:
roles: [Bot]
bot_name: terraform
join_method: gcp
gcp:
allow:
- project_ids:
- "my-project-123456"
service_accounts:
- "my-service-account@my-project-123456.iam.gserviceaccount.com"
Create the bot token described by the terraform-bot-token.yaml
manifest:
$ tctl create -f terraform-bot-token.yaml
This is an admin-level action and requires MFA to complete
Tap any security key
Detected security key tap
provision_token "terraform-bot" has been created
Step 3/4. Configure your Terraform provider
In this step you will write a minimal Terraform code that configures the provider to connect to your Teleport cluster and join with the token you previously created.
To do this you need:
- your Teleport cluster domain including the port: teleport.example.com:443. You can find this in the URL when accessing the Web UI.
- the join method of the token you've created. This is the
spec.join_method
field in theterraform-bot-token.yaml
: token-join-method.
Create this minimal main.tf
file:
terraform {
required_providers {
teleport = {
source = "terraform.releases.teleport.dev/gravitational/teleport"
version = "~> 17.0"
}
}
}
provider "teleport" {
addr = "teleport.example.com:443"
join_method = "token-join-method"
join_token = "terraform-bot"
}
# We must create a test role, if we don't declare resources, Terraform won't try to
# connect to Teleport and we won't be able to validate the setup.
resource "teleport_role" "test" {
version = "v7"
metadata = {
name = "test"
description = "Dummy role to validate Terraform Provider setup"
labels = {
test = "yes"
}
}
spec = {}
}
- GitHub Actions
- GitLab CI
- CircleCI
- AWS
- GCP
Copy the main.tf
file in the GitHub repo that runs GitHub Actions pipelines.
Copy the main.tf
file in the GitLab repo that runs GitLab CI pipelines.
Copy the main.tf
file in the Git repo that runs CircleCI pipelines.
Copy the main.tf
file on the AWS VM you will run Terraform from.
Copy the main.tf
file on the GCP VM you will run Terraform from.
Step 4/4. Run Terraform
This step shows minimal examples on how to run Terraform based on your environment. This code uses the default local backend which is not fit for production purposes. Especially in CI, you must use non-local Terraform backends so the Terraform state is persisted across CI pipelines.
- GitHub Actions
- GitLab CI
- CircleCI
- AWS
- GCP
In the repo containing your Terraform code, create a .github/workflows/teleport-terraform.yaml
file with the
following content:
name: Teleport Terraform Demo
# This is a basic workflow to help you get started.
# It will take the following action whenever a push is made to the "main" branch.
on:
push:
branches:
- main
jobs:
demo:
permissions:
# The "id-token: write" permission is required or Machine ID will not be
# able to authenticate with the cluster.
id-token: write
contents: read
name: terraform-plan
runs-on: ubuntu-latest
# You can find more advanced TF workflows at https://github.com/hashicorp/setup-terraform
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- name: Terraform Init
id: init
run: terraform init
- name: Terraform Plan
id: plan
run: terraform plan -no-color
Commit the changes and push to the main
branch to trigger the GitHub Actions workflow.
You should see a successful Terraform plan in the workflow logs.
Recover your cluster name:
$ tctl status
Cluster teleport.example.com
Version 16.2.0
# ...
In the repo containing your Terraform code, create the .gitlab-ci.yaml
file if it does exist, and add the following
content:
stages:
- plan
image:
name: hashicorp/terraform:1.9
entrypoint: [""]
terraform-job:
stage: plan
# id_tokens configures ID Tokens that GitLab will automatically inject into
# the environment of your GitLab run.
#
# See https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html
# for further explanation of the id_tokens configuration in GitLab.
id_tokens:
TBOT_GITLAB_JWT:
# aud for TBOT_GITLAB_JWT must be configured with the name of your
# Teleport cluster. This is not necessarily the address of your Teleport
# cluster and will not include a port or scheme (http/https)
#
# This helps the Teleport Auth Server know that the token is intended for
# it, and not a different service or Teleport cluster.
aud: "teleport.example.com"
script:
- terraform init
- terraform plan
Commit the changes and push to any branch to trigger a Gitlab CI pipeline. You should see a successful Terraform plan in the pipeline logs.
In the repo containing your Terraform code add the following CircleCI config in .circleci/config.yml
:
version: '2.1'
orbs:
terraform: circleci/terraform@3.1
workflows:
deploy_infrastructure:
jobs:
- terraform/init:
tag: 1.9.5
checkout: true
context: teleport-access
- terraform/plan:
tag: 1.9.5
context: teleport-access
requires:
- terraform/init
Commit the changes and push to any branch to trigger a CircleCI pipeline. You should see a successful Terraform plan in the pipeline logs.
Run the Terraform commands on the EC2 instance:
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding terraform.releases.teleport.dev/gravitational/teleport versions matching ...
$ terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# teleport_role.test will be created
+ resource "teleport_role" "test" {
+ id = (known after apply)
+ kind = (known after apply)
+ metadata = {
+ name = "test"
+ namespace = (known after apply)
}
+ spec = {}
+ version = "v7"
}
Plan: 1 to add, 0 to change, 0 to destroy.
Run the Terraform commands on the GCP VM:
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding terraform.releases.teleport.dev/gravitational/teleport versions matching ...
$ terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# teleport_role.test will be created
+ resource "teleport_role" "test" {
+ id = (known after apply)
+ kind = (known after apply)
+ metadata = {
+ name = "test"
+ namespace = (known after apply)
}
+ spec = {}
+ version = "v7"
}
Plan: 1 to add, 0 to change, 0 to destroy.