diff --git a/docs/pages/access-controls/reference.mdx b/docs/pages/access-controls/reference.mdx index 64f70654605e9..281480195623b 100644 --- a/docs/pages/access-controls/reference.mdx +++ b/docs/pages/access-controls/reference.mdx @@ -12,7 +12,7 @@ controls (RBAC) in your Teleport cluster. A Teleport `role` works by having two lists of rules: `allow` rules and `deny` rules. When declaring access rules, keep in mind the following: -- Everything is denied by default. +- Nothing is allowed by default. - Deny rules get evaluated first and take priority. A rule consists of two parts: the resources and verbs. Here's an example of an @@ -25,10 +25,10 @@ allow: verbs: [list] ``` -If this rule was declared in the `deny` section of a role definition, it -would prohibit users from getting a list of Trusted Clusters and -sessions. You can see all of the available resources and verbs under the `allow` -section in the example role configuration below. +If this rule was declared in the `deny` section of a role definition, it would +prohibit users from getting a list of active sessions. You can see all of the +available resources and verbs under the `allow` section in the example role +configuration below. To manage cluster roles, a Teleport administrator can use the Web UI or the command line using [tctl resource commands](../reference/resources.mdx). @@ -151,15 +151,17 @@ Label | `v3`, `v4` and `v5` Default | `v6` Default ## RBAC for resources -A Teleport role defines which resources (e.g., applications, servers, and databases) a user can have access to. -This works by [labeling resources](../management/admin/labels.mdx) and listing -allow/deny labels in a role definition. +A Teleport role defines which resources (e.g., applications, servers, and +databases) a user can access. +This works by [labeling resources](../management/admin/labels.mdx) and +configuring allow/deny labels in a role definition. Consider the following use case: The infrastructure is split into staging/production environments using labels -like `environment=production` and `environment=staging`. You can create roles -that only have access to one environment. Let's say you create an intern role with the allow rule for label `environment=staging`. +like `environment=production` and `environment=staging`. +You can create roles that only have access to one environment. +Let's say you create an intern role with the allow rule for label `environment=staging`. ### Example @@ -187,8 +189,8 @@ spec: ``` Teleport handles multiple label entries with logical "AND" operations. -As an example this entry would match to databases that have the `env: prod` label and a -`region` label of either `us-west-1` or `eu-central-1`: +As an example, this entry would match to databases that have the `env: prod` +label *and* a `region` label of either `us-west-1` or `eu-central-1`: ```yaml db_labels: @@ -200,12 +202,13 @@ As an example this entry would match to databases that have the `env: prod` labe type="tip" title="Dynamic RBAC" > - Resource labels can be dynamic, i.e. determined at runtime by an output of an executable. In this case, you can implement "permissions follow workload" + Resource labels can be dynamic, i.e. determined at runtime by an output of an executable. + In this case, you can implement "permissions follow workload" policies (eg., any server where PostgreSQL is running becomes *automatically* accessible only by the members of the "DBA" group and nobody else). -### Extended labels syntax +### Extended label matching syntax Below are a few examples for more complex filtering using various regexes. @@ -228,6 +231,65 @@ spec: 'environment': '^test|staging$' ``` +### Label expressions + + +Label expressions are available starting in Teleport version `13.1.1`. +All components of your Teleport cluster must be upgraded to version `13.1.1` +or newer before you will be able to use label expressions. +This includes the Auth Service and **all** Teleport agents. + + +Teleport roles also support matching resource labels with predicate expressions +when you need to: + +- combine logic with OR and AND operators +- perform matching on label keys +- implement negative matches + +The following example role would allow access to any nodes labeled `env=staging` +or labeled `team=`, where `` is one of the values of the user's +`teams` trait: + +```yaml +kind: role +version: v6 +metadata: + name: example-role +spec: + allow: + node_labels_expression: | + labels["env"] == "staging" || + contains(user.spec.traits["teams"], labels["team"]) +``` + +The `_labels_expression` fields have the same purpose of the +matching `_labels` fields, but support predicate expressions instead +of label matchers. +They can be used in the following fields of role `spec.allow` and `spec.deny` +conditions: + +- `node_labels_expression` +- `app_labels_expression` +- `cluster_labels_expression` +- `kubernetes_labels_expression` +- `db_labels_expression` +- `db_service_labels_expression` +- `windows_desktop_labels_expression` +- `group_labels_expression` + +Check out our +[predicate language](../reference/predicate-language.mdx#label-expressions) +guide for a more in depth explanation of the language. + +Typically you will only want to use one of `_labels` or +`_labels_expression` in a single role, but you are allowed to specify +both. +If you have both in a deny rule, the matching is greedy, if either one matches +access will be denied. +In an allow rule, the matching is not greedy, if both are set they both have to +match for access to be allowed. + ## Teleport resources RBAC lets teams limit what resources are available to Teleport users. This can be helpful if, for example, diff --git a/docs/pages/includes/role-spec.mdx b/docs/pages/includes/role-spec.mdx index 3ecdb82b34931..6c3842e11de38 100644 --- a/docs/pages/includes/role-spec.mdx +++ b/docs/pages/includes/role-spec.mdx @@ -120,7 +120,7 @@ spec: windows_desktop_logins: [Administrator, '{{internal.logins}}'] # node_labels: a user with this role will be allowed to connect to - # SSH nodes, which labels match expressions below. + # SSH nodes with labels matching below. node_labels: # literal strings: 'env': 'test' @@ -128,9 +128,11 @@ spec: '*': '*' # a list of alternative options: 'region': ['us-west-1', 'eu-central-1'] - # regular expressions start with ^ and end with $ - # Teleport uses golang regexp syntax. - # of the list example above can be expressed as: + # Regular expressions start with ^ and end with $. + # Teleport uses Go's regular expression syntax: + # https://github.com/google/re2/wiki/Syntax + # The list example above can be expressed as: + # 'region': '^us-west-1|eu-central-1$' 'reg': '^us-west-1|eu-central-1$' # kubernetes_groups specifies Kubernetes groups a user with this role will assume. @@ -143,14 +145,17 @@ spec: kubernetes_users: ['IAM#{{external.foo}};'] # kubernetes_labels: a user with this role will be allowed to connect to - # k8s clusters, which labels match expressions below. + # k8s clusters with labels matching below. kubernetes_labels: # A user can only access prod environments 'env': 'prod' # User can access any region in us-west, e.g us-west-1, us-west-2 'region': 'us-west-*' - # regular expressions start with ^ and ending with $ - # Teleport uses golang regexp syntax. + # Regular expressions start with ^ and end with $. + # Teleport uses Go's regular expression syntax: + # https://github.com/google/re2/wiki/Syntax + # The list example above can be expressed as: + # 'region': '^us-west-1|eu-central-1$' 'cluster_name': '^us.*\.example\.com$' # kubernetes_resources indicates the Kubernetes resources that a user with @@ -178,7 +183,7 @@ spec: 'env': '{{regexp.replace(external.access["env"], "^(staging)$", "$1")}}' # app_labels: a user with this role will be allowed to connect to - # applications, which labels match expressions below. + # applications with labels matching below. app_labels: # A user can only access prod environments 'env': 'prod' @@ -198,6 +203,30 @@ spec: # A user is given group membership to production related groups. 'env': 'prod' + # cluster_labels: a user with this role will be allowed to connect to remote + # clusters with labels matching below. + cluster_labels: + 'env': 'prod' + + # node_labels_expression has the same purpose as node_labels but + # supports predicate expressions to configure custom logic. + # A user with this role will be allowed to access nodes if they are in the + # staging environment *or* if they belong to one of the user's own teams. + node_labels_expression: | + labels["env"] == "staging" || + contains(user.spec.traits["teams"] , labels["team"]) + + # The below _labels_expression fields have the same purpose of the + # matching _labels fields, but support predicate expressions instead + # of label matchers. + app_labels_expression: 'labels["env"] == "staging"' + cluster_labels_expression: 'labels["env"] == "staging"' + kubernetes_labels_expression: 'labels["env"] == "staging"' + db_labels_expression: 'labels["env"] == "staging"' + db_service_labels_expression: 'labels["env"] == "staging"' + windows_desktop_labels_expression: 'labels["env"] == "staging"' + group_labels_expression: 'labels["env"] == "staging"' + # aws_role_arns allows a user with this role to assume AWS roles when # accessing AWS console using UI or AWS API using CLI aws_role_arns: @@ -245,12 +274,12 @@ spec: # the `claims_to_roles` mapping works the same as it does in # the OIDC connector, with the added benefit that the roles being mapped to - # can also be matchers. + # can also be matchers. # - # This example leverages Teleport's regular expression support, which allows + # This example leverages Teleport's regular expression support, which allows # for dynamic mapping from claims. The below mapping says that users with - # claims that match "projects: project-(.*)" can request roles that match - # "$1-admin", where "$1" is the first capture group in the + # claims that match "projects: product-(.*)" can request roles that match + # "$1-admin", where "$1" is the first capture group in the # regular expression. # Example: the "projects: product-foo" claim allows a user to request the # "foo-admin" role diff --git a/docs/pages/reference/predicate-language.mdx b/docs/pages/reference/predicate-language.mdx index 28099c77fd48e..4d70344ecb2b3 100644 --- a/docs/pages/reference/predicate-language.mdx +++ b/docs/pages/reference/predicate-language.mdx @@ -10,10 +10,12 @@ The predicate language uses a slightly different syntax depending on whether it - [Role resources](#scoping-allowdeny-rules-in-role-resources) - [Resource filtering](#resource-filtering) +- [Label expressions](#label-expressions) ## Scoping allow/deny rules in role resources -Some fields in Teleport's role resources use the predicate language to define the scope of a role's permissions: +Some fields in Teleport's role resources use the predicate language to define +the scope of a role's permissions: - [Dynamic Impersonation](../access-controls/guides/impersonation.mdx#filter-fields) - [RBAC for sessions](../access-controls/reference.mdx#filter-fields) @@ -37,8 +39,8 @@ The language also supports the following functions: ## Resource filtering -Both the [`tsh`](cli.mdx#tsh) and [`tctl`](cli.mdx#tctl) CLI tools allow you to filter nodes, -applications, databases, and Kubernetes resources using the `--query` flag. The `--query` flag allows you to +Both the [`tsh`](cli.mdx#tsh) and [`tctl`](cli.mdx#tctl) CLI tools allow you to filter nodes, +applications, databases, and Kubernetes resources using the `--query` flag. The `--query` flag allows you to perform more sophisticated searches using the predicate language. For common resource fields, we defined shortened field names that can easily be accessed by: @@ -68,3 +70,54 @@ The language also supports the following functions: | `search("foo", "bar", "some phrase")` | fuzzy match against common resource fields | See some [examples](cli.mdx#filter-examples) of the different ways you can filter resources. + +## Label expressions + + +Label expressions are available starting in Teleport version `13.1.1`. +All components of your Teleport cluster must be upgraded to version `13.1.1` +or newer before you will be able to use label expressions. +This includes the Auth Service and **all** Teleport agents. + + +Label expressions can be used in Teleport roles to define access to resources +with custom logic. +Check out the Access Controls +[reference page](../access-controls/reference.mdx#label-expressions) +for an overview of label expressions and where they can be used. + +Label expressions support a predicate language with the following fields +available: + +| Field | Type | Description | +|--------------------|-------------------------|-------------| +| `labels` | `map[string]string` | Combined static and dynamic labels of the resource (server, application, etc.) being accessed. | +| `user.spec.traits` | `map[string][]string` | All traits of the user accessing the resource (referred to as `external` or `internal` in role template expressions). | + +The language supports the following functions: + +| Syntax | Return type | Description | Example | +|--------|-------------|-------------|---------| +| `contains(list, item)` | Boolean | Returns true if `list` contains an exact match for `item` | `contains(user.spec.traits[teams], labels["team"])` | +| `regexp.match(list, re)` | Boolean | Returns true if `list` contains a match for `re` | `regexp.match(labels["team"], "dev-team-\d+$")` | +| `regexp.replace(list,` `re, replacement)` | `[]string` | Replaces all matches of `re` with replacement for all items in `list` | `contains(regexp.replace(user.spec.traits["allowed-env"],` `"^env-(.*)$", "$1"), labels["env"])` +| `email.local(list)` | `[]string` | Returns the local part of each email in `list`, or an error if any email fails to parse | `contains(email.local(user.spec.traits["email"]),` `labels["owner"])` +| `strings.upper(list)` | `[]string` | Converts all items of the list to uppercase | `contains(strings.upper(user.spec.traits["username"]),` `labels["owner"])` +| `strings.lower(list)` | `[]string` | Converts all items of the list to lowercase | `contains(strings.lower(user.spec.traits["username"]),` `labels["owner"])` +| `labels_matching(re)` | `[]string` | Returns the aggregate of all label values with keys matching `re`, which can be a glob or a regular expression | `contains(labels_matching("^project-(team\|label)$"),` `"security")` +| `contains_any(list, items)` | Boolean | Returns true if `list` contains an exact match for any element of `items` | `contains_any(user.spec.traits["projects"],` `labels_matching("project-*"))` | +| `contains_all(list, items)` | Boolean | Returns true if `list` contains an exact match for all elements of `items` | `contains_all(user.spec.traits["projects"],` `labels_matching("project-*"))` | + +Above, any argument named `list` can accept a list of values (like the list of +values for a specific user trait) or a single value (like the value of a +resource label or a string literal). + +The language also supports the following operators: + +| Operator | Meaning | Example | +|----------|-------------------------------------|---------| +| == | equal to | `labels["env"] == "staging"` | +| != | not equal to | `labels["env"] != "production"` | +| \|\| | or (any one condition should match) | `labels["env"] == "staging" \|\| labels["env"] == "test"` | +| && | and (all conditions must match) | `labels["env"] == "staging" && labels["team"] == "dev"` | +| ! | not (logical negation) | `!regexp.match(user.spec.traits["teams"], "contractor")` |