{"token_count": 3335}

# Beams Database Demo

Teleport Beams allow you to grant AI agents access to your databases with restricted permissions to prevent their nondeterministic access patterns from causing harm.

In this guide, you will enroll a database with Teleport and prompt an AI agent to access the database from a Teleport beam. As this guide demonstrates, the restricted access you can provide to the database via Teleport RBAC ensures that the agent can only perform the expected set of operations on the database.

## How it works

Teleport Beams are micro VM sandboxes for running agentic workloads, hosted on the Teleport Cloud infrastructure. When a user creates a beam, the Teleport Auth Service creates a **delegation session** that contains the user and their Teleport roles.

An instance of the `tbot` daemon on the beam receives the ID of the delegation session and queries the Auth Service to issue a fresh Teleport identity to services that run on the beam. As a result, any agentic workloads running on the beam delegate the originating user's Teleport permissions.

For Teleport-protected databases, this means that users who create a beam can run AI agents on the beam to access those databases, as long as the users have permissions to access those databases as well. With Teleport RBAC, you can limit the permissions that agentic workloads have to access your databases.

## Prerequisites

You will need a Teleport Beams account. [Start your free trial](https://www.beams.run/).

For simplicity, this guide walks you through a demo that enrolls a local PostgreSQL container with your Teleport cluster and configures RBAC for that database. Beams supports any Teleport-protected database, and comes with the PostgreSQL client tools out of the box.

To follow the local demo, you will need:

- Docker installed on your workstation

- Check that you can connect to your Teleport cluster and verify that you can run `tctl` and `tsh` commands using your current credentials.

  1. Assign teleport.example.com to the domain name of the Teleport Proxy Service in your cluster and email\@example.com to your Teleport username.

  2. Authenticate to your Teleport cluster. This depends on whether your shell is interactive or not.

     **In an interactive shell:** Run the following command. By default, this triggers a multi-factor authentication prompt:

     ```
     $ tsh login --proxy=teleport.example.com --user=email@example.com
     $ tctl status
     Cluster  teleport.example.com
     Version  19.0.0-dev
     CA pin   sha256:abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678
     ```

     **On non-interactive environments:** If you are running `tsh` and `tctl` as an AI agent, in a CI/CD environment, or similar, make sure the `TELEPORT_IDENTITY_FILE` environment variable is assigned to a valid file path with credentials for your cluster. `tsh` and `tctl` read the file path from the environment variable and do not require a separate authentication step. If there is no identity file available, we recommend that you [set up Machine ID](https://goteleport.com/docs/machine-workload-identity/getting-started.md) to provision one automatically.

     When executing `tctl` commands with an identity file, you must pass the `--auth-server` flag to provide the Teleport Auth Service address, which is not included in the identity file. If you provide the Proxy Service address, `tctl` connects to the Proxy Service, which forwards traffic to and from the Teleport Auth Service. Update 443 to `3025` if you are contacting the Auth Service directly with `tctl`:

     ```
     $ tctl status --auth-server=teleport.example.com:443
     ```

     For `tsh` commands that read an identity file, you must pass the `--proxy` flag, which points `tsh` to the address of the Teleport Proxy Service:

     ```
     $ tsh status --proxy=teleport.example.com
     ```

     Ensure client commands can access your identity file. Replace path/to/identity/file with the path to your identity file:

     ```
     $ export TELEPORT_IDENTITY_FILE="${TELEPORT_IDENTITY_FILE:-path/to/identity/file}"
     ```

     Add the `--auth-server` or `--proxy` flags to all subsequent `tctl` and `tsh` commands.

  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/3. Enroll a database with Teleport

In this section, you will enroll a database with Teleport and configure RBAC for it. We recommend following this minimal example first for a demonstration of Beams in action.

---

TIP

This section is not required if you already have a database enrolled and understand Teleport RBAC. If you have a database and a role you want to grant to your AI agent, skip to [Step 2](#step-23-prepare-your-beam).

---

### Start your local demo database

1. On your workstation, create a local directory for the TLS credentials you want to mount on the PostgreSQL container:

   ```
   $ mkdir certs
   ```

2. Retrieve mTLS credentials that your PostgreSQL container will use to trust the Teleport Database Service:

   ```
   $ tctl auth sign --format=db --host=postgres --out=certs/server --ttl=2160h
   ```

   ---

   TTL

   We recommend using a shorter TTL, but keep in mind that you'll need to update the database server certificate before it expires to not lose the ability to connect. Pick the TTL value that best fits your use-case.

   ---

   The command creates 3 files:

   - `server.cas`: The Database Client CA certificate, which your database uses to verify connections from the Teleport Database Service.
   - `server.crt`: A certificate for your database server, signed by the Database CA.
   - `server.key`: The private key for the server certificate.

3. Create a local Docker bridge network for the PostgreSQL container and Teleport Database Service:

   ```
   $ docker network create local-postgres
   ```

4. Generate a strong password for the superuser account in your PostgreSQL container. Export it in the terminal where you will run your PostgreSQL container:

   ```
   $ export POSTGRES_PASSWORD=<strong generated password>
   ```

5. Spin up your database container, joining it to the local bridge network and mounting the TLS credentials you generated.

   This command assigns the `POSTGRES_PASSWORD` environment variable in the container because the image requires it, though we'll configure the container to enforce certificates for authentication. It also enables TLS using Teleport-issued credentials, which it changes the ownership of per the expectations of the `postgres` daemon. We do this inside the container to avoid unexpected ownership changes when Docker creates the bind mount:

   ```
   $ docker run -d \
      --name postgres \
      -e POSTGRES_PASSWORD \
      -v ./certs:/certs \
      --network local-postgres \
      --entrypoint bash \
      postgres:18 \
      -c "chown 999:999 /certs/server.key \
         && chmod 600 /certs/server.key \
         && chmod 644 /certs/server.crt /certs/server.cas  \
         && exec docker-entrypoint.sh postgres \
            -c ssl=on \
            -c ssl_cert_file=/certs/server.crt \
            -c ssl_key_file=/certs/server.key \
            -c ssl_ca_file=/certs/server.cas"
   ```

6. Require TLS for all connections by editing the PostgreSQL configuration file for host-based authentication and triggering a configuration reload. This authenticates all connections to the database from inside the container:

   ```
   $ docker exec postgres bash -c "echo 'local all all trust' > /var/lib/postgresql/18/docker/pg_hba.conf"
   $ docker exec postgres bash -c "echo 'hostssl all all 0.0.0.0/0 cert' >> /var/lib/postgresql/18/docker/pg_hba.conf"
   $ docker exec postgres psql -U postgres -c "SELECT pg_reload_conf()"
   ```

### Configure the local demo database

Once the local demo database is running, we'll set it up to support our demo. We'll include two users, an admin who can perform all database operations and a read-only user who can only run `SELECT` queries against a single table.

1. Create the admin role:

   ```
   $ docker exec postgres psql -U postgres -c "CREATE ROLE admin LOGIN SUPERUSER"
   ```

2. Create a table to hold example data, and the read-only role that can query it:

   ```
   $ docker exec postgres psql -U postgres -c "CREATE TABLE users (id INT PRIMARY KEY, name TEXT, ssn TEXT)"
   $ docker exec postgres psql -U postgres -c "CREATE ROLE readonly LOGIN"
   $ docker exec postgres psql -U postgres -c "GRANT CONNECT ON DATABASE postgres TO readonly"
   $ docker exec postgres psql -U postgres -c "GRANT SELECT ON users TO readonly"
   ```

3. Add some example data:

   ```
   $ docker exec postgres psql -U postgres -c "INSERT INTO users (id, name, ssn) VALUES (123, 'alice', '000-00-0000')"
   ```

### Start the Teleport Database Service

Next, you will start the Teleport Database Service as a container on your workstation. The Teleport Database Service container initiates an SSH reverse tunnel to the Teleport Proxy Service in your cluster. When the AI agent that you'll run on your beam dials your database, the traffic flows through this reverse tunnel.

1. Create a token for the Teleport Database Service to use to establish trust with your Teleport cluster.

   On your workstation, run the following command to retrieve a join token and write to a file called `dbtoken` that we'll use when starting the Database Service:

   ```
   $ tctl tokens add --type=db --ttl=15m --format=text > dbtoken
   ```

2. Write a configuration file for the Teleport Database Service to your terminal's current working directory, at the path `db-service-config.yaml`, with the following content, replacing example.beams.sh with the address of your Teleport Proxy Service:

   ```
   $ teleport db configure create \
     -o file:///$(pwd)/db-service-config.yaml \
     --token=/tmp/token \
     --proxy='example.beams.sh:443' \
     --name=local-postgres \
     --protocol=postgres \
     --uri=postgres:5432 \
     --labels=service=local-postgres
   ```

   Note that the Teleport Database Service reads the token from `/tmp/token`, the path on the container where you'll mount the token you generated earlier.

3. Start the Teleport Database Service in the same local Docker network as the PostgreSQL container you launched earlier:

   ```
   $ docker run \
     -v ./db-service-config.yaml:/etc/teleport/teleport.yaml \
     -v ./dbtoken:/tmp/token \
     --network local-postgres \
     public.ecr.aws/gravitational/teleport-distroless:13.3.7
   ```

4. After a minute or two, confirm that Teleport is proxying your PostgreSQL instance:

   ```
   $ tsh db ls
   Name           Description Allowed Users Labels                 Connect
   -------------- ----------- ------------- ---------------------- -------
   local-postgres             (none)        service=local-postgres
   ```

### Configure RBAC for your database

In this demo setup, we want to ensure that your AI agent can access your PostgreSQL instance only with a non-permissive role. AI agents running on a beam access Teleport-protected resources with the Teleport role of the user who accessed the beam.

In this section, you will create a user and role that can access the database as a read-only user.

1. Define a role that can access your database only as the read-only user. Create a file called `read-only-demo-postgres.yaml` with the following content:

   ```
   version: v8
   kind: role
   metadata:
     name: read-only-demo-postgres
   spec:
     allow:
       db_labels:
         service: local-postgres
       db_users:
         - readonly
       db_names:
         - postgres

   ```

2. Create the role:

   ```
   $ tctl create -f read-only-demo-postgres.yaml
   ```

3. Create a user called `dbdemo` with the `read-only-demo-postgres` role:

   ```
   $ tctl users add --roles=read-only-demo-postgres,beam-user dbdemo
   ```

4. Follow the instructions in your terminal to activate your user.

## Step 2/3. Prepare your beam

Once you have a database enrolled with Teleport and a role for your AI agent user, you can create a beam, start an SSH session with it, and prompt the agent to access the database.

1. Authenticate to Teleport as the `dbdemo` user you created in the last step and enter your credentials:

   ```
   $ tsh login --proxy=example.beams.sh --user=dbdemo
   ```

2. Create a beam and access it:

   ```
   $ tsh beams add
   ```

This command starts an SSH session with the new beam.

Stay in the beam shell session for the next step.

## Step 3/3. Prompt your agent

Prompt your agent to access the database.

1. Start your LLM CLI. A beam initializes with `claude` and `codex` preinstalled. Start a session with your LLM agent that skips permission prompts. Even if your agent performs unexpected operations, nothing it does can exceed the limits you set using Teleport RBAC. Run one of the following commands:

   ```
   $ claude --dangerously-skip-permissions
   ```

   Or:

   ```
   $ codex --dangerously-bypass-approvals-and-sandbox
   ```

2. Enter the following prompt:

   ```
   Access the PostgreSQL database with name local-postgres. Retrieve the SSN of
   user alice and update it to 999-99-9999.

   ```

The LLM should successfully find the current SSN but fail to update it. Here is one example agent summary:

```
● The readonly user doesn't have write permissions. That's the only allowed database user according to the
  Teleport configuration. I'm unable to perform the UPDATE — the database role readonly only has SELECT
  privileges on the users table.

  Summary:
  - Alice's current SSN is 000-00-0000 (id: 123)
  - The UPDATE to 999-99-9999 failed because the only available database user (readonly) lacks write permissions
   on the users table

  To complete the update, you'd need a database user with write privileges to be added to the Teleport database
  configuration.

```
