Managing Users And Roles With IaC
In this guide, you will see how to create users and grant them roles through infrastructure as code (IaC). Teleports supports three ways to dynamically create resources from code:
- The Teleport Kubernetes Operator, which allows you to manage Teleport resources from Kubernetes
- The Teleport Terraform Provider, which allows you to manage Teleport resources via Terraform
- The
tctl
CLI, which allows you to manage Teleport resources from your local computer or your CI environment
Prerequisites
To follow this guide, you must have:
- tctl
- Kubernetes Operator
- Terraform
-
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
.
A running operator by following either:
- the guide to enable the operator in the
teleport-cluster
Helm chart. - the guide to setup a standalone operator.
You must also set the namespace in which you deployed the operator as this is the namespace where you will deploy the CustomResources:
# for operators deployed with the `teleport-cluster` Helm chart
$ export OPERATOR_NAMESPACE="teleport-cluster"
# for standalone operators
$ export OPERATOR_NAMESPACE="teleport-iac"
A functional Teleport Terraform provider by following the Terraform provider guide.
Step 1/4. Write manifests
In this step, we'll write text files describing the resources we want in Teleport. Those files are called manifests and their syntax will vary based on the IaC tooling you'll use.
Those manifests are typically versioned in a shared revision system like git. This allows you to keep track of all changes, follow standard code review procedures before changing resources in Teleport, and quickly redeploy your Teleport instance if needed.
Write role manifests
We will create 2 roles:
manager
allows listing users and roles, as well as reviewing audit events and session contents.engineer
grants access to dev and staging servers.
- tctl
- Kubernetes Operator
- Terraform
Create the following roles.yaml
file:
kind: role
version: v7
metadata:
name: manager
spec:
allow:
rules:
- resources: ['user', 'role']
verbs: ['list','read']
- resources: ['session', 'event']
verbs: ['list', 'read']
---
kind: role
version: v7
metadata:
name: engineer
spec:
allow:
logins: ['root', 'ubuntu', '{{internal.logins}}']
node_labels:
'env': ['test', 'staging']
Create the following roles.yaml
file:
apiVersion: resources.teleport.dev/v1
kind: TeleportRoleV7
metadata:
name: manager
spec:
allow:
rules:
- resources: ['user', 'role']
verbs: ['list','read']
- resources: ['session', 'event']
verbs: ['list', 'read']
---
apiVersion: resources.teleport.dev/v1
kind: TeleportRoleV7
metadata:
name: engineer
spec:
allow:
logins: ['root', 'ubuntu', '{{internal.logins}}']
node_labels:
'env': ['test', 'staging']
Kubernetes validates all custom resource names to follow RFC 1123, which
includes specifications for hostnames. This requires the metadata.name
field
of Teleport resources controlled by the operator to consist of lowercase
alphanumeric characters, -
or .
, and to start and end with an alphanumeric
character.
Create the following roles.tf
file:
resource "teleport_role" "manager" {
version = "v7"
metadata = {
name = "manager"
}
spec = {
allow = {
rules = [
{
resources = ["user", "role"]
verbs = ["list", "read"]
},
{
resources = ["session", "event"]
verbs = ["list", "read"]
}
]
}
}
}
resource "teleport_role" "engineer" {
version = "v7"
metadata = {
name = "engineer"
}
spec = {
allow = {
logins = ["root", "ubuntu", "{{internal.logins}}"]
node_labels = {
env = ["test", "staging"]
}
}
}
}
Write user manifests
We will create 2 users:
- Bob, an engineer with the
engineer
role. - Alice, an engineering manager with both
manager
andengineer
roles.
Users created from manifests are local users, as opposed to users coming from an external SAML/OIDC/GitHub Identity Provider (IdP).
See the user type reference for more details.
- tctl
- Kubernetes Operator
- Terraform
Create the file users.yaml
with the following content:
kind: user
version: v2
metadata:
name: alice
spec:
roles: ['manager', 'engineer']
---
kind: user
version: v2
metadata:
name: bob
spec:
roles: ['engineer']
Create the file users.yaml
with the following content:
apiVersion: resources.teleport.dev/v2
kind: TeleportUser
metadata:
name: alice
spec:
roles: ['manager', 'engineer']
---
apiVersion: resources.teleport.dev/v2
kind: TeleportUser
metadata:
name: bob
spec:
roles: ['engineer']
Kubernetes validates all custom resource names to follow RFC 1123, which
includes specifications for hostnames. This requires the metadata.name
field
of Teleport resources controlled by the operator to consist of lowercase
alphanumeric characters, -
or .
, and to start and end with an alphanumeric
character.
Create the file users.tf
with the following content:
resource "teleport_user" "alice" {
version = "v2"
metadata = {
name = "alice"
}
spec = {
# referencing to the teleport_role resource name instead of using plain
# strings tells Terraform that the user depends on the role. Thanks to this,
# Terraform will create the role first and won't let you remove the role
# if it is still assigned to a user (which is illegal in Teleport).
roles = [
teleport_role.manager.metadata.name,
teleport_role.engineer.metadata.name,
]
}
}
resource "teleport_user" "bob" {
version = "v2"
metadata = {
name = "bob"
}
spec = {
roles = [teleport_role.engineer.metadata.name]
}
}
Step 2/4. Apply all manifests
- tctl
- Kubernetes Operator
- Terraform
$ tctl create -f roles.yaml
role 'manager' has been created
role 'engineer' has been created
$ tctl create -f users.yaml
user "alice" has been created
user "bob" has been created
The user resource depends on roles, you must create roles before users as a user with a non-existing role is invalid and might be rejected by Teleport.
$ kubectl apply -n "$OPERATOR_NAMESPACE" -f roles.yaml
teleportrolev7.resources.teleport.dev/manager created
teleportrolev7.resources.teleport.dev/engineer created
$ kubectl apply -n "$OPERATOR_NAMESPACE" -f users.yaml
teleportuser.resources.teleport.dev/alice created
teleportuser.resources.teleport.dev/bob created
List the created Kubernetes resources:
$ kubectl get teleportrolev7 -n "$OPERATOR_NAMESPACE"
# NAME AGE
# engineer 10m
# manager 10m
$ kubectl get teleportusers -n "$OPERATOR_NAMESPACE"
# NAME AGE
# alice 10m
# bob 10m
$ terraform plan
[...]
Plan: 4 to add, 0 to change, 0 to destroy.
$ terraform apply
teleport_role.engineer: Creating...
teleport_role.manager: Creating...
teleport_role.engineer: Creation complete after 0s [id=engineer]
teleport_role.manager: Creation complete after 0s [id=manager]
teleport_user.bob: Creating...
teleport_user.alice: Creating...
teleport_user.bob: Creation complete after 0s [id=bob]
teleport_user.alice: Creation complete after 0s [id=alice]
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Step 3/4. Validate users were created
Now that the IaC tooling has run, we'll validate that the users were properly created and granted the correct roles.
- Via the UI
- Via CLI
If you have UI access, connect to your Teleport cluster Web UI, open the management panel, and select the "Users" tab.
Two new users alice
and bob
should be present.
$ tctl users ls
User Roles
----------------------------- -------------------------
@teleport-access-approval-bot @teleport-access-approver
alice manager,engineer
bob engineer
bot-operator bot-operator
# alternatively you can inspect the users details by doing
$ tctl get user/alice
kind: user
metadata:
id: 1704849160091933780
labels:
teleport.dev/origin: kubernetes
name: alice
spec:
created_by:
time: "2024-01-10T01:12:40.088581806Z"
user:
name: bot-operator
expires: "0001-01-01T00:00:00Z"
roles:
- manager
- engineer
status:
is_locked: false
lock_expires: "0001-01-01T00:00:00Z"
locked_time: "0001-01-01T00:00:00Z"
recovery_attempt_lock_expires: "0001-01-01T00:00:00Z"
version: v2
Step 4/4. Create a password reset link
At this point, the local users have been created in Teleport. However, we never specified any password or additional authentication factors. You must issue a password reset link for the users to finish their Teleport registration and be able to log in Teleport.
User reset links contain single-use expiring tokens. Because of this, you cannot follow the same declarative approach as for other Teleport resources and generate them via a manifest. You need to create those tokens once after the user creation, and securely send them to the end-user for them to register their password/MFA.
Option 1: Reset via CLI
You can manually reset a user password via tctl
by doing:
$ tctl users reset alice
User "alice" has been reset. Share this URL with the user to complete password reset, link is valid for 8h:
https://teleport.example.com:443/web/reset/05b420fdc784597cbbb1d2ba65697cd8
NOTE: Make sure teleport.example.com:443 points at a Teleport proxy which users can access.
Option 2: Automating user reset
If you have a way to securely send reset links to the users, you can build automation to fit your organization's specific needs. For example:
$ tctl users reset alice --format=json | \
jq '"Sending an email to " + .spec.user +" that contains the link: " + .spec.url'
You must replace the jq
command by something that actually sends the link over
a secure channel. This channel will depend on your organization. It is usually a
direct message or an email.
You can trigger your custom script on Terraform resource creation with
the local-exec
provisioner.
resource "teleport_user" "bob" {
version = v2
metadata = {
name = "bob"
}
spec = {
roles = [teleport_role.engineer.metadata.name]
}
# on user creation, trigger a reset flow and send the link via
provisioner "local-exec" {
command = "tctl users reset alice --format=json | jq '\"Sending an email to \" + .spec.user +\" that contains the link: \" + .spec.url'"
}
}
Next steps
- Allow users with the
manager
role to grant access to production servers to someengineers
via Access Lists. Manager will need to justify and review granted access periodically. See the AccessList documentation for a high-level explanation of the feature, and the AccessList IaC guide for a step by step IaC AccessList setup. - Allow users with the
engineer
role to request temporary access to production, and have users with themanager
role validate the requests. See the Access Requests documentation - You can see all supported fields in the references of the user resource and the role resource.