Skip to main content

Deploying Machine ID with Bound Keypair Joining

In this guide, you will install Machine & Workload Identity's agent, tbot, on an arbitrary host using Bound Keypair Joining. This host could be a bare-metal machine, a VM, a container, or any other host - the only requirement is that the host has persistent storage.

Bound Keypair Joining is an improved alternative to secret-based join methods and can function as a drop-in replacement. It is more secure than static token joining, and is more flexible than ephemeral token joining with renewable certificates: when its certificates expire, it can perform an automated recovery to ensure the bot can rejoin even after an extended outage.

Note that platform-specific join methods may be available that are better suited to your environment; refer to the deployment guides for a full list of options.

How it works

With Bound Keypair Joining, Machine & Workload Identity bots generate a unique keypair which is persistently stored in their internal data directory. Teleport is then configured to trust this public key for future joining attempts.

Later, when the bot attempts to join the cluster, Teleport issues it a challenge that can only be completed using its private key. The bot returns the solved challenge, attesting to its own identity, and is conditionally allowed to join the cluster. This process is repeated for every join attempt, but if the bot has been offline long enough for its certificates to expire, it is additionally forced to perform an automatic recovery to join again.

As self attestation is inherently less secure than the external verification that would be provided by a cloud provider like AWS or a dedicated TPM, Bound Keypair Joining enforces a number of additional checks to prevent abuse, including:

  • Join state verification to ensure the keypair cannot be usefully shared or duplicated
  • Certificate generation counter checks to ensure regular bot certificates cannot be usefully shared or duplicated
  • Configurable limits on how often - if at all - bots may be allowed to automatically recover using this keypair

An important benefit to Bound Keypair Joining is that all joining restrictions can be reconfigured at any time, and bots that expire or go offline can be recovered by making a server-side exemption without any client-side intervention.

Refer to the admin guide for further details on how this join method works.

Prerequisites

  • A running Teleport cluster version 18.1.0 or above.
  • The tsh and tctl clients.
  • 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 protected] to your Teleport username:
    tsh login --proxy=teleport.example.com --user=[email protected]
    tctl status

    Cluster teleport.example.com

    Version 18.0.2

    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.
  • This guide assumes the bot host has mutable persistent storage for internal bot data. While it is possible to use Bound Keypair Joining can on immutable hosts (like CI runs), doing so will reduce security guarantees; see the admin guide for further information.

Step 1/5. Install tbot

This step is completed on the bot host.

First, tbot needs to be installed on the host that you wish to use Machine ID on.

Download and install the appropriate Teleport package for your platform:

To install a Teleport Agent on your Linux server:

The easiest installation method, for Teleport versions 17.3 and above, is the cluster install script. It will use the best version, edition, and installation mode for your cluster.

  1. Assign teleport.example.com:443 to your Teleport cluster hostname and port, but not the scheme (https://).

  2. Run your cluster's install script:

    curl "https://teleport.example.com:443/scripts/install.sh" | sudo bash

On older Teleport versions:

  1. Assign edition to one of the following, depending on your Teleport edition:

    EditionValue
    Teleport Enterprise Cloudcloud
    Teleport Enterprise (Self-Hosted)enterprise
    Teleport Community Editionoss
  2. Get the version of Teleport to install. If you have automatic agent updates enabled in your cluster, query the latest Teleport version that is compatible with the updater:

    TELEPORT_DOMAIN=example.teleport.com:443
    TELEPORT_VERSION="$(curl https://$TELEPORT_DOMAIN/v1/webapi/automaticupgrades/channel/default/version | sed 's/v//')"

    Otherwise, get the version of your Teleport cluster:

    TELEPORT_DOMAIN=example.teleport.com:443
    TELEPORT_VERSION="$(curl https://$TELEPORT_DOMAIN/v1/webapi/ping | jq -r '.server_version')"
  3. Install Teleport on your Linux server:

    curl https://cdn.teleport.dev/install.sh | bash -s ${TELEPORT_VERSION} edition

    The installation script detects the package manager on your Linux server and uses it to install Teleport binaries. To customize your installation, learn about the Teleport package repositories in the installation guide.

Step 2/5. Create a Bot

This step is completed on your local machine.

Next, you need to create a Bot. A Bot is a Teleport identity for a machine or group of machines. Like users, bots have a set of roles and traits which define what they can access.

Create bot.yaml:

kind: bot
version: v1
metadata:
  # name is a unique identifier for the Bot in the cluster.
  name: example
spec:
  # roles is a list of roles to grant to the Bot. Don't worry if you don't know
  # what roles you need to specify here, the Access Guides will walk you through
  # creating and assigning roles to the already created Bot.
  roles: []

Make sure you replace example with a unique, descriptive name for your Bot.

Use tctl to apply this file:

tctl create bot.yaml

Step 3/5. Create a join token

This step is completed on your local machine.

In this guide, we'll demonstrate joining a bot using a registration secret: this is a one-time use secret the bot can provide to Teleport to authenticate its first join. Once authenticated, the bot automatically generates a keypair and registers its public key with Teleport for use in all future join attempts.

Create token-example.yaml:

kind: token
version: v2
metadata:
  # This name will be used in tbot's `onboarding.token` field.
  name: example
spec:
  roles: [Bot]
  # bot_name should match the name of the bot created earlier in this guide.
  bot_name: example
  join_method: bound_keypair
  bound_keypair:
    recovery:
      mode: standard
      limit: 1

Replace example in spec.bot_name with the name of the bot you created in the second step.

For this example, we don't need to set any additional options for the bound keypair token. We've allowed a single recovery attempt, which will be used to allow the bot's initial join, and Teleport will generate a registration secret automatically when the token is created as we have not preregistered a public key to use.

Onboarding Options

This example makes use of registration secrets to authenticate the initial join. If desired, it is also possible to generate a key on the bot host first and register it with Teleport out-of-band, avoiding the need to copy secrets between hosts.

To learn more about preregistering public keys and Bound Keypair Joining's other onboarding and recovery options, refer to the Reference and Admin Guide.

Use tctl to apply this file:

tctl create -f token-example.yaml

Next, retrieve the generated registration secret, which will be needed for the next step:

tctl get token/example --format=json | jq -r '.[0].status.bound_keypair.registration_secret'

This assumes jq is installed. If not, run tctl get token/example and inspect the .status.bound_keypair.registration_secret field.

Step 4/5. Configure tbot

This step is completed on the bot host.

Create /etc/tbot.yaml:

version: v2
proxy_server: example.teleport.sh:443
onboarding:
  join_method: bound_keypair
  token: example
  bound_keypair:
    registration_secret: SECRET
storage:
  type: directory
  path: /var/lib/teleport/bot
# outputs will be filled in during the completion of an access guide.
outputs: []

Replace the following:

  • example.teleport.sh:443 with the address of your Teleport Proxy.
  • example with the name of the token created in the previous step, if you changed it from example.
  • SECRET with the registration secret retrieved in the previous step.

Now, you must decide if you want to run tbot as a daemon or in one-shot mode.

In daemon mode, tbot runs continually, renewing the short-lived credentials for the configured outputs on a fixed interval. This is often combined with a service manager (such as systemd) in order to run tbot in the background. This is the default behaviour of tbot.

In one-shot mode, tbot generates short-lived credentials and then exits. This is useful when combining tbot with scripting (such as in CI/CD) as it allows further steps to be dependent on tbot having succeeded. It is important to note that the credentials will expire if not renewed and to ensure that the TTL for the certificates is long enough to cover the length of the CI/CD job.

Configuring tbot as a daemon

By default, tbot will run in daemon mode. However, this must then be configured as a service within the service manager on the Linux host. The service manager will start tbot on boot and ensure it is restarted if it fails. For this guide, systemd will be demonstrated but tbot should be compatible with all common alternatives.

Use tbot install systemd to generate a systemd service file:

sudo tbot install systemd \ --write \ --config /etc/tbot.yaml \ --user teleport \ --group teleport \ --anonymous-telemetry

Ensure that you replace:

  • teleport with the name of Linux user you wish to run tbot as.
  • /etc/tbot.yaml with the path to the configuration file you have created.

You can omit --write to print the systemd service file to the console instead of writing it to disk.

--anonymous-telemetry enables the submission of anonymous usage telemetry. This helps us shape the future development of tbot. You can disable this by omitting this.

Next, enable the service so that it will start on boot and then start the service:

sudo systemctl daemon-reload
sudo systemctl enable tbot
sudo systemctl start tbot

Check the service has started successfully:

sudo systemctl status tbot

Configuring tbot for one-shot mode

To use tbot in one-shot mode, modify /etc/tbot.yaml to add oneshot: true:

version: v2
oneshot: true
auth_server: ...

Now, you should test your tbot configuration. When started, several log messages will be emitted before it exits with status 0:

export TELEPORT_ANONYMOUS_TELEMETRY=1
tbot start -c /etc/tbot.yaml

TELEPORT_ANONYMOUS_TELEMETRY enables the submission of anonymous usage telemetry. This helps us shape the future development of tbot. You can disable this by omitting this.

Step 5/5. Configure outputs

You have now prepared the base configuration for tbot. At this point, it identifies itself to the Teleport cluster and renews its own credentials but does not output any credentials for other applications to use.

Follow one of the access guides to configure an output that meets your access needs.

Next steps