Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ how to execute the procedure.

Teleport locks allow you to permanently or temporarily revoke access to a number
of different "targets". Supported lock targets include: specific users, roles,
servers, desktops, or MFA devices. After you create a lock, all existing
sessions where the lock applies are terminated and new sessions are rejected
while the lock remains in force.
servers, desktops, or MFA devices. For Machine & Workload Identity bots, this
additionally includes the join token name (for delegated join methods) and the
bot instance UUID. After you create a lock, all existing sessions where the loc
applies are terminated and new sessions are rejected while the lock remains in
force.

For more information, read our
[Session and Identity Locking Guide](../../../identity-governance/locking.mdx).
27 changes: 26 additions & 1 deletion docs/pages/identity-governance/locking.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ A lock can target the following objects or attributes:
cluster)
- a Windows desktop by the desktop's name
- an [Access Request](access-requests/access-requests.mdx) by UUID
- a bot instance ID (for Machine & Workload Identity bots)
- a join token name (for Machine & Workload Identity bots using a [delegated join method](../reference/join-methods.mdx#delegated-join-methods))

## Prerequisites

Expand Down Expand Up @@ -83,6 +85,29 @@ with one of the following options:
# Created a lock with name "dc7cee9d-fe5e-4534-a90d-db770f0234a1".
```
</TabItem>
<TabItem label="Machine & Workload Identity Bot">
The most appropriate locking target for a Machine & Workload Identity bot
depends on its join method.

For [delegated join methods](../reference/join-methods.mdx#secret-vs-delegated),
it's best to target the specific join token the bot is using to join:
```code
$ tctl lock --join-token=example-token-name
```

The join token name cannot be targeted for bots joined using the `token` join
method, so it's best to use the
[bot instance ID](../reference/architecture/machine-id-architecture.mdx#bot-instances):
```code
$ tctl lock --bot-instance-id aabbccdd-1234-5678-0000-3b04d7d03acc
```

In all cases, you may also target the bot user, which will lock all instances
of a bot that share the same underlying user:
```code
$ tctl lock --user bot-example
```
</TabItem>
</Tabs>

<details>
Expand Down Expand Up @@ -209,7 +234,7 @@ auth_service:

Restart or redeploy the Auth Service for the change to take effect.

If not, edit your cluster authentication preference resource:
If not, edit your cluster authentication preference resource:

```code
$ tctl edit cap
Expand Down
65 changes: 65 additions & 0 deletions docs/pages/includes/provision-token/bound-keypair-spec.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
```yaml
kind: token
version: v2
metadata:
name: example-token
spec:
roles: [Bot]
join_method: bound_keypair
bot_name: example

# Fields related to the bound keypair joining process.
bound_keypair:
# Fields related to the initial join attempt.
onboarding:
# If set to a public key in SSH authorized_keys format, the
# joining client must have the corresponding private key to join. This
# keypair may be created using `tbot keypair create`. If set,
# `registration_secret` and `must_register_before` are ignored.
initial_public_key: ""

# If set to a secret string value, a client may use this secret to perform
# the first join without pre-registering a public key in
# `initial_public_key`. If unset and no `initial_public_key` is provided,
# a random value will be generated automatically into
# `.status.bound_keypair.registration_secret`.
registration_secret: ""

# If set to an RFC 3339 timestamp, attempts to register via
# `registration_secret` will be denied once the timestamp has elapsed. If
# more time is needed, this field can be edited to extend the registration
# period.
must_register_before: ""

# Fields related to recovery after certificates have expired.
recovery:
# The maximum number of allowed recovery attempts. This value may
# be raised or lowered after creation to allow additional recovery
# attempts should the initial limit be exhausted. If `mode` is set to
# `standard`, recovery attempts will only be allowed if
# `.status.bound_keypair.recovery_count` is less than this limit. This
# limit is not enforced if `mode` is set to `relaxed` or `insecure`. This
# value must be at least 1 to allow for the initial join during
# onboarding, which counts as a recovery.
limit: 1

# The recovery rule enforcement mode. Valid values:
# - standard (or unset): all configured rules enforced. The recovery limit
# and client join state are required and verified. This is the most
# secure recovery mode.
# - relaxed: recovery limit is not enforced, but client join state is
# still required. This effectively allows unlimited recovery attempts,
# but client join state still helps mitigate stolen credentials.
# - insecure: neither the recovery limit nor client join state are
# enforced. This allows any client with the private key to join freely.
# This is less secure, but can be useful in certain situations, like in
# otherwise unsupported CI/CD providers. This mode should be used with
# care, and RBAC rules should be configured to heavily restrict which
# resources this identity can access.
mode: "standard"

# If set to an RFC 3339 timestamp, once elapsed, a keypair rotation will be
# forced on next join if it has not already been rotated. The most recent
# rotation is recorded in `.status.bound_keypair.last_rotated_at`.
rotate_after: ""
```
Comment thread
timothyb89 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
---
title: Deploying Machine ID with Bound Keypair Joining
description: "How to install and configure 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][secret] 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](./deployment.mdx) 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][guide] for further details on how this join method
works.

## Prerequisites

{/* note: consider edition-prereqs-tabs.mdx include for v19; it is misleading due to the minor launch release */}

- A running Teleport cluster version 18.1.0 or above.
- The `tsh` and `tctl` clients.
- (!docs/pages/includes/tctl.mdx!)
- 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][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:

(!docs/pages/includes/install-linux.mdx!)

## Step 2/5. Create a Bot

**This step is completed on your local machine.**

(!docs/pages/includes/machine-id/create-a-bot.mdx!)

## 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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would mention both approaches before we narrow down on one, just so the reader knows there's another option.

Maybe:

The initial joining operation can operate in two modes. The first is by using
a registration secret, which is similar to the first join process with the token
join method. Alternatively, initial joining can be performed with a public key.

In this guide, we will demonstrate joining using a registration secret.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added an explicit reference (and a link) in the admonition, hopefully it makes the existence of the alternative clear? Trying to balance clarity with the guide only actually showing how to accomplish a single mode.

(Maybe showing both paths in the guide will be more reasonable with a tctl helper - may update this further if so)

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`:

```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.

<Admonition type="tip" title="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][guide].
</Admonition>

Use `tctl` to apply this file:

```code
$ tctl create -f token-example.yaml
```

Next, retrieve the generated registration secret, which will be needed for the
next step:
```code
$ tctl get token/example --format=json | jq -r '.[0].status.bound_keypair.registration_secret'
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This flow might be much easier to document (and user friendly) if we had a tctl tokens add command which created the token and output the registration secret.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hrm, I agree. I'll see if I can't throw something together.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've explored this a little bit and think it's best to defer it, at least for now. I do very much want to see this, but it doesn't look as simple to implement as I'd like, at least without taking ugly shortcuts. tctl tokens add doesn't support multiple join methods today (only token) and we hit UX problems if we try to change that. (What about every other join method? How do we handle it only supporting bots?)

The existing tctl bots add is a better candidate but has the same problem - it only issues token-type tokens. That said, I'd like to switch the default for this command to bound_keypair in v19, since it should be a drop-in replacement. Maybe that would be a good opportunity to make the change without having to worry about supporting more than one token type?

```

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`:

```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.

(!docs/pages/includes/machine-id/daemon-or-oneshot.mdx!)

## Step 5/5. Configure outputs

(!docs/pages/includes/machine-id/configure-outputs.mdx!)

## Next steps

- Read the [Bound Keypair Joining Reference and Admin Guide][guide]
for more details about the join method and the available configuration options.
- Follow the [access guides](../access-guides/access-guides.mdx) to finish configuring `tbot` for
your environment.
- Read the [configuration reference](../../../reference/machine-id/configuration.mdx) to explore
all the available configuration options.
- [More information about `TELEPORT_ANONYMOUS_TELEMETRY`.](../../../reference/machine-id/telemetry.mdx)

{/*
TODO: guide link above is a placeholder, link to the real guide once merged in
follow-up PR.
[guide]: ../../../reference/machine-id/bound-keypair.mdx
*/}

[secret]: ../../../reference/join-methods.mdx#secret-vs-delegated
[guide]: ../../../reference/machine-id/machine-id.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,15 @@ and [Architecture](../../../reference/architecture/machine-id-architecture.mdx)
Read the following guides for how to deploy Machine ID on your cloud platform or
on-prem infrastructure.

| Platform | Installation method | Join method |
|-------------------------------------------|-------------------------------------------------|-----------------------------------------------------|
| [Linux](linux.mdx) | Package manager or TAR archive | Static join token |
| [Linux (TPM)](linux-tpm.mdx) | Package manager or TAR archive | Attestation from TPM 2.0 |
| [GCP](gcp.mdx) | Package manager, TAR archive, or Kubernetes pod | Identity document signed by GCP |
| [AWS](aws.mdx) | Package manager, TAR archive, or Kubernetes pod | Identity document signed by AWS |
| [Azure](azure.mdx) | Package manager or TAR archive | Identity document signed by Azure |
| [Kubernetes](kubernetes.mdx) | Kubernetes pod | Identity document signed by your Kubernetes cluster |
| Platform | Installation method | Join method |
|--------------------------------------------|-------------------------------------------------|-----------------------------------------------------|
| [Linux](linux.mdx) | Package manager or TAR archive | Static join token |
| [Linux (TPM)](linux-tpm.mdx) | Package manager or TAR archive | Attestation from TPM 2.0 |
| [Linux (Bound Keypair)](bound-keypair.mdx) | Package manager or TAR archive | Bound Keypair |
| [GCP](gcp.mdx) | Package manager, TAR archive, or Kubernetes pod | Identity document signed by GCP |
| [AWS](aws.mdx) | Package manager, TAR archive, or Kubernetes pod | Identity document signed by AWS |
| [Azure](azure.mdx) | Package manager or TAR archive | Identity document signed by Azure |
| [Kubernetes](kubernetes.mdx) | Kubernetes pod | Identity document signed by your Kubernetes cluster |

### CI/CD

Expand Down
Loading
Loading