-
Notifications
You must be signed in to change notification settings - Fork 2k
MWI: Add documentation for bound keypair joining #56604
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
85089b5
5324dad
72667fd
cf2d999
fc898f5
e7c4237
c8ea87a
5e49293
cf57e4c
6556cd0
e723101
af9941b
c87b4ad
8b80c8a
1a086d2
a9acbbb
7b32e94
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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: "" | ||
| ``` |
| 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 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
| 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' | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. The existing |
||
| ``` | ||
|
|
||
| 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 | ||
Uh oh!
There was an error while loading. Please reload this page.