[Infrastructure as Code (IaC)] Manage Teleport with Terraform Teleport Provider

Terraform Teleport Provider

Terraform is an open-source infrastructure as code software tool that provides a consistent CLI workflow to manage hundreds of cloud services. Terraform codifies cloud APIs into declarative configuration files.

Teleport is a Certificate Authority and an Access Plane for your infrastructure. With Teleport you can:

Terraform relies on plugins called “providers” to interact with cloud providers, SaaS providers, and other APIs.

Terraform configurations must declare which providers they require so that Terraform can install and use them. Additionally, some providers require configuration (like endpoint URLs or cloud regions) before they can be used.

This article describe how to use Terraform to manage Teleport resources.

Prerequsites

Usages

Step 1/4. Install the Terraform provider

Create a folder teleport-terraform to hold some temporary files:

1
2
3
$ mkdir -p teleport-terraform

$ cd teleport-terraform

Then, install the Terraform provider.

1
2
3
4
5
6
7
8
9
10
11
12
13
# MacOS
$ mkdir -p ${HOME?}/.terraform.d/plugins/gravitational.com/teleport/teleport/9.0.3/darwin_amd64

$ curl -L -O https://get.gravitational.com/terraform-provider-teleport-v9.0.3-darwin-amd64-bin.tar.gz

$ tar -zxvf terraform-provider-teleport-v9.0.3-darwin-amd64-bin.tar.gz -C ${HOME?}/.terraform.d/plugins/gravitational.com/teleport/teleport/9.0.3/darwin_amd64

# # Linux
# $ mkdir -p ${HOME?}/.terraform.d/plugins/gravitational.com/teleport/teleport/9.0.3/linux_amd64

# $ curl -L -O https://get.gravitational.com/terraform-provider-teleport-v9.0.3-linux-amd64-bin.tar.gz

# $ tar -zxvf terraform-provider-teleport-v9.0.3-linux-amd64-bin.tar.gz -C ${HOME?}/.terraform.d/plugins/gravitational.com/teleport/teleport/9.0.3/linux_amd64

Step 2/4. Create a Terraform user

Enable impersonation

In order for Terraform to manage resources in your Teleport cluster, it needs a signed identity file from the cluster’s certificate authority. The Terraform user cannot request this itself, and requires another user to impersonate this account in order to request a certificate.

Create a role that enables your user to impersonate the Terraform user. First, paste the following YAML document into a file called terraform-impersonator.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# terraform-impersonator.yaml

kind: role
version: v5
metadata:
name: terraform-impersonator
spec:
# SSH options used for user sessions
options:
# max_session_ttl defines the TTL (time to live) of SSH certificates
# issued to the users with this role.
max_session_ttl: 10h

# The allow section declares a list of resource/verb combinations that are
# allowed for the users of this role. By default, nothing is allowed.
allow:
impersonate:
users: ['terraform']
roles: ['terraform']

# The deny section uses the identical format as the 'allow' section.
# Deny rules always override allow rules.
deny:
node_labels:
'*': '*'

Next, create the role:

1
$ tctl create terraform-impersonator.yaml

Assign this role to the current user. Log in to your Teleport cluster to assume the new role.

Create the Terraform user

Put the following content into terraform.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# terraform.yaml

kind: role
metadata:
name: terraform
spec:
allow:
rules:
- resources: ['user', 'role', 'token', 'trusted_cluster', 'github', 'oidc', 'saml']
verbs: ['list','create','read','update','delete']
version: v5
---
kind: user
metadata:
name: terraform
spec:
roles: ['terraform']
version: v2

Create the terraform user and role.

1
$ tctl create terraform.yaml

Next, request a signed certificate for the Terraform user:

Self-Hosted
1
2
3
4
5
# Self-Hosted
$ tctl auth sign --format=tls --user=terraform --out=auth

# Teleport Cloud
# $ tctl auth sign --user=terraform --out=terraform-identity

This command should result in three PEM-encoded files: auth.crt, auth.key, and auth.cas (certificate, private key, and CA certs, respectively).

Teleport Cloud
1
$ tctl auth sign --user=terraform --out=terraform-identity

The above sequence should result in one PEM-encoded file: terraform-identity.

Step 3/4. Create a Terraform configuration

Paste the following into a file called main.tf to define an example user and role using Terraform.

Teleport Cloud

Self-Hosted

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# main.tf

terraform {
required_providers {
teleport = {
version = ">= 9.0.3"
source = "gravitational.com/teleport/teleport"
}
}
}

provider "teleport" {
# Update addr to point to Teleport Auth/Proxy
# addr = "auth.example.com:3025"
addr = "proxy.example.com:443"
cert_path = "auth.crt"
key_path = "auth.key"
root_ca_path = "auth.cas"
}

resource "teleport_role" "terraform-test" {
metadata {
name = "terraform-test"
description = "Terraform test role"
labels = {
example = "yes"
}
}

spec {
options {
forward_agent = false
max_session_ttl = "30m"
port_forwarding = false
client_idle_timeout = "1h"
disconnect_expired_cert = true
permit_x11_forwarding = false
request_access = "denied"
}

allow {
logins = ["this-user-does-not-exist"]

rules {
resources = ["user", "role"]
verbs = ["list"]
}

request {
roles = ["example"]
claims_to_roles {
claim = "example"
value = "example"
roles = ["example"]
}
}

node_labels {
key = "example"
value = ["yes"]
}
}

deny {
logins = ["anonymous"]
}
}
}

resource "teleport_user" "terraform-test" {
metadata {
name = "terraform-test"
description = "Test terraform user"
expires = "2022-10-12T07:20:50.52Z"

labels = {
test = "true"
}
}

spec {
roles = ["terraform-test"]
}
}

Teleport Cloud

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# main.tf

terraform {
required_providers {
teleport = {
version = ">= 9.0.3"
source = "gravitational.com/teleport/teleport"
}
}
}

provider "teleport" {
# Update addr to point to your Teleport Cloud tenant URL
addr = "mytenant.teleport.sh"
identity_file_path = "terraform-identity"
}

resource "teleport_role" "terraform-test" {
metadata {
name = "terraform-test"
description = "Terraform test role"
labels = {
example = "yes"
}
}

spec {
options {
forward_agent = false
max_session_ttl = "30m"
port_forwarding = false
client_idle_timeout = "1h"
disconnect_expired_cert = true
permit_x11_forwarding = false
request_access = "denied"
}

allow {
logins = ["this-user-does-not-exist"]

rules {
resources = ["user", "role"]
verbs = ["list"]
}

request {
roles = ["example"]
claims_to_roles {
claim = "example"
value = "example"
roles = ["example"]
}
}

node_labels {
key = "example"
value = ["yes"]
}
}

deny {
logins = ["anonymous"]
}
}
}

resource "teleport_user" "terraform-test" {
metadata {
name = "terraform-test"
description = "Test terraform user"
expires = "2022-10-12T07:20:50.52Z"

labels = {
test = "true"
}
}

spec {
roles = ["terraform-test"]
}
}

Step 4/4. Apply the configuration

Check the contents of the teleport-terraform folder:

Self-Hosted

1
2
$ ls
main.tf auth.crt auth.key auth.cas terraform-impersonator.yaml terraform.yaml

Teleport Cloud

1
2
$ ls
main.tf terraform-identity terraform-impersonator.yaml terraform.yaml

Init terraform and apply the spec:

1
2
3
$ terraform init

$ terraform apply

References

[1] Terraform Provider | Teleport Docs - https://goteleport.com/docs/setup/guides/terraform-provider/

[2] Terraform by HashiCorp - https://www.terraform.io/

[3] Teleport: Easiest, most secure way to access infrastructure | Teleport - https://goteleport.com/