# Machine & Workload Identity with Database Access

Teleport protects and controls access to databases. Machine & Workload Identity can be used to grant machines secure, short-lived access to these databases.

In this guide, you will configure `tbot` to produce credentials that can be used to access a database configured in Teleport.

![Accessing Teleport-protected databases with Machine \&amp; Workload Identity](/docs/assets/images/machine-id-database-access-b18ffa95192758290ed960b7bcbbc47d.svg)

## Prerequisites

- A running Teleport 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/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/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
     ```

* If you have not already put your database behind the Teleport Database Service, follow the [database access getting started guide](https://goteleport.com/docs/enroll-resources/database-access/getting-started.md). The Teleport Database Service supports databases like PostgreSQL, MongoDB, Redis, and much more. See our [database access guides](https://goteleport.com/docs/enroll-resources/database-access/guides.md) for a complete list.
* 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  18.7.3
  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.
* The `tsh` binary must be installed on the machine that will access the database. Depending on how `tbot` was installed, this may already be installed. If it is not, see [Installation](https://goteleport.com/docs/installation.md) for details.
* `tbot` must already be installed and configured on the machine that will access the database. For more information, see the [deployment guides](https://goteleport.com/docs/machine-workload-identity/deployment.md).

## Step 1/4. Configure RBAC

First, Teleport must be configured to allow the credentials produced by the bot to access the database server and database. This is done by creating a role that grants the necessary permissions and then assigning this role to a Bot.

Create a file called `role.yaml` with the following content:

```
kind: role
version: v6
metadata:
  name: example-role
spec:
  allow:
    db_labels:
      '*': '*'
    db_names: [example-db]
    db_users: [alice]
    rules:
      - resources: [db_server, db]
        verbs: [read, list]

```

Replace:

- `example-role` with a descriptive name related to your use case.
- `example-db` with the name of the database which the bot will be used to access.
- `alice` with the name of the user which the bot will use when connecting to the database.

Use `tctl create -f ./role.yaml` to create the role.

---

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.

---

Now, use `tctl bots update` to add the role to the Bot. Replace `example` with the name of the Bot you created in the deployment guide and `example-role` with the name of the role you just created:

```
$ tctl bots update example --add-roles example-role
```

This rule will allow the bot to do two things:

- Access the database `example-db` on any database server (due to the `'*': '*'` label selector) as the user `alice`.
- Discover information about database resources in Teleport.

The `'*': '*'` label selector grants access to any database server configured in Teleport. In production, consider restricting the bot's access using a more specific label selector; see the [Database Access RBAC guide](https://goteleport.com/docs/enroll-resources/database-access/rbac.md) for a full reference of database-related role options.

## Step 2/4. Configure a database `tbot` output service

Now, `tbot` needs to be configured with an output service that will produce the credentials needed for database access. To do this, the `database` output service type is used.

The database you wish to generate credentials for is configured as part of the `database` service. This is controlled using three fields:

- `service` specifies the Database Service as named in the Teleport configuration that the credentials will grant access to.
- `database` specifies the database on the Database Service that the credentials will grant access to.
- `username` specifies the user on the database that the credentials will grant access to. This field does not need to be specified for all types of database.

In addition, the `format` field in the database output service controls the format of the generated credentials. This allows for compatibility with clients that expect a specific format. When this field is not specified, a sensible default option is used that is compatible with most clients. The full list of supported `format` options is below:

| Client      | `format`    | Description                                                                                                                                 |
| ----------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| Default     | Unspecified | Provides a certificate in `tlscert`, a private key in `key` and the CA in `teleport-database-ca.crt`. This is compatible with most clients. |
| MongoDB     | `mongo`     | Provides `mongo.crt` and `mongo.cas`.                                                                                                       |
| CockroachDB | `cockroach` | Provides `cockroach/node.key`, `cockroach/node.crt`, and `cockroach/ca.crt`.                                                                |
| Generic TLS | `tls`       | Provides `tls.key`, `tls.crt`, and `tls.cas` for generic clients that require specific file extensions.                                     |

Output services must be configured with a destination. In this example, the `directory` destination will be used. This will write artifacts to a specified directory on disk. Ensure that this directory can be written to by the Linux user that `tbot` runs as, and that it can be read by the Linux user that will be accessing applications.

Modify your `tbot` configuration to add a `database` service:

```
services:
- type: database
  destination:
    type: directory
    path: /opt/machine-id
  # Specify the details of the database you wish to connect to.
  service: example-server
  database: example-db
  username: alice
  # Specify a format to use for the output credentials. For most databases,
  # this configuration field can be omitted.
  # format: mongo

```

If operating `tbot` as a background service, restart it. If running `tbot` in one-shot mode, it must be executed before you attempt to access the database.

## Step 3/4. Configure the local database access proxy

Now that `tbot` has produced the database access credentials, a local proxy should be set up to forward the database connections from your database client to the Teleport Proxy Service through a TLS connection. This is necessary as the TLS connection allows the Teleport Proxy Service to identify the protocol and intended recipient.

The local proxy needs to be running as long as the client needs to make connections to the database or as long as a connection is still open. One way to keep this local proxy running in the background is to use a systemd service. This is demonstrated in the remainder of this step, but a different service manager could be used or a number of other techniques could be used to run the local proxy whilst the client is running.

The local proxy opens a specified port on the local loopback interface. Clients must then be configured to connect to this port on localhost. As the port is opened on the local loopback interface, it means that the local proxy must be running on the same host as the client which wants to connect to the database.

By default, database clients must also be configured to use the credentials when connecting to the local port. This ensures no other users of the host can access the database via the local port, and ensures the connection between your database client and server is never unencrypted, even over localhost.

To create a systemd service for this purpose, create a unit file at `/etc/systemd/system/tbot-db-proxy.service`:

```
[Unit]
Description=Teleport Machine & Workload Identity Proxy Service
After=network.target
# If you have followed a previous guide and configured tbot itself as a systemd
# service, uncomment the following line to create a dependency between the two
# services.
# Requires=tbot.service

[Service]
Type=simple
# Ensure that the teleport user/group exists and has read access to the
# destination directory.
User=teleport
Group=teleport
Restart=always
RestartSec=5
# Adjust `12345` to any port of your choosing that is free on the local loopback
# interface. Adjust `example-server` to the name of the Database Service in
# teleport.
ExecStart=/usr/local/bin/tbot -c /etc/tbot.yaml proxy --proxy=proxy.example.com:3080 --destination-dir=/opt/machine-id db --port=12345 example-server
ExecReload=/bin/kill -HUP $MAINPID
PIDFile=/run/tbot-db-proxy.pid
LimitNOFILE=8192

[Install]
WantedBy=multi-user.target

```

This will start a local proxy on port `12345` that can be used to connect to the `example-server` database server. Be sure to customize the `tbot` parameters as necessary for your local setup.

Finally, run the following commands to enable and start the local proxy service:

```
$ sudo systemctl enable tbot-db-proxy
$ sudo systemctl start tbot-db-proxy
$ sudo systemctl status tbot-db-proxy
```

### Authenticated tunnel

Whilst the default behaviour requires the client to use client certificate authentication, it is possible to configure an **authenticated tunnel**. This will automatically attach credentials to any incoming connection to the local port. Whilst this is less secure, it can be necessary if the client you wish to use with your database does not support client certificate authentication.

If you wish to enable the authenticated tunnel mode, `--tunnel` flag is used with `tbot proxy db...`.

If you are executing this in the foreground, provide the `--tunnel` flag. If you are using a systemd service, add `--tunnel` to the `ExecStart` in `machine-id-proxy.service` and then reload the unit.

Once this has been enabled, you do not need to specify a password or TLS certificates and certificate authorities in the client when connecting to the configured port.

## Step 4/4. Configure the client to connect to the database

With the credentials generated and the local proxy running, you can now configure your client to use the local proxy with the credentials.

Refer to these sample Go programs for using the credentials:

**Self-Hosted PostgreSQL**

```
// This example program demonstrates how to connect to a Postgres database
// using certificates issued by Teleport Machine & Workload Identity.

package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/jackc/pgx/v4/stdlib"
)

func main() {
	// Open connection to database.
	db, err := sql.Open("pgx", fmt.Sprint(
		"host=localhost ",
		"port=1234 ",
		"dbname=example-db ",
		"user=alice ",
		// The next four options should be omitted if the local proxy has been
		// placed in "authenticated tunnel" mode.
		"sslmode=verify-full ",
		"sslrootcert=/opt/machine-id/teleport-host-ca.crt ",
		"sslkey=/opt/machine-id/key ",
		"sslcert=/opt/machine-id/tlscert ",
	))
	if err != nil {
		log.Fatalf("Failed to open database: %v.", err)
	}

	defer db.Close()

	// Call "Ping" to test connectivity.
	err = db.Ping()
	if err != nil {
		log.Fatalf("Failed to Ping database: %v.", err)
	}

	log.Printf("Successfully connected to PostgreSQL.")
}


```

**Self-Hosted MongoDB**

```
// This example program demonstrates how to connect to a MongoDB database
// using certificates issued by Teleport Machine & Workload Identity.

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// Create client and connect to MongoDB. Make sure to modify the host,
	// port, and certificate paths.
	uri := fmt.Sprintf(
		"mongodb://localhost:1234/?tlsCAFile=%s&tlsCertificateKeyFile=%s",
		"/opt/machine-id/mongo.cas",
		"/opt/machine-id/mongo.crt",
	)
	client, err := mongo.NewClient(options.Client().ApplyURI(uri))
	if err != nil {
		log.Fatalf("Failed to create database client: %v.", err)
	}
	err = client.Connect(ctx)
	if err != nil {
		log.Fatalf("Failed to connect to database: %v.", err)
	}

	defer client.Disconnect(ctx)

	log.Printf("Successfully connected to MongoDB.")

	// List databases to test connectivity.
	databases, err := client.ListDatabaseNames(ctx, bson.M{})
	if err != nil {
		log.Fatalf("Failed to list databases: %v.", err)
	}
	log.Println(databases)

}


```

You're all set. You have provided your application with short-lived certificates tied to a machine identity that can access your database, be rotated, and audited, all while being controlled with all the familiar Teleport access controls.

## Next steps

- Read the [configuration reference](https://goteleport.com/docs/reference/machine-workload-identity/configuration.md) to explore all the available configuration options.
