Scaling Privileged Access for Modern Infrastructure: Real-World Insights
Apr 25
Virtual
Register Today
Teleport logoTry For Free
Fork me on GitHub

Teleport

Login Rules Reference

This page provides details on the expression language that powers Login Rules. To learn how to add the first login rule to your cluster, checkout out the Login Rules Guide.

YAML specification

kind: login_rule
version: v1
metadata:
  # name is a unique name for the Login Rule in the cluster.
  name: example

  # expires is optional and usually should not be set for deployed login
  # rules, but it can be useful to set an expiry a short time in the future
  # while testing new Login Rules to prevent potentially locking yourself out of
  # your teleport cluster.
  # expires: "2023-01-31T00:00:00-00:00"
spec:
  # priority can be used to order the evaluation of multiple Login Rules within
  # a cluster.
  #
  # Login Rules with lower numbered priorities will be applied first, followed
  # by rules with priorities in increasing order. In case of a tie, Login Rules
  # with the same priority will be ordered by a lexicographical sort of their
  # names.
  #
  # The default value is 0, the supported range is -2147483648 to 2147483647
  # (inclusive).
  priority: 0

  # If set, traits_map will determine the traits of all users who log in to the
  # cluster.
  #
  # This is a YAML map where the key must be a static string which will be the
  # final trait key, and the value is a list of predicate expressions which each
  # must evaluate to a set of strings. The final trait will be set to the union
  # of the resulting string sets of all predicate expressions for that trait
  # key.
  #
  # traits_map must contain the complete set of desired traits. Any external
  # traits not found here will not be included in the user's certificates.
  #
  # Exactly one of traits_map or traits_expression must be set.
  traits_map:
    logins:
      - external.groups
    logins:
      - strings.lower(external.username)

  # traits_expression is a string holding a single predicate expression which
  # must evaluate to a dict. This will set all user's traits during login.
  #
  # Exactly one of traits_map or traits_expression must be set.
  traits_expression: |
    external.put("logins", strings.lower(external.logins))

traits_map vs traits_expression

Every login rule spec must contain either the traits_map field or a traits_expression field.

They both serve the same purpose of transforming user traits. The logic difference lies only in the syntax you prefer for your use case, since you can write every traits_map as an equivalent traits_expression.

traits_map will remove any traits not specifically included, while the traits_expression syntax allows you add or modify only specific traits while keeping the rest unchanged. The traits_map behavior can be useful if you want to keep only a handful of necessary traits while filtering out all others. If lower priority Login Rules set traits, those traits must be also included with higher priority traits_map to remain populated. For example, the following configuration keeps the groups trait unmodified.

  traits_map:
    groups:
      - external["groups"]

traits_map

Here is an example Login Rule that uses a traits_map to implement the following rules:

  • Every user with the groups: devs trait should receive an extra trait access: [staging].
  • Every user with the groups: admins trait should receive an extra trait access: [staging, prod].
  • Every user should receive a logins trait with the value of their incoming username trait converted to lowercase.
  • All traits other than groups, logins, and access should be filtered out.
kind: login_rule
version: v1
metadata:
  name: my_expression_rule
spec:
  priority: 0

  traits_map:
    # the groups trait will be copied unmodified. Do the same for all other
    # traits which should not be changed, any traits omitted here will *not* be
    # set for your users and will *not* be used for role mapping.
    groups:
      - external["groups"]

    # the logins traits will be set to the username trait converted to
    # lowercase.
    logins:
      - 'strings.lower(external.username)'

    # the access trait is determined conditionally based on the incoming groups trait.
    access:
      - 'ifelse(external.groups.contains("devs"), set("staging"), set())'
      - 'ifelse(external.groups.contains("admins"), set("staging", "prod"), set())'

traits_expression

Here is an example login rule using the traits_expression field implementing the same rules as the above example:

kind: login_rule
version: v1
metadata:
  name: my_expression_rule
spec:
  priority: 0

  traits_expression: |
    dict(
      pair("groups", external.groups),
      pair("logins", strings.lower(external.username)),
      pair("access",
        choose(
          option(external.groups.contains("devs"), set("staging")),
          option(external.groups.contains("admins"), set("staging", "prod")),
          option(true, set()),
        ),
      ),
    )

Every traits expression must return a value of type dict which will be used as the complete set of output traits. It is possible to construct a dict from scratch as shown above, or you can make modifications to the incoming traits stored in the external dict like the following:

kind: login_rule
version: v1
metadata:
  name: uppercase_logins
spec:
  priority: 0

  # This example expression will return all incoming traits unmodified except
  # for the "logins" trait which will be converted to lowercase.
  traits_expression: |
    external.put("logins", strings.lower(external.logins))

dict type

Description

dict is a dictionary type mapping from string keys to set values. When Login Rule expressions access input traits with the external.<trait> or external[<trait>] syntax, external is a value of type dict. Values of type dict can also be constructed and accessed within expressions. Expressions used for the traits_expression field must return a value of type dict.

Constructor

Signature

func dict(pairs ...pair) dict

Description

The dict constructor returns a new dict populated with initial key-value pairs from the pairs argument. Each pair must hold a string and a set.

Arguments

ArgumentTypeDescription
pairs...pairZero or more key-value pairs to initialize the dict.

Returns

TypeDescription
dictA new dict.

Examples

ExpressionResult
dict(){}
dict(pair("a", set("x", "y"))){"a": ("x", "y")}

Accessors

SyntaxExampleDescription
dict.keyexternal.usernameThe "dot" accessor returns the set for the given key, or the empty set if there is not value for that key.
dict["key"]external["user-name"]The square brace accessor has the same behavior as the "dot" accessor, but supports keys with special characters (including -, ., , etc) which must be quoted for parsing.

dict.add_values

Signature

func (dict) add_values(key string, values ...string) dict

Description

dict.add_values returns a copy of the dict with the given values added to the set at dict[key]. If there is no set already present at dict[key] a new one will be created.

Arguments

ArgumentTypeDescription
keystringKey where the new values should be added.
values...stringOne or more string values to add at dict[key].

Returns

TypeDescription
dictA copy of the given dict with values added at key key.

Examples

ExpressionResult
dict().add_values("logins", "ubuntu", "ec2-user"){"logins": ("ubuntu", "ec2-user")}
dict(pair("a", set("x"))).add_values("a", "y", "z"){"a": ("x", "y", "z")}

dict.remove

Signature

func (dict) remove(keys ...string) dict

Description

dict.remove returns a copy of the dict with the given keys removed. Any given keys not present in the dict have no effect.

Arguments

ArgumentTypeDescription
keys...stringOne or more keys to remove from the dict.

Returns

TypeDescription
dictA copy of the given dict with given keys removed.

Examples

ExpressionResult
dict(pair("a", set("x"))).remove("a", "b"){}
dict(pair("a", set("x")), pair("b", set("c"))).remove("b"){"a": ("x")}

dict.put

Signature

func (dict) put(key string, value set) dict

Description

dict.put returns a copy of the dict with dict[key] set to value. If there is already a value present for the given key it is overwritten.

Arguments

ArgumentTypeDescription
keystringkey at which to set the new value
valuesetset of strings to set at the given key

Returns

TypeDescription
dicta copy of the given dict with dict[key] set to value.

Examples

ExpressionResult
dict(pair("a", set("x"))).put("a", set("y")){"a": ("y")}
dict().put("b", set("z")){"b": ("z")}

set type

Description

set holds a set of unique strings.

Constructor

Signature

func set(values ...string) set

Description

The set constructor returns a new set initialized with the given values.

Arguments

ArgumentTypeDescription
values...stringZero or more strings to initialize the set.

Returns

TypeDescription
setA new set initialized with the given values.

Examples

ExpressionResult
set()()
set("a", "b", "a")("a", "b")

set.contains

Signature

func (set) contains(value) bool

Description

set.contains returns true if the set contains an exact match for value, else it returns false.

Arguments

ArgumentTypeDescription
valuestringA string to check for in the set.

Returns

TypeDescription
booltrue if the set contains an exact match for value, else false.

Examples

ExpressionResult
set("a", "b").contains("a")true
set("a", "b").contains("x")false

set.add

Signature

func (set) add(values ...string) set

Description

set.add returns a new set that is a copy of the given set with the new values added.

Arguments

ArgumentTypeDescription
values...stringValues to add to the set.

Returns

TypeDescription
setA new set that is a copy of the given set with values added.

Examples

ExpressionResult
set("a", "b").add("b", "c")("a", "b", "c")

set.remove

Signature

func (set) remove(values ...string) set

Description

set.remove returns a new set that is a copy of the given set with all values removed.

Arguments

ArgumentTypeDescription
values...stringValues to remove from the set.

Returns

TypeDescription
setA new set that is a copy of the given set with values removed.

Examples

ExpressionResult
set("a", "b").remove("b", "c")("a")

pair type

Description

pair can hold two values of any type. Currently its only use is in the dict constructor where it must hold key-value pairs of type string and set.

Constructor

Signature

func pair(first, second any) pair

Description

The pair constructor returns a new pair holding first and second.

Arguments

ArgumentTypeDescription
firstanyA value of any type.
secondanyA value of any type.

Returns

TypeDescription
pairA new pair holding first and second.

Examples

ExpressionResult
pair("logins", set("root", "user")){"logins", ("root", "user")}

option type

Description

option is meant to be used exclusively as an argument to choose. It holds a Boolean condition that may cause the option to be selected and a value which should be returned by the choose expression if that option is in fact selected.

Constructor

Signature

func option(cond bool, value any) option

Description

Returns a new option holding cond and value.

Arguments

ArgumentTypeDescription
condboolA Boolean condition which may cause this option to be selected.
valueanyA value which should be returned by choose if this option is selected.

Returns

TypeDescription
optionAn option type which should be passed as an argument to choose.

Examples

See the examples for choose.

Helper functions

strings.upper

Signature

func strings.upper(input set) set

Description

strings.upper returns a copy of the given set of strings converted to uppercase.

Arguments

ArgumentTypeDescription
inputsetset of input strings to convert to uppercase

Returns

TypeDescription
seta copy of input where each string has been converted to uppercase

Examples

ExpressionResult
strings.upper(set("Alice"))("ALICE")
strings.upper(set("AbCdE", "fGhIj))("ABCDE", "FGHIJ")

strings.lower

Signature

func strings.lower(input set) set

Description

strings.lower returns a copy of the given set of strings converted to lowercase.

Arguments

ArgumentTypeDescription
inputsetset of input strings to convert to lowercase

Returns

TypeDescription
seta copy of input where each string has been converted to lowercase

Examples

ExpressionResult
strings.lower(set("Alice"))("alice")
strings.lower(set("AbCdE", "fGhIj))("abcde", "fghij")

strings.replaceall

Signature

func strings.replaceall(input set, match string, replacement string) set

Description

strings.replaceall implements substring replacement on sets of strings. The return value is a copy of input where each substring match of match found in each element of input will be replaced with replacement. The matching is literal and does not support regular expressions.

Arguments

ArgumentTypeDescription
inputsetset of input strings where replacements are needed
matchstringliteral substring to be replaced
replacementstringliteral string to replace all instances of match

Returns

TypeDescription
seta copy of input where each instance of match found in each element of input has been replaced with replacement.

Examples

ExpressionResult
strings.replaceall(set("user-name"), "-", "_")("user_name")
strings.replaceall(set("user-alice", "user-bob"), "user-", "")("alice", "bob")

strings.split

Note

The strings.split helper was introduced in Teleport v13.3.0. All Auth Service instances must be running this version or greater before it can be used.

Signature

func strings.split(input set, separator string) set

Description

strings.split splits each element of input at each match of separator and returns a set containing the union of all split strings. This may be useful when an IdP does not have the ability to pass multi-valued claims, a Login Rule with this helper function can split a single claim value into a Teleport trait with multiple values.

Arguments

ArgumentTypeDescription
inputsetset of input strings which should be split
sepstringliteral string separator

Returns

TypeDescription
setthe union of all split strings

Examples

ExpressionResult
strings.split(set("alice,bob,charlie"), ",")("alice", "bob", "charlie")
strings.split(set("devs security"), " ")("devs", "security")

email.local

Note

The email.local helper was introduced in Teleport v13.3.0. All Auth Service instances must be running this version or greater before it can be used.

Signature

func email.local(input set) set

Description

email.local maps each email in the input set to its local part.

Arguments

ArgumentTypeDescription
inputsetset of input emails

Returns

TypeDescription
seta copy of input where each email has been converted to its local part.

Examples

ExpressionResult
email.local(set("[email protected]"))("alice")
email.local(set("Alice <[email protected]>"))("alice")

regexp.replace

Note

The regexp.replace helper was introduced in Teleport v13.3.0. All Auth Service instances must be running this version or greater before it can be used.

Signature

func regexp.replace(input set, expression string, replacement string) set

Description

regexp.replace finds all matches of expression in each element of input and replaces them with replacement. Values which do not match the expression will be filtered out. The replacement supports expansion of capture groups from expression. $N is used to refer to the Nth captured group, starting at $1.

Arguments

ArgumentTypeDescription
inputsetset of input strings

Returns

TypeDescription
seta copy of input where each string has had all matches of expression replaced with replacement.

Examples

ExpressionResult
regexp.replace(set("team-devs"), "^team-(.*)$", "$1")("devs")
regexp.replace(set("team-dev-security"), "^team-(.*)-(.*)$", "$1.$2")("dev.security")

ifelse

Signature

func ifelse(cond bool, valueIfTrue any, valueIfFalse any) any

Description

ifelse implements the classic if-else branch in a pure functional style. If the first argument evaluates to true the second argument is returned, else the third argument is returned.

Arguments

ArgumentTypeDescription
condboolA Boolean condition that determines which of the following two arguments is returned.
valueIfTrueanyThe value to return if cond is true, of any type.
valueIfFalseanyThe value to return if cond is false, of any type.

Returns

TypeDescription
anyThe second or third argument will be returned.

Examples

ExpressionResult
ifelse(set("a", "b").contains("a"), set("x", "y"), set("z"))("x", "y")
ifelse(set("a", "b").contains("c"), set("x", "y"), set("z"))("z")

choose

Signature

func choose(options ...option) any

Description

choose implements a functional style of switch statement, returning the first option argument with a condition evaluating to true.

If no option can be selected at runtime, this will return an error and the login will not succeed. It is recommended to add a final option with the condition hardcoded to true to implement a default option and avoid this scenario. For example choose(..., option(true, set())) would return the empty set if no other option can be selected.

Arguments

ArgumentTypeDescription
options...optionOne or more options.

Returns

TypeDescription
anyThe value of the first option argument with a condition evaluating to true, which may be of any type.

Examples

ExpressionResult
choose(option(false, set("x")), option(true, set("y")), option(true, set("z")))("y")
choose(option(set("a", "b").contains("a"), set("x")), option(true, set("y")))("x")

union

Signature

func union(sets ...set) set

Description

union returns a new set containing the union of all elements in the given sets.

Arguments

ArgumentTypeDescription
sets...setZero or more sets to union.

Returns

TypeDescription
setA new set containing the union of all given sets.

Examples

ExpressionResult
union(set("a"), set("b"))("a", "b")
union(set("a", "b"), set("b", "c"))("a", "b", "c")