-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Add tbot proxy
and tbot db
wrapper commands
#12687
Conversation
This enhances support for identity files in tsh, which previously only worked for regular SSH access. The largest blocker for support is that tsh uses profiles for all non-SSH resource access, and profiles have a direct mapping to some on-disk resources. This patch works around this in a few ways: * Virtual profiles: When an identity file is specified with `-i`, we use it to create an in-memory virtual profile using the cert as the root identity _and_ for every `RouteToDatabase` (and in the future, app) field contained in the cert. * Virtual profile paths: Certain profile operations require paths to valid certificates and other resources on disk, which may not exist inside the identity file. As the driving use-case for this change is integration with Machine ID, we can "cheat" and pass the correct paths to tsh via environment variables. A cooperating wrapper in `tbot` will execute `tsh` with appropriate flags and environment variables, which override tsh's usual certifiate paths. This allows commands like `tsh db connect ...` to work as expected. * Key stores: previously we used a `noLocalKeyStore{}` with which all lookups fail. This patch replaces it with an in-memory keystore if a client key is available. * Profile status: lastly, we add a new `StatusCurrentWithIdentity()` function to load virtual profiles where supported. Some commands are not supported in this PR (like `tsh app ...`), but others don't make sense to support (like cert reissuing). We might consider merging everything into the traditional `StatusCurrent()` when adding app support. App access is still broken and will be addressed in a later change. Partially fixes #11770
Outstanding TODOs:
|
This adds new wrapper commands that leverage tsh for proxy and database access. It also adds a new `tshwrap` helper package which contains utilities for locating the tsh executable, checking its version, and loading all necessary data (certificates, destinations, etc) that will need to be passed to tsh for wrapped commands to function.
325def1
to
be0153b
Compare
Additionally, log a warning when environment variable paths aren't found.
…nded-identityfiles
Co-authored-by: Krzysztof Skrzętnicki <krzysztof.skrzetnicki@goteleport.com>
…nded-identityfiles
…tbot-proxy-wrappers
…into timothyb89/tbot-proxy-wrappers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks solid. There's a test failure for TestDefaultTemplateRendering
which may be relevant though.
It might be easier to rebase this on top of #12855 when thats been merged rather than vice versa.
// sshConfigUnsupportedWarning is used to ensure we don't spam log messages if | ||
// using non-filesystem backends. | ||
var sshConfigUnsupportedWarning sync.Once | ||
|
||
func (c *TemplateSSHClient) Render(ctx context.Context, authClient auth.ClientI, currentIdentity *identity.Identity, destination *DestinationConfig) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be super nice to include a unit-test for this function using the golden
helper, so we can easily see what changes to the logic result in what changes to the generated file in PRs though. More than willing to provide some advice on this, or I will do it post this PR being merged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've gone ahead and done this in #12898 . It should be simple enough to pull that commit into this branch, or approve and merge that PR and then rebase onto it.
You'll need to run the following to regenerate the golden file for your changes in this PR:
GOLDEN_UPDATE=1 go test -run ^TestTemplateSSHClient_Render$ github.com/gravitational/teleport/tool/tbot/config
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a big fan of making the result of these changes obvious during review. Any objections if we try to get this in after v9.3?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yep, I've fixed the failing test, making ssh_config
optional broke it.
I do like the golden approach but let's aim to include that post-v9.3.
A caveat here is that we are looking to squeeze this into v9.3 (end of this week). I have mixed feelings about also squeezing in and backporting a refactoring patch, especially with the timeline constraints. What do you think? |
If that's the case, just get that into 9.3 :) |
This fixes a failing unit test by making the description for `ssh_config` match its behavior in practice. This necessitated passing the destination to all templates, unfortunately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies for the delay.
@@ -88,7 +88,7 @@ type Template interface { | |||
// statically as this must be callable without any auth clients (or any | |||
// secrets) for use with `tbot init`. If an arbitrary number of files must | |||
// be generated, they should be placed in a subdirectory. | |||
Describe() []FileDescription | |||
Describe(destination destination.Destination) []FileDescription |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note for some other time: "destination.Destination" stutters, "destination destination.Destination" triply so. When you get some spare cycles (if ever), consider renaming package and/or type to a combination that doesn't stutters and takes better advantage of both package and type name.
https://github.com/golang/go/wiki/CodeReviewComments#package-names
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's come up before and I agree that it's ugly, but this practically needs to live in its own package to avoid import cycles. Since it's the only thing that will ever live in that package, there's few names that would make sense other than, well, destination
. Always open to suggestions if you've got a more creative solution to offer 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having a quick look the only implementor I found was DestinationDirectory. The destination
package holds an interface and nothing else, which is a bit of a design smell for Go.
I would suggest the following:
- Rename
package destination
topackage destinations
. The main reason is that we can have variables nameddestination
without overshadowing the package name (similar tostrings
orbytes
). - Move
DestinationDirectory
todestinations.Directory
. Names fit nicely and the package now exports something concrete. (IIUC, this won't cause import cycles.) - Ditch the interface, or at the very least ditch it from the
destinations
package. If you do need an interface, spring up one where it's used, preferably with only 1 or 2 methods that the code cares about.
We don't usually need "preemptive" interfaces in Go. Code against the concrete type if you can; if you need an interface, spit it out where it's needed, and only after it has a reason to be there. (The api/ package is the one place where we may want to do differently, but for internal code this should work just fine.)
Co-authored-by: Alan Parra <alan.parra@goteleport.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few ramblings / minor suggestions. Thanks for the fixes.
// Remaining args are stored directly to a []string rather than written to | ||
// a shared ref like most other kingpin args, so we'll need to manually | ||
// move them to the remaining args field. | ||
if len(*dbRemaining) > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kingpin is a bit of a strange choice, cobra is much more common nowadays (I think it leads to better code too, no need for that "what's the command" switch). I assume Teleport predates cobra, hence kingpin.
Just idle musings, no actions expected here.
const ( | ||
// TSHVarName is the name of the environment variable that can override the | ||
// tsh path that would otherwise be located on the $PATH. | ||
TSHVarName = "TSH" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair. Maybe tshwrap.EnvVarName
would cut it, but it's fine as-is.
Co-authored-by: Alan Parra <alan.parra@goteleport.com>
* Extend support for identity files in tsh This enhances support for identity files in tsh, which previously only worked for regular SSH access. The largest blocker for support is that tsh uses profiles for all non-SSH resource access, and profiles have a direct mapping to some on-disk resources. This patch works around this in a few ways: * Virtual profiles: When an identity file is specified with `-i`, we use it to create an in-memory virtual profile using the cert as the root identity _and_ for every `RouteToDatabase` (and in the future, app) field contained in the cert. * Virtual profile paths: Certain profile operations require paths to valid certificates and other resources on disk, which may not exist inside the identity file. As the driving use-case for this change is integration with Machine ID, we can "cheat" and pass the correct paths to tsh via environment variables. A cooperating wrapper in `tbot` will execute `tsh` with appropriate flags and environment variables, which override tsh's usual certifiate paths. This allows commands like `tsh db connect ...` to work as expected. * Key stores: previously we used a `noLocalKeyStore{}` with which all lookups fail. This patch replaces it with an in-memory keystore if a client key is available. * Profile status: lastly, we add a new `StatusCurrentWithIdentity()` function to load virtual profiles where supported. Some commands are not supported in this PR (like `tsh app ...`), but others don't make sense to support (like cert reissuing). We might consider merging everything into the traditional `StatusCurrent()` when adding app support. App access is still broken and will be addressed in a later change. Partially fixes #11770 * Fix failing lint * Add `tbot proxy` and `tbot db` wrapper commands This adds new wrapper commands that leverage tsh for proxy and database access. It also adds a new `tshwrap` helper package which contains utilities for locating the tsh executable, checking its version, and loading all necessary data (certificates, destinations, etc) that will need to be passed to tsh for wrapped commands to function. * Fix failing unit test due to incorrect default IsVirtual profile flag * Combine `StatusCurrentWithIdentity()` into `StatusCurrent()` Additionally, log a warning when environment variable paths aren't found. * Fix virtual profile flag always being true * Update lib/client/api.go Co-authored-by: Krzysztof Skrzętnicki <krzysztof.skrzetnicki@goteleport.com> * Address review feedback * Use `tbot proxy` in generated `ssh_config` * Add tests for mockable parts of our tsh integration * Fix lints * Clarify docstrings in CLIConf * Tweak comment for clarity; fix typo in `onProxyCommand` * Add missing copyright header * Fix failing unit test and pass destination to `Describe()` This fixes a failing unit test by making the description for `ssh_config` match its behavior in practice. This necessitated passing the destination to all templates, unfortunately. * Add a few extra tests * Apply suggestions from code review Co-authored-by: Alan Parra <alan.parra@goteleport.com> * Address another batch of review comments * Comment tweaks * Refactor tshwrap to remove the Runner interface. * Apply suggestions from code review Co-authored-by: Alan Parra <alan.parra@goteleport.com> * Address review comments Co-authored-by: Krzysztof Skrzętnicki <krzysztof.skrzetnicki@goteleport.com> Co-authored-by: Alan Parra <alan.parra@goteleport.com>
* Extend support for identity files in tsh This enhances support for identity files in tsh, which previously only worked for regular SSH access. The largest blocker for support is that tsh uses profiles for all non-SSH resource access, and profiles have a direct mapping to some on-disk resources. This patch works around this in a few ways: * Virtual profiles: When an identity file is specified with `-i`, we use it to create an in-memory virtual profile using the cert as the root identity _and_ for every `RouteToDatabase` (and in the future, app) field contained in the cert. * Virtual profile paths: Certain profile operations require paths to valid certificates and other resources on disk, which may not exist inside the identity file. As the driving use-case for this change is integration with Machine ID, we can "cheat" and pass the correct paths to tsh via environment variables. A cooperating wrapper in `tbot` will execute `tsh` with appropriate flags and environment variables, which override tsh's usual certifiate paths. This allows commands like `tsh db connect ...` to work as expected. * Key stores: previously we used a `noLocalKeyStore{}` with which all lookups fail. This patch replaces it with an in-memory keystore if a client key is available. * Profile status: lastly, we add a new `StatusCurrentWithIdentity()` function to load virtual profiles where supported. Some commands are not supported in this PR (like `tsh app ...`), but others don't make sense to support (like cert reissuing). We might consider merging everything into the traditional `StatusCurrent()` when adding app support. App access is still broken and will be addressed in a later change. Partially fixes #11770 * Fix failing lint * Add `tbot proxy` and `tbot db` wrapper commands This adds new wrapper commands that leverage tsh for proxy and database access. It also adds a new `tshwrap` helper package which contains utilities for locating the tsh executable, checking its version, and loading all necessary data (certificates, destinations, etc) that will need to be passed to tsh for wrapped commands to function. * Fix failing unit test due to incorrect default IsVirtual profile flag * Combine `StatusCurrentWithIdentity()` into `StatusCurrent()` Additionally, log a warning when environment variable paths aren't found. * Fix virtual profile flag always being true * Update lib/client/api.go Co-authored-by: Krzysztof Skrzętnicki <krzysztof.skrzetnicki@goteleport.com> * Address review feedback * Use `tbot proxy` in generated `ssh_config` * Add tests for mockable parts of our tsh integration * Fix lints * Clarify docstrings in CLIConf * Tweak comment for clarity; fix typo in `onProxyCommand` * Add missing copyright header * Fix failing unit test and pass destination to `Describe()` This fixes a failing unit test by making the description for `ssh_config` match its behavior in practice. This necessitated passing the destination to all templates, unfortunately. * Add a few extra tests * Apply suggestions from code review Co-authored-by: Alan Parra <alan.parra@goteleport.com> * Address another batch of review comments * Comment tweaks * Refactor tshwrap to remove the Runner interface. * Apply suggestions from code review Co-authored-by: Alan Parra <alan.parra@goteleport.com> * Address review comments Co-authored-by: Krzysztof Skrzętnicki <krzysztof.skrzetnicki@goteleport.com> Co-authored-by: Alan Parra <alan.parra@goteleport.com> Co-authored-by: Krzysztof Skrzętnicki <krzysztof.skrzetnicki@goteleport.com> Co-authored-by: Alan Parra <alan.parra@goteleport.com>
This adds new wrapper commands that leverage tsh for proxy and database access.
It also adds a new
tshwrap
helper package which contains utilities for locating the tsh executable, checking its version, and loading all necessary data (certificates, destinations, etc) that will need to be passed to tsh for wrapped commands to function.Usage examples:
ssh -F tbot-user/ssh_config user@host.example.com
(should now work both with and without the legacy SSH proxy port enabled)
tbot db --destination-dir=./tbot-user --proxy=proxy.example.com connect db-name
tbot proxy --destination-dir=./tbot-user --proxy=proxy.example.com:3080 db db-name
tbot proxy --destination-dir=./tbot-user --proxy=proxy.example.com:3080 --tunnel db-name
Fixes #11445