This changes prompt.ContextReader in the following ways:
Reads only happen as a response to Read methods being called. This allows
ContextReader to coexist with other readers as long as no reads are abandoned.
ReadPassword is now available, the underlying implementation being
term.ReadPassword. An abandoned password read may be turned into a clean read.
This gives us some UX flexibility when callers abandon password reads (looking
at you, PromptMFAChallenge). Turning clean reads into password reads is not
supported. It's tricky and I have a few ideas, but it's not paramount at this
moment.
This solves the woes caused by abandoned OTP reads followed by PIN reads in
different packages, such as client.PromptMFAChallenge followed by tsh mfa add's
implementation.
#9160
* Move ContextReader to its own file
* Refactor ContextReader and implement ReadPassword
* Test ReadPassword
* Fix typos
* Remove prompt.StdinSync()
prompt.Stdin() has the same behavior for non-abandoned reads.
* Group /x/term methods under a type
Passwordless login is enabled by the global `--pwdless` flag. Registration gets
a new prompt and an `--allow-passwordless` flag.
UX messages were tweaked to follow the descriptions on RFD 53: Passwordless
FIDO2[1].
Passwordless login requires two touches for all devices (both PIN and biometric).
I'd like to get it down to a single touch, at least for the most common
situations, but that'll be a follow up to this work.
Passwordless support requires `tsh` to be compiled with the `libfido2` tag, try
`go build -tags=libfido2 ./tool/tsh`.
#9160
[1] https://github.com/gravitational/teleport/blob/master/rfd/0053-passwordless-fido2.md#ux
* Allow reuse of devices for passwordless
* Implement passwordless registration in tsh
* Add better tracing to FIDO2 filters
* Implement passwordless logins in tsh
* Make --pwdless a global flag
* Fix lint errors
* Fix U2F tests
* Use initClient's URL as origin
* Distinguish whether --allow-passwordless is set or unset
Seamlessly change the public API of lib/auth/webauthncli to use the
libfido2-backed implementation, as long as the binary was compiled with the
libfido2 build tag.
A few adjustments are necessary to "wancli" methods to allow users to provide
prompt callbacks and to return the credential user (not applicable here, but
will be in following PRs).
Additional changes are made to tsh mfa add in order to avoid stdin hijacking by
ContextReader, since we now may require PIN reads for authenticators.
#9160
* Move U2F logic to u2f_* files
* Split U2F API from general l/a/webauthncli API
* Move FIDO2 public API to fido2_common.go, introduce IsFIDO2Available
* Introduce prompt.SyncReader
Sync reads allow prompt calls to be mixed with term.ReadPassword calls.
* Wire FIDO2 into MFA login
* Wire FIDO2 into MFA registration
The default `join_method` value was improperly assumed to be "" which
caused any onboarding config from the config file to be overwritten.
This uses the correct default and allows bots to be fully onboarded
via config file.
Fixes#11099
The inferred default was changed without updating the flag's help
message. This updates the help message to explain the new default
value of `--owner`.
- changes to configuration.go: fixes tsh login in first test case
`tsh login --insecure --proxy=127.0.0.1:3080 --user=test`
- changes to apiserver.go fixes `--auth` not showing motd
`staticcheck` does not seem to appreciate our nop implementations for
non-Linux OSes and produces several noisy warnings about it. This
disables the lints as precisely as possible.
* UX improvements for tbot
A last batch of UX tweaks for 9.0:
- rename --renew-interval -> renewal-interval
- add `--oneshot` mode to fetch one set of certs and exit (client
side only, no server enforcement yet)
- add `tbot version`
- add unix signal handling: graceful exit on SIGINT, reload on
SIGHUP/SIGUSR1
- make auth server an optional config option and check it only when
needed (i.e. `tbot start`)
* Remove `--auth-server` flag from `tbot init` example
* Add `cut` workaround to allow connecting to nodes without DNS
* Update product name in tbot CLI help
* Add `--format=json` support to `tctl bots add`
* Detect OpenSSH version and conditionally remove the RSA deprecation workaround
* Fix failing unit test after rename
* Update tool/tbot/config/configtemplate_ssh.go
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Alan Parra <alan.parra@goteleport.com>
* Document IncludeRSAWorkaround and address review comments
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
Co-authored-by: Alan Parra <alan.parra@goteleport.com>
* Fix goroutine and memory leak in watchCertAuthorities
The CA Watcher was blocking both on writing to a channel when the watcher
was closed and on HTTP calls that had no request timeout or context passed
to cause cancellation.
All resourceWatcher implementations that had a bug which may cause them to block
on writing to a channel forever were fixed by selecting on the write and ctx.Done.
Adding context.Context to all Get/Put/Post/Delete methods on the auth HTTPClient to
force callers to propagate context. Prior all calls used context.TODO which
prevents requests from being properly cancelled.
Add context propagation to RotateCertAuthority, RotateExternalCertAuthority,
GetCertAuthority, GetCertAuthorities. This is needed to get the correct ctx
from the CertAtuhorityWatcher all the way down to the HTTPClient that makes
the call.
Closes#10648
* Add certificate renewal bot
This adds a new `tbot` tool to continuously renew a set of
certificates after registering with a Teleport cluster using a
similar process to standard node joining.
This makes some modifications to user certificate generation to allow
for certificates that can be renewed beyond their original TTL, and
exposes new gRPC endpoints:
* `CreateBotJoinToken` creates a join token for a bot user
* `GenerateInitialRenewableUserCerts` exchanges a token for a set of
certificates with a new `renewable` flag set
A new `tctl` command, `tctl bots add`, creates a bot user and calls
`CreateBotJoinToken` to issue a token. A bot instance can then be
started using a provided command.
* Cert bot refactoring pass
* Use role requests to split renewable certs from end-user certs
* Add bot configuration file
* Use `teleport.dev/bot` label
* Remove `impersonator` flag on initial bot certs
* Remove unnecessary `renew` package
* Misc other cleanup
* Do not pass through `renewable` flag when role requests are set
This adds additional restrictions on when a certificate's `renewable`
flag is carried over to a new certificate. In particular, it now also
denies the flag when either role requests are present, or the
`disallowReissue` flag has been previously set.
In practice `disallow-reissue` would have prevented any undesired
behavior but this improves consistency and resolves a TODO.
* Various tbot UX improvements; render SSH config
* Fully flesh out config template rendering
* Fix rendering for SSH configuration templates
* Added `String()` impls for destination types
* Improve certificate renewal logging; show more detail
* Properly fall back to default (all) roles
* Add mode hints for files
* Add/update copyright headers
* Add stubs for tbot init and watch commands
* Add gRPC endpoints for managing bots
* Add `CreateBot`, `DeleteBot`, and `GetBotUsers` gRPC endpoints
* Replace `tctl bot (add|rm|ls)` implementations with gRPC calls
* Define a few new constants, `DefaultBotJoinTTL`, `BotLabel`,
`BotGenerationLabel`
* Fix outdated destination flag in example tbot command
* Bugfix pass for demo
* Fixed a few nil pointer derefs when using config from CLI args
* Properly create destination if `--destination-dir` flag is used
* Remove improper default on CLI flag
* `DestinationConfig` is now a list of pointers
* Address first wave of review feedback
Fixes the majority of smaller issues caught by reviewers, thanks all!
* Add doc comments for bot.go functions
* Return the token TTL from CreateBot
* Split initial user cert issuance from `generateUserCerts()`
Issuing initial renewable certificate ended up requiring a lot of
hacks to skip checks that prevented anonymous bots from getting
certs even though we'd verified their identity elsewhere (via token).
This reverts all those hacks and splits initial bot cert logic into a
dedicated `generateInitialRenewableUserCerts()` function which should
make the whole process much easier to follow.
* Set bot traits to silence log messages
* tbot log message consistency pass
* Implement `tbot init` subcommand
This adds a new CLI subcommand to initialize a tbot destination
directory by creating required files ahead of time and assigning
proper permissions (and ACLs, where possible).
* Resolve lints
* Add config tests
* Remove CreateBotJoinToken endpoint
Users should instead use the CreateBot/DeleteBot endpoints.
* Create a fresh private key for every impersonated identity renewal
* Hide `config` subcommand
* Rename bot label prefix to `teleport.internal/`
* Use types.NewRole() to create bot roles
* Clean up error handling in custom YAML unmarshallers
Also, add notes about the supported YAML shapes.
* Fetch proxy host via gRPC Ping() instead of GetProxies()
* Update lib/auth/bot.go
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* Fix some review comments
* Add renewable certificate generation checks (#10098)
* Add renewable certificate generation checks
This adds a new validation check for renewable certificates that
maintains a renewal counter as both a certificate extension and a
user label. This counter is used to ensure only a single certificate
lineage can exist: for example, if a renewable certificate is stolen,
only one copy of the certificate can be renewed as the generation
counter will not match
When renewing a certificate, first the generation counter presented
by the user (via their TLS identity) is compared to a value stored
with the associated user (in a new `teleport.dev/bot-generation`
label field). If they aren't equal, the renewal attempt fails.
Otherwise, the generation counter is incremented by 1, stored to the
database using a `CompareAndSwap()` to ensure atomicity, and set on
the generated certificate for use in future renewals.
* Add unit tests for the generation counter
This adds new unit tests to exercise the generation counter checks.
Additionally, it fixes two other renewable cert tests that were
failing.
* Remove certRequestGeneration() function
* Emit audit event when cert generations don't match
* Fully implement `tctl bots lock`
* Show bot name in `tctl bots ls`
* Lock bots when a cert generation mismatch is found
* Make CompareFailed respones from validateGenerationLabel() more actionable
* Update lib/services/local/users.go
Co-authored-by: Nic Klaassen <nic@goteleport.com>
* Backend changes for tbot IoT and AWS joining (#10360)
* backend changes
* add token permission check
* pass ctx from caller
Co-authored-by: Roman Tkachenko <roman@goteleport.com>
* fix comment typo
Co-authored-by: Roman Tkachenko <roman@goteleport.com>
* use UserMetadata instead of Identity in RenewableCertificateGenerationMismatch event
* Client changes for tbot IoT joining (#10397)
* client changes
* delete replaced APIs
* delete unused tbot/auth.go
* add license header
* don't unecessarily fetch host CA
* log fixes
* s/tunnelling/tunneling/
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* auth server addresses may be proxies
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* comment typo fix
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* move *Server methods out of auth_with_roles.go (#10416)
Co-authored-by: Tim Buckley <tim@goteleport.com>
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
Co-authored-by: Tim Buckley <tim@goteleport.com>
Co-authored-by: Roman Tkachenko <roman@goteleport.com>
Co-authored-by: Tim Buckley <tim@goteleport.com>
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
Co-authored-by: Nic Klaassen <nic@goteleport.com>
Co-authored-by: Roman Tkachenko <roman@goteleport.com>
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* Address another batch of review feedback
* Addres another batch of review feedback
Add `Role.SetMetadata()`, simplify more `trace.WrapWithMessage()`
calls, clear some TODOs and lints, and address other misc feedback
items.
* Fix lint
* Add missing doc comments to SaveIdentity / LoadIdentity
* Remove pam tag from tbot build
* Update note about bot lock deletion
* Another pass of review feedback
Ensure all requestable roles exist when creating a bot, adjust the
default renewable cert TTL down to 1 hour, and check types during
`CompareAndSwapUser()`
* Remove ModeHint
* Rename Identity.Cert and Identity.XCert
* Add `symlinks` flag to tbot config
The optional symlinks flag for directory destinations allows users to
opt in / out of whichever symlink attack hardening mode is selected
by default.
* Add mostly-working secure implementation of botfs.Create/Write
This adds symlink mode selection (secure, try-secure, insecure) and
Linux `Create()`/`Write()` implementations to open files safely.
* Add configurable ACL modes and verify ACL support in tbot init
* Initialize destinations at startup and test before renewal
This initializes destinations at startup (to create directories if
not using `tbot init`) and tests them to ensure the bot can write
_before_ attempting to renew certificates; this should prevent most
accidental generation counter locks.
* Hide watch for now
* Issue a new identity if a token change is detected
* Warn if identity appears to be expired on startup
* Fully implement ACL Verify and Configure
- Fully implements ACL support for Linux
- Adds bot-side verification support to ensure ACLs are configured
properly at runtime.
- Gracefully falls back to no ACLs if the platform / filesystem
doesn't support them
- Clear up outstanding lints
* Make `tbot init` work without a config file
* Show init instructions in tctl bots add
Also:
- Make --bot-user a flag in init (the tctl instructions were
confusing otherwise)
- Handle IsOwnedBy sanely on unsupported platforms
- Add Bold colorizing support
* Clear some TODOs and rephrase tctl help
* Fix typo
* Fix token hash detection bug
* Actually read and write certs with symlink enforcement
Also, fix a config loading bug where CheckAndSetDefaults() wasn't
being called in all cases with CLI destinations.
* Add workaround for OpenSSH permissions check with ACLs
OpenSSH has an overly-paranoid permissions check that forces key
files to be exclusively owner-readable. Unfortunately, for POSIX
compatibility purposes, when ACLs are set, the ACL mask is set as
the group permissions. This effectively makes any ACL incompatible
with OpenSSH.
However, OpenSSH's check does have an escape hatch: it only applies
if the current user is the owner of the file. Therefore, this change
tweaks the `tbot init` flow to create files as root, owned by a
separate user (either `nobody` or even the bot user), with ACL
permissions granting both the bot and reader user access to the
certificates. This effectively bypasses OpenSSH's permissions check
and should preserve our security boundaries.
* Fix lints
* Fix an improper directory chmod to 0600 if ACL test fails
* First pass of tbot init unit tests
* Add symlink tests and fix bug with resolving the default owner
* Fix err misuse
* Fix an ACL error if the bot or reader user is the owner.
* Fix typo
* Fix missing error case in VerifyACL causing unreadable directories
* Address review feedback
- Rename ACLOn -> ACLRequired
- Simplify fs_linux.Read()
- Add missing fs_other.Read()
- Hoist renewal loop logic into its own function
- A few misc bugfixes
* Apply suggestions from code review
Co-authored-by: rosstimothy <39066650+rosstimothy@users.noreply.github.com>
* Address review feedback
- Only log syscall warning once
- Formatting and wording changes
- Improve error handling for `--clean`
* Fix lint error
* Fix imports in fs_other
* Fix possible nil pointer deref if storage is unset
* Use the bot user as default owner
This is more likely to be a safe owner choice than `nobody:nobody`.
* Apply suggestions from code review
Co-authored-by: Roman Tkachenko <roman@goteleport.com>
* Code review fixes
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
Co-authored-by: Nic Klaassen <nic@goteleport.com>
Co-authored-by: Roman Tkachenko <roman@goteleport.com>
Co-authored-by: rosstimothy <39066650+rosstimothy@users.noreply.github.com>
Before this commit, if `--proxy` was set, it would be passed as it to the kubeconfig file. Due to this, if the `--proxy` URL did not have a scheme, it would default to `http`, leading to the issue reported in https://github.com/gravitational/cloud/issues/1358.
With this commit, we now try to parse the `--proxy` URL and set its scheme to `https` in case it's not set.
In case it's set, we only allow `--proxy` URLs with the `http` and `https` schemes.
* Enforce that a leaf cluster has sent us just a single host CA
* Test coverage for validateTrustedCluster
* Add `tctl rm cert_authority/kind/name`
* Check against existing trusted clusters
* Add certificate renewal bot
This adds a new `tbot` tool to continuously renew a set of
certificates after registering with a Teleport cluster using a
similar process to standard node joining.
This makes some modifications to user certificate generation to allow
for certificates that can be renewed beyond their original TTL, and
exposes new gRPC endpoints:
* `CreateBotJoinToken` creates a join token for a bot user
* `GenerateInitialRenewableUserCerts` exchanges a token for a set of
certificates with a new `renewable` flag set
A new `tctl` command, `tctl bots add`, creates a bot user and calls
`CreateBotJoinToken` to issue a token. A bot instance can then be
started using a provided command.
* Cert bot refactoring pass
* Use role requests to split renewable certs from end-user certs
* Add bot configuration file
* Use `teleport.dev/bot` label
* Remove `impersonator` flag on initial bot certs
* Remove unnecessary `renew` package
* Misc other cleanup
* Do not pass through `renewable` flag when role requests are set
This adds additional restrictions on when a certificate's `renewable`
flag is carried over to a new certificate. In particular, it now also
denies the flag when either role requests are present, or the
`disallowReissue` flag has been previously set.
In practice `disallow-reissue` would have prevented any undesired
behavior but this improves consistency and resolves a TODO.
* Various tbot UX improvements; render SSH config
* Fully flesh out config template rendering
* Fix rendering for SSH configuration templates
* Added `String()` impls for destination types
* Improve certificate renewal logging; show more detail
* Properly fall back to default (all) roles
* Add mode hints for files
* Add/update copyright headers
* Add stubs for tbot init and watch commands
* Add gRPC endpoints for managing bots
* Add `CreateBot`, `DeleteBot`, and `GetBotUsers` gRPC endpoints
* Replace `tctl bot (add|rm|ls)` implementations with gRPC calls
* Define a few new constants, `DefaultBotJoinTTL`, `BotLabel`,
`BotGenerationLabel`
* Fix outdated destination flag in example tbot command
* Bugfix pass for demo
* Fixed a few nil pointer derefs when using config from CLI args
* Properly create destination if `--destination-dir` flag is used
* Remove improper default on CLI flag
* `DestinationConfig` is now a list of pointers
* Address first wave of review feedback
Fixes the majority of smaller issues caught by reviewers, thanks all!
* Add doc comments for bot.go functions
* Return the token TTL from CreateBot
* Split initial user cert issuance from `generateUserCerts()`
Issuing initial renewable certificate ended up requiring a lot of
hacks to skip checks that prevented anonymous bots from getting
certs even though we'd verified their identity elsewhere (via token).
This reverts all those hacks and splits initial bot cert logic into a
dedicated `generateInitialRenewableUserCerts()` function which should
make the whole process much easier to follow.
* Set bot traits to silence log messages
* tbot log message consistency pass
* Resolve lints
* Add config tests
* Remove CreateBotJoinToken endpoint
Users should instead use the CreateBot/DeleteBot endpoints.
* Create a fresh private key for every impersonated identity renewal
* Hide `config` subcommand
* Rename bot label prefix to `teleport.internal/`
* Use types.NewRole() to create bot roles
* Clean up error handling in custom YAML unmarshallers
Also, add notes about the supported YAML shapes.
* Fetch proxy host via gRPC Ping() instead of GetProxies()
* Update lib/auth/bot.go
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* Fix some review comments
* Add renewable certificate generation checks (#10098)
* Add renewable certificate generation checks
This adds a new validation check for renewable certificates that
maintains a renewal counter as both a certificate extension and a
user label. This counter is used to ensure only a single certificate
lineage can exist: for example, if a renewable certificate is stolen,
only one copy of the certificate can be renewed as the generation
counter will not match
When renewing a certificate, first the generation counter presented
by the user (via their TLS identity) is compared to a value stored
with the associated user (in a new `teleport.dev/bot-generation`
label field). If they aren't equal, the renewal attempt fails.
Otherwise, the generation counter is incremented by 1, stored to the
database using a `CompareAndSwap()` to ensure atomicity, and set on
the generated certificate for use in future renewals.
* Add unit tests for the generation counter
This adds new unit tests to exercise the generation counter checks.
Additionally, it fixes two other renewable cert tests that were
failing.
* Remove certRequestGeneration() function
* Emit audit event when cert generations don't match
* Fully implement `tctl bots lock`
* Show bot name in `tctl bots ls`
* Lock bots when a cert generation mismatch is found
* Make CompareFailed respones from validateGenerationLabel() more actionable
* Update lib/services/local/users.go
Co-authored-by: Nic Klaassen <nic@goteleport.com>
* Backend changes for tbot IoT and AWS joining (#10360)
* backend changes
* add token permission check
* pass ctx from caller
Co-authored-by: Roman Tkachenko <roman@goteleport.com>
* fix comment typo
Co-authored-by: Roman Tkachenko <roman@goteleport.com>
* use UserMetadata instead of Identity in RenewableCertificateGenerationMismatch event
* Client changes for tbot IoT joining (#10397)
* client changes
* delete replaced APIs
* delete unused tbot/auth.go
* add license header
* don't unecessarily fetch host CA
* log fixes
* s/tunnelling/tunneling/
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* auth server addresses may be proxies
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* comment typo fix
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* move *Server methods out of auth_with_roles.go (#10416)
Co-authored-by: Tim Buckley <tim@goteleport.com>
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
Co-authored-by: Tim Buckley <tim@goteleport.com>
Co-authored-by: Roman Tkachenko <roman@goteleport.com>
Co-authored-by: Tim Buckley <tim@goteleport.com>
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
Co-authored-by: Nic Klaassen <nic@goteleport.com>
Co-authored-by: Roman Tkachenko <roman@goteleport.com>
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
* Address another batch of review feedback
* Addres another batch of review feedback
Add `Role.SetMetadata()`, simplify more `trace.WrapWithMessage()`
calls, clear some TODOs and lints, and address other misc feedback
items.
* Fix lint
* Add missing doc comments to SaveIdentity / LoadIdentity
* Remove pam tag from tbot build
* Update note about bot lock deletion
* Another pass of review feedback
Ensure all requestable roles exist when creating a bot, adjust the
default renewable cert TTL down to 1 hour, and check types during
`CompareAndSwapUser()`
Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
Co-authored-by: Nic Klaassen <nic@goteleport.com>
Co-authored-by: Roman Tkachenko <roman@goteleport.com>
* Add support for windows desktop services proxying different desktops
* Add filter to GetWindowsDesktops, remove GetWindowsDesktop and GetWindowsDesktopByName
* Cache cleanup
* Fix cache deletes for Windows desktops
For deletes, the cache only gets the backend key, not the entire
resource. Do what database access does, which is to extract the
host ID from the path, and stuff it in the description field of
the resource header.
* Godoc cleanup
* Fix lint
* Address review comments
* Send error message if no desktop found
* Revert to x/net/websocket
This got converted to gorilla/websocket as part of moderated sessions.
We'll do a more intentional conversion post-release.
* fix lint
Co-authored-by: Zac Bergquist <zac.bergquist@goteleport.com>
Add support for Database Access for Redis for standalone and cluster self-hosted instances. Teleport requires mTLS in order to connect to Redis instance which is only supported in Redis 6.0+. RESP2 is currently the only supported protocol.