# Dual Authorization

You can set up Teleport to require the approval of multiple team members to perform some critical actions. Here are the most common scenarios:

- Improve the security of your system and prevent one successful phishing attack from compromising your system.
- Satisfy FedRAMP AC-3 Dual authorization control that requires approval of two authorized individuals.

In this guide, we will set up Teleport's Just-in-Time Access Requests to require the approval of two team members for a privileged role `elevated-access`.

The steps below describe how to use Teleport with Mattermost. You can also [integrate with many other providers](https://goteleport.com/docs/ver/17.x/identity-governance/access-requests.md).

---

WARNING

Dual Authorization requires Teleport Identity Governance.

---

## How it works

Teleport administrators can configure a role that allows elevated privileges as long as multiple additional users approve a request for that role. When a user requests access to the elevated role, they create an Access Request resource on the Teleport Auth Service backend.

A Teleport Access Request plugin connects to the Teleport Auth Service and receives a gRPC message whenever a Teleport user creates or updates an Access Request. The plugin then manages updates in a third-party communication platform, in this case, Mattermost. Users can then approve and deny Access Requests by following a message link.

![The Mattermost Access Request plugin](/docs/assets/images/diagram-0481e3a7aeea9621cefa6c6267a6ce81.png)

## Prerequisites

- Mattermost installed.

* A running Teleport Enterprise cluster. If you want to get started with Teleport, [sign up](https://goteleport.com/signup) for a free trial or [set up a demo environment](https://goteleport.com/docs/ver/17.x/get-started/deploy-community.md).

* The `tctl` and `tsh` clients.

  Installing `tctl` and `tsh` clients

  1. Determine the version of your Teleport cluster. The `tctl` and `tsh` clients must be at most one major version behind your Teleport cluster version. Send a GET request to the Proxy Service at `/v1/webapi/find` and use a JSON query tool to obtain your cluster version. Replace teleport.example.com:443 with the web address of your Teleport Proxy Service:

     ```
     $ TELEPORT_DOMAIN=teleport.example.com:443
     $ TELEPORT_VERSION="$(curl -s https://$TELEPORT_DOMAIN/v1/webapi/find | jq -r '.server_version')"
     ```

  2. Follow the instructions for your platform to install `tctl` and `tsh` clients:

     **Mac**

     Download the signed macOS .pkg installer for Teleport, which includes the `tctl` and `tsh` clients:

     ```
     $ curl -O https://cdn.teleport.dev/teleport-${TELEPORT_VERSION?}.pkg
     ```

     In Finder double-click the `pkg` file to begin installation.

     ---

     DANGER

     Using Homebrew to install Teleport is not supported. The Teleport package in Homebrew is not maintained by Teleport and we can't guarantee its reliability or security.

     ---

     **Windows - Powershell**

     ```
     $ curl.exe -O https://cdn.teleport.dev/teleport-v${TELEPORT_VERSION?}-windows-amd64-bin.zip
     Unzip the archive and move the `tctl` and `tsh` clients to your %PATH%
     NOTE: Do not place the `tctl` and `tsh` clients in the System32 directory, as this can cause issues when using WinSCP.
     Use %SystemRoot% (C:\Windows) or %USERPROFILE% (C:\Users\<username>) instead.
     ```

     **Linux**

     All of the Teleport binaries in Linux installations include the `tctl` and `tsh` clients. For more options (including RPM/DEB packages and downloads for i386/ARM/ARM64) see our [installation page](https://goteleport.com/docs/ver/17.x/installation.md).

     ```
     $ curl -O https://cdn.teleport.dev/teleport-v${TELEPORT_VERSION?}-linux-amd64-bin.tar.gz
     $ tar -xzf teleport-v${TELEPORT_VERSION?}-linux-amd64-bin.tar.gz
     $ cd teleport
     $ sudo ./install
     Teleport binaries have been copied to /usr/local/bin
     ```

---

RUNNING MATTERMOST LOCALLY WITH DOCKER

```
$ docker run --name mattermost-preview -d --publish 8065:8065 --add-host dockerhost:127.0.0.1 mattermost/mattermost-preview
```

---

- To check that you can connect to your Teleport cluster, sign in with `tsh login`, then verify that you can run `tctl` commands using your current credentials. For example, run the following command, assigning teleport.example.com to the domain name of the Teleport Proxy Service in your cluster and email\@example.com to your Teleport username:
  ```
  $ tsh login --proxy=teleport.example.com --user=email@example.com
  $ tctl status
  Cluster  teleport.example.com
  Version  17.7.20
  CA pin   sha256:abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678
  ```
  If you can connect to the cluster and run the `tctl status` command, you can use your current credentials to run subsequent `tctl` commands from your workstation. If you host your own Teleport cluster, you can also run `tctl` commands on the computer that hosts the Teleport Auth Service for full permissions.

## Step 1/2. Set up a Teleport bot

### Create a bot within Mattermost

Enable bot account creation in "System Console -> Integrations".

Toggle `Enable Bot Account Creation`.

![Enable bots](/docs/assets/images/mattermost-0-enable-faca6b86831ce7c1848462efac3c221f.png)

Go back to your team settings, navigate to "Integrations -> Bot Accounts". Press "Add Bot Account".

![Enable bots](/docs/assets/images/mattermost-1-bot-1ef2d1cd8dfb5a9862de10ce6b72b62f.png)

Add the "Post All" permission on the new account.

![Enable bots](/docs/assets/images/mattermost-2-all-permissions@2x-34bb70a36a702bf3d3ea79d4678fff47.png)

Create the bot and save the access token.

### Set up RBAC for the plugin

The required permissions for the plugin are configured in the preset `access-plugin` role. To generate credentials for the plugin, define either a Machine ID bot user or a regular Teleport user.

**Machine & Workload Identity**

If you haven't set up a Machine ID bot yet, refer to the [deployment guide](https://goteleport.com/docs/ver/17.x/machine-workload-identity/deployment.md) to run the `tbot` binary on your infrastructure.

Next, allow the Machine ID bot to generate credentials for the `access-plugin` role. You can do this using `tctl`, replacing `my-bot` with the name of your bot:

```
$ tctl bots update my-bot --add-roles access-plugin
```

**Long-lived identity files**

As with all Teleport users, the Teleport Auth Service authenticates the `access-plugin` user by issuing short-lived TLS credentials. In this case, we will need to request the credentials manually by *impersonating* the `access-plugin` role and user.

If you are running a self-hosted Teleport Enterprise deployment and are using `tctl` from the Auth Service host, you will already have impersonation privileges.

To grant your user impersonation privileges for `access-plugin`, define a user named `access-plugin` and a role named `access-plugin-impersonator` by adding the following YAML document into a file called `access-plugin-impersonator.yaml`:

```
kind: user
metadata:
  name: access-plugin
spec:
  roles: ['access-plugin']
version: v2
---
kind: role
version: v7
metadata:
  name: access-plugin-impersonator
spec:
  allow:
    impersonate:
      roles:
      - access-plugin
      users:
      - access-plugin

```

Create the user and role:

```
$ tctl create -f access-plugin-impersonator.yaml
user "access-plugin" has been created
role "access-plugin-impersonator" has been created
```

---

TIP

You can also create and edit roles using the Web UI. Go to **Access -> Roles** and click **Create New Role** or pick an existing role to edit.

---

Assign this role to the user you plan to use to generate credentials for the `access-plugin` role and user:

Assign the `access-plugin-impersonator` role to your Teleport user by running the appropriate commands for your authentication provider:

**Local User**

1. Retrieve your local user's roles as a comma-separated list:

   ```
   $ ROLES=$(tsh status -f json | jq -r '.active.roles | join(",")')
   ```

2. Edit your local user to add the new role:

   ```
   $ tctl users update $(tsh status -f json | jq -r '.active.username') \
     --set-roles "${ROLES?},access-plugin-impersonator"
   ```

3. Sign out of the Teleport cluster and sign in again to assume the new role.

**GitHub**

1. Open your `github` authentication connector in a text editor:

   ```
   $ tctl edit github/github
   ```

2. Edit the `github` connector, adding `access-plugin-impersonator` to the `teams_to_roles` section.

   The team you should map to this role depends on how you have designed your organization's role-based access controls (RBAC). However, the team must include your user account and should be the smallest team possible within your organization.

   Here is an example:

   ```
     teams_to_roles:
       - organization: octocats
         team: admins
         roles:
           - access
   +       - access-plugin-impersonator

   ```

3. Apply your changes by saving closing the file in your editor.

4. Sign out of the Teleport cluster and sign in again to assume the new role.

**SAML**

1. Retrieve your `saml` configuration resource:

   ```
   $ tctl get --with-secrets saml/mysaml > saml.yaml
   ```

   Note that the `--with-secrets` flag adds the value of `spec.signing_key_pair.private_key` to the `saml.yaml` file. Because this key contains a sensitive value, you should remove the saml.yaml file immediately after updating the resource.

2. Edit `saml.yaml`, adding `access-plugin-impersonator` to the `attributes_to_roles` section.

   The attribute you should map to this role depends on how you have designed your organization's role-based access controls (RBAC). However, the group must include your user account and should be the smallest group possible within your organization.

   Here is an example:

   ```
     attributes_to_roles:
       - name: "groups"
         value: "my-group"
         roles:
           - access
   +       - access-plugin-impersonator

   ```

3. Apply your changes:

   ```
   $ tctl create -f saml.yaml
   ```

4. Sign out of the Teleport cluster and sign in again to assume the new role.

**OIDC**

1. Retrieve your `oidc` configuration resource:

   ```
   $ tctl get oidc/myoidc --with-secrets > oidc.yaml
   ```

   Note that the `--with-secrets` flag adds the value of `spec.signing_key_pair.private_key` to the `oidc.yaml` file. Because this key contains a sensitive value, you should remove the oidc.yaml file immediately after updating the resource.

2. Edit `oidc.yaml`, adding `access-plugin-impersonator` to the `claims_to_roles` section.

   The claim you should map to this role depends on how you have designed your organization's role-based access controls (RBAC). However, the group must include your user account and should be the smallest group possible within your organization.

   Here is an example:

   ```
     claims_to_roles:
       - name: "groups"
         value: "my-group"
         roles:
           - access
   +       - access-plugin-impersonator

   ```

3. Apply your changes:

   ```
   $ tctl create -f oidc.yaml
   ```

4. Sign out of the Teleport cluster and sign in again to assume the new role.

You will now be able to generate signed certificates for the `access-plugin` role and user.

### Export the access-plugin identity files

Like all Teleport users, `access-plugin` needs signed credentials in order to connect to your Teleport cluster. You will use the `tctl auth sign` command to request these credentials.

The following `tctl auth sign` command impersonates the `access-plugin` user, generates signed credentials, and writes an identity file to the local directory:

```
$ tctl auth sign --user=access-plugin --out=identity
```

The plugin connects to the Teleport Auth Service's gRPC endpoint over TLS.

The identity file, `identity`, includes both TLS and SSH credentials. The plugin uses the SSH credentials to connect to the Proxy Service, which establishes a reverse tunnel connection to the Auth Service. The plugin uses this reverse tunnel, along with your TLS credentials, to connect to the Auth Service's gRPC endpoint.

Certificate Lifetime

By default, `tctl auth sign` produces certificates with a relatively short lifetime. For production deployments, we suggest using [Machine & Workload Identity](https://goteleport.com/docs/ver/17.x/machine-workload-identity/introduction.md) to programmatically issue and renew certificates for your plugin. See our Machine & Workload Identity [getting started guide](https://goteleport.com/docs/ver/17.x/machine-workload-identity/getting-started.md) to learn more.

Note that you cannot issue certificates that are valid longer than your existing credentials. For example, to issue certificates with a 1000-hour TTL, you must be logged in with a session that is valid for at least 1000 hours. This means your user must have a role allowing a `max_session_ttl` of at least 1000 hours (60000 minutes), and you must specify a `--ttl` when logging in:

```
$ tsh login --proxy=teleport.example.com --ttl=60060
```

If you are running the plugin on a Linux server, create a data directory to hold certificate files for the plugin:

```
$ sudo mkdir -p /var/lib/teleport/plugins/api-credentials
$ sudo mv identity /var/lib/teleport/plugins/api-credentials
```

If you are running the plugin on Kubernetes, Create a Kubernetes secret that contains the Teleport identity file:

```
$ kubectl -n teleport create secret generic --from-file=identity plugin-identity
```

Once the Teleport credentials expire, you will need to renew them by running the `tctl auth sign` command again.

We'll reference the exported file(s) later when configuring the plugin.

### Install the plugin

**Download**

Access Request Plugins are available as `amd64` and `arm64` Linux binaries for downloading. Replace `ARCH` with your required version.

```
$ curl -L -O https://cdn.teleport.dev/teleport-access-mattermost-v17.7.20-linux-ARCH-bin.tar.gz
$ tar -xzf teleport-access-mattermost-v17.7.20-linux-ARCH-bin.tar.gz
$ cd teleport-access-mattermost
$ sudo ./install
```

Make sure the binary is installed:

```
$ teleport-mattermost version
teleport-mattermost v17.7.20 git:teleport-mattermost-v17.7.20-fffffffff go1.25.9
```

**Docker Image**

```
$ docker pull public.ecr.aws/gravitational/teleport-plugin-mattermost:17.7.20
```

Make sure the plugin is installed by running the following command:

```
$ docker run public.ecr.aws/gravitational/teleport-plugin-mattermost:17.7.20 version
teleport-mattermost v17.7.20 git:teleport-mattermost-v17.7.20-api/14.0.0-gd1e081e 1.25.9
```

For a list of available tags, visit [Amazon ECR Public Gallery](https://gallery.ecr.aws/gravitational/teleport-plugin-mattermost).

**From Source**

To install from source you need `git` and `go` installed. If you do not have Go installed, visit the Go [downloads page](https://go.dev/dl/).

```
$ git clone https://github.com/gravitational/teleport -b branch/v17
$ cd teleport/integrations/access/mattermost
$ git checkout v17.7.20
$ make build/teleport-mattermost
```

Move the `teleport-mattermost` binary into your PATH.

Make sure the binary is installed:

```
$ teleport-mattermost version
teleport-mattermost v17.7.20 git:teleport-mattermost-v17.7.20-fffffffff go1.25.9
```

**Helm Chart**

Allow Helm to install charts that are hosted in the Teleport Helm repository:

```
$ helm repo add teleport https://charts.releases.teleport.dev
```

Update the cache of charts from the remote repository:

```
$ helm repo update
```

**Download**

Access Request Plugins are available as `amd64` or `arm64` Linux binaries for downloading. Replace `ARCH` with your required version.

```
$ curl -L https://cdn.teleport.dev/teleport-access-mattermost-v17.7.20-linux-ARCH-bin.tar.gz
$ tar -xzf teleport-access-mattermost-v17.7.20-linux-ARCH-bin.tar.gz
$ cd teleport-access-mattermost
$ ./install
```

**From Source**

To install from source you need `git` and `go` installed. If you do not have Go installed, visit the Go [downloads page](https://go.dev/dl/).

```
$ git clone https://github.com/gravitational/teleport -b branch/v17
$ cd teleport/integrations/access/mattermost
$ git checkout v17.7.20
$ make build/teleport-mattermost
```

```
$ teleport-mattermost configure > /etc/teleport-mattermost.toml
```

Update the config with the Teleport address, Mattermost URL, and a bot token:

```
# example mattermost configuration TOML file
[teleport]
auth_server = "myinstance.teleport.sh:443"                   # Teleport Cloud proxy HTTPS address
identity = "/var/lib/teleport/plugins/mattermost/identity"   # Identity file path
refresh_identity = true                                      # Refresh identity file on a periodic basis.

[mattermost]
url = "https://mattermost.example.com" # Mattermost Server URL
team = "team-name"                     # Mattermost team in which the channel resides.
channel = "channel-name"               # Mattermost Channel name to post requests to
token = "api-token"                    # Mattermost Bot OAuth token
secret = "signing-secret-value"        # Mattermost API signing Secret

[http]
public_addr = "example.com" # URL on which callback server is accessible externally, e.g. [https://]teleport-mattermost.example.com
# listen_addr = ":8081" # Network address in format [addr]:port on which callback server listens, e.g. 0.0.0.0:443
https_key_file = "/var/lib/teleport/plugins/mattermost/server.key"  # TLS private key
https_cert_file = "/var/lib/teleport/plugins/mattermost/server.crt" # TLS certificate

[log]
output = "stderr" # Logger output. Could be "stdout", "stderr" or "/var/lib/teleport/mattermost.log"
severity = "INFO" # Logger severity. Could be "INFO", "ERROR", "DEBUG" or "WARN".


```

## Step 2/2. Configure dual authorization

In this section, we will use an example to show you how to require dual authorization for a user to assume a role.

### Require dual authorization for a role

Alice and Ivan are reviewers. They can approve requests for assuming role `elevated-access`. Bob is a DevOps engineer and can assume the `elevated-access` role if two members of the `reviewer` role approve the request.

Create the following `elevated-access`, `dbreviewer` and `devops` roles:

```
kind: role
version: v5
metadata:
  name: dbreviewer
spec:
  allow:
    review_requests:
      roles: ['elevated-access']
---
kind: role
version: v5
metadata:
  name: devops
spec:
  allow:
    request:
      roles: ['elevated-access']
      thresholds:
        - approve: 2
          deny: 1
---
kind: role
version: v5
metadata:
  name: elevated-access
spec:
  allow:
    logins: ['root']
    node_labels:
      'env': 'prod'
      'type': 'db'

```

---

TIP

You can also create and edit roles using the Web UI. Go to **Access -> Roles** and click **Create New Role** or pick an existing role to edit.

---

The commands below create the local users Bob, Alice, and Ivan.

```
$ tctl users add bob@example.com --roles=devops
$ tctl users add alice@example.com --roles=dbreviewer
$ tctl users add ivan@example.com --roles=dbreviewer
```

### Create an Access Request

Bob does not have a role `elevated-access` assigned to him, but can create an Access Request for this role in the Web UI or CLI:

**Web UI**

![Role-Request](/docs/assets/images/role-new-request-f8de5e6e24cbe3c1978cfbcf386700c6.png) ![Request-Success](/docs/assets/images/request-success-435549c4acf63b36a74e44b091690b73.png)

**Terminal**

```
Bob has to set valid emails of Alice and Ivan matching in Mattermost.
$ tsh request create --roles=elevated-access --reviewers=alice@example.com,ivan@example.com
```

The Web UI will notify the admin:

![Mattermost-Request](/docs/assets/images/pending-access-request-07126c97c7aced6ed379880fabc9b976.png)

The request can then be reviewed and approved through the Web UI or CLI:

**Web UI**

![Teleport-Approve](/docs/assets/images/approve-new-request-51dc06eae57234cbbfea4e13f0879884.png)

**CLI**

```
$ tsh request list

ID                                   User        Roles            Created  (UTC)       Status
------------------------------------ ----------  ---------------  -------------------  ------
0193496f-268c-727e-b696-600a868429ff test (Bob)  elevated-access  21 Nov 24 18:50 UTC  PENDING

$ tsh request review --approve --reason="Need to gain elevated-access for investigation" 0193496f-268c-727e-b696-600a868429ff
Successfully submitted review.  Request state: APPROVED
```

If the user has created a request using CLI, the role will be assumed once it has been approved, or they can assume the role using the Web UI.

## Troubleshooting

### Certificate errors in self-hosted deployments

You may be getting certificate errors if Teleport's Auth Service is missing an address in the server certificate:

```
authentication handshake failed: x509: cannot validate certificate for 127.0.0.1 because it doesn't contain any IP SANs

```

```
x509: certificate is valid for,*.teleport.cluster.local, teleport.cluster.local, not example.com

```

To fix the problem, update the Auth Service with a public address, and restart Teleport:

```
auth_service:
  public_addr: ['localhost:3025', 'example.com:3025']

```
