Skip to content

feat: Hardware Key Agent - initialize hardware key service at start of tsh daemon#54226

Merged
Joerger merged 7 commits intomasterfrom
joerger/tshd-init-client-store
Apr 25, 2025
Merged

feat: Hardware Key Agent - initialize hardware key service at start of tsh daemon#54226
Joerger merged 7 commits intomasterfrom
joerger/tshd-init-client-store

Conversation

@Joerger
Copy link
Copy Markdown
Contributor

@Joerger Joerger commented Apr 23, 2025

Changes:

  • Initialize the hardware key agent at the start of tsh daemon
  • Always use the direct PIV service since Teleport Connect's built in hardware key prompts provide the best UX.
    • This avoids some unexpected issues, such as tsh daemon connecting to the hardware key agent that it started due to the client connection forming in the background.
  • Put tshdEventsClient into a protected lazy loading struct for easier usage outside of the daemon service that previously had full ownership.

@Joerger Joerger requested review from gzdunek and ravicious April 23, 2025 03:42
@github-actions github-actions Bot requested review from Tener and strideynet April 23, 2025 03:43
@Joerger Joerger requested review from rosstimothy and zmb3 and removed request for Tener and strideynet April 23, 2025 04:28
Comment thread lib/teleterm/clusters/config.go Outdated
Comment thread lib/teleterm/daemon/config.go Outdated
// The startup of the app is orchestrated so that the client is loaded before any other method on
// daemon.Service. This way all the other code in daemon.Service can assume that the tshd events
// client is available right from the beginning, without the need for nil checks.
TshdEventsClient *tshdEventsClient
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.

Can we avoid having an exported field with an unexported type?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is that bad?

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'm not sure there's a written rule but it's just sorta bad practice.

If you think about it, having it be a private struct does nothing since callers can still call NewTshdEventsClient and call its public methods. However you couldn't do things like add a TshdEventsClient field to structs from other packages, you'd actually need to create an interface to utilize the struct as a field. So IIUC this package should either provide that public interface, or provide a public struct. Or make it private of course.

Comment thread lib/teleterm/daemon/daemon.go
return trace.Wrap(err)
}

// Successfully connected set the client and signal to any waiters.
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.

Can we replace this whole mutex+channel setup thing with sync.Once?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

At first I thought it could be replaced with syncflight.Group but I wasn't 100% sure. When I tried to do so, I realized that syncflight.Group requires both callsites (Connect and GetClient) to be able to instantiate a new client, but GetClient actually cannot do this because it doesn't know the server address. In that way, GetClient needs the channel to wait for the eventual call to Connect to set up the client.

So I think at best both syncflight.Group and sync.Once are only able to get rid of the mutex and then checking the channel in Connect, but that's about it. Though the code might end up expressing the intent a bit better, at first I wasn't sure why connectedChan needs to be read from in Connect.

But then again, I might be wrong as I'm not particularly good at writing concurrent code.

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.

but GetClient actually cannot do this because it doesn't know the server address

I see. sync.OnceValues would be a nice fit if we had the server address up front, but now that I understand things I think this is fine as-is.

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 initially was using a sync.Once in Connect, but a mutex prevents multiple callers of Connect from trying to connect a client at the same time. If we replaced it with a sync.Once, then we'd need to close unused connections which isn't easy to represent with a sync.Once:

	conn, err := grpc.NewClient(serverAddress, withCreds)
	if err != nil {
		return trace.Wrap(err)
	}

	// Successfully connected set the client and signal to any waiters.
	c.connectOnce.Do(func() {
		c.client = api.NewTshdEventsServiceClient(conn)
		close(c.connectedChan)
	})

	// conn leaks if the once condition has already been called.

profileStore := client.NewFSProfileStore(s.Dir)
pfNames, err := profileStore.ListProfiles()
return pfNames, trace.Wrap(err)
return s.ClientStore.ListProfiles()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we wrap the error here?

Copy link
Copy Markdown
Contributor Author

@Joerger Joerger Apr 23, 2025

Choose a reason for hiding this comment

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

If the function already wraps the error, then there's no reason to wrap it unless we want to add a new message. See below trace.Wrap just returns the existing error.

	if traceErr, ok := err.(Error); ok {
		trace = traceErr
	} else {
		trace = newTrace(err)
	}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

All this time I've thought that trace.Wrap is important so that we can capture the stack trace. 🤦 But this is of course done with the runtime package.

Comment thread lib/teleterm/daemon/config.go Outdated
// The startup of the app is orchestrated so that the client is loaded before any other method on
// daemon.Service. This way all the other code in daemon.Service can assume that the tshd events
// client is available right from the beginning, without the need for nil checks.
TshdEventsClient *tshdEventsClient
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is that bad?

s.headlessAuthSemaphore = newWaitSemaphore(maxConcurrentImportantModals, imporantModalWaitDuraiton)

return nil
return s.cfg.TshdEventsClient.Connect(serverAddress)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I get a panic when the frontend app executes this through an RPC.

Logs
TSHD panic: runtime error: invalid memory address or nil pointer dereference
TSHD [signal SIGSEGV: segmentation violation code=0x2 addr=0x0 pc=0x10684313c]
TSHD
TSHD goroutine 44 [running]:
TSHD github.com/gravitational/teleport/lib/teleterm/daemon.(*tshdEventsClient).Connect(0x1084f21e0?, {0x14000b961e0?, 0x0?})
TSHD 	github.com/gravitational/teleport/lib/teleterm/daemon/events_client.go:55 +0x2c
TSHD github.com/gravitational/teleport/lib/teleterm/daemon.(*Service).UpdateAndDialTshdEventsServerAddress(...)
TSHD 	github.com/gravitational/teleport/lib/teleterm/daemon/daemon.go:928
TSHD github.com/gravitational/teleport/lib/teleterm/apiserver/handler.(*Handler).UpdateTshdEventsServerAddress(0x10ac08900?, {0x10858c020?, 0x14000d1b808?}, 0x10457b168?)
TSHD 	github.com/gravitational/teleport/lib/teleterm/apiserver/handler/handler_tshd_events.go:30 +0x30
TSHD github.com/gravitational/teleport/gen/proto/go/teleport/lib/teleterm/v1._TerminalService_UpdateTshdEventsServerAddress_Handler.func1({0x10867c480?, 0x14000bee5a0?}, {0x1081b1c40?, 0x1400079cfc0?})
TSHD 	github.com/gravitational/teleport/gen/proto/go/teleport/lib/teleterm/v1/service_grpc.pb.go:958 +0xd0
TSHD github.com/gravitational/teleport/lib/teleterm/apiserver.New.withErrorHandling.func1({0x10867c480, 0x14000bee5a0}, {0x1081b1c40?, 0x1400079cfc0?}, 0x80?, 0x108423420?)
TSHD 	github.com/gravitational/teleport/lib/teleterm/apiserver/middleware.go:38 +0x40
TSHD github.com/gravitational/teleport/gen/proto/go/teleport/lib/teleterm/v1._TerminalService_UpdateTshdEventsServerAddress_Handler({0x10858c020, 0x140000c1eb0}, {0x10867c480, 0x14000bee5a0}, 0x1400034d180, 0x14000b83880)
TSHD 	github.com/gravitational/teleport/gen/proto/go/teleport/lib/teleterm/v1/service_grpc.pb.go:960 +0x148
TSHD google.golang.org/grpc.(*Server).processUnaryRPC(0x14000ba2800, {0x10867c480, 0x14000bee510}, 0x14000bf0300, 0x14000bcdf50, 0x10ac3a080, 0x0)
TSHD 	google.golang.org/grpc@v1.71.0/server.go:1405 +0xc9c
TSHD google.golang.org/grpc.(*Server).handleStream(0x14000ba2800, {0x10867e000, 0x14000bd84e0}, 0x14000bf0300)
TSHD 	google.golang.org/grpc@v1.71.0/server.go:1815 +0x900
TSHD google.golang.org/grpc.(*Server).serveStreams.func2.1()
TSHD 	google.golang.org/grpc@v1.71.0/server.go:1035 +0x84
TSHD created by google.golang.org/grpc.(*Server).serveStreams.func2 in goroutine 43
TSHD 	google.golang.org/grpc@v1.71.0/server.go:1046 +0x138
MAIN [Main] info: tshd exited with code 2
MAIN [Main] error: Could not fetch root clusters {"name":"TshdRpcError","message":"Connection dropped","stack":"RpcError: Connection dropped

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.

Yeah I forgot to actually set TshdEventsClient 💀

@Joerger Joerger force-pushed the joerger/tshd-init-client-store branch from f9326d4 to 136225a Compare April 23, 2025 18:04
@Joerger Joerger added the no-changelog Indicates that a PR does not require a changelog entry label Apr 23, 2025
Joerger added a commit that referenced this pull request Apr 23, 2025
@Joerger Joerger requested a review from ravicious April 24, 2025 02:28
@Joerger Joerger force-pushed the joerger/tshd-init-client-store branch from f5773e7 to 7d3686a Compare April 24, 2025 02:43
Copy link
Copy Markdown
Member

@ravicious ravicious left a comment

Choose a reason for hiding this comment

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

The app seems to work fine, I tested tshd sending a relogin prompt to the frontend app. If there are any other issues we'll likely catch them during the test plan.

Comment thread lib/teleterm/daemon/events_client.go
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Apr 24, 2025
@Joerger Joerger added this pull request to the merge queue Apr 24, 2025
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Apr 24, 2025
@Joerger Joerger added this pull request to the merge queue Apr 24, 2025
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Apr 24, 2025
@Joerger Joerger enabled auto-merge April 24, 2025 20:50
@Joerger Joerger added this pull request to the merge queue Apr 24, 2025
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Apr 24, 2025
@Joerger Joerger added this pull request to the merge queue Apr 24, 2025
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Apr 24, 2025
@Joerger Joerger added this pull request to the merge queue Apr 24, 2025
Merged via the queue into master with commit 4db4cb3 Apr 25, 2025
41 checks passed
@Joerger Joerger deleted the joerger/tshd-init-client-store branch April 25, 2025 00:06
Joerger added a commit that referenced this pull request Apr 25, 2025
…f `tsh daemon` (#54226)

* * Initialize shared hardware key service and client store for tshd

* Replace CustomHardwareKeyPrompt with SetPrompt

* Add lazy loaded tshd event service client and use it to initialize hardware key prompt early.

* Address comments; Set TshdEventsClient in daemon service.

* Fix test.

* Fix potential race condition on global yubikey service prompt.

* Add test.
Joerger added a commit that referenced this pull request Apr 25, 2025
…f `tsh daemon` (#54226)

* * Initialize shared hardware key service and client store for tshd

* Replace CustomHardwareKeyPrompt with SetPrompt

* Add lazy loaded tshd event service client and use it to initialize hardware key prompt early.

* Address comments; Set TshdEventsClient in daemon service.

* Fix test.

* Fix potential race condition on global yubikey service prompt.

* Add test.
Joerger added a commit that referenced this pull request Apr 25, 2025
…f `tsh daemon` (#54226)

* * Initialize shared hardware key service and client store for tshd

* Replace CustomHardwareKeyPrompt with SetPrompt

* Add lazy loaded tshd event service client and use it to initialize hardware key prompt early.

* Address comments; Set TshdEventsClient in daemon service.

* Fix test.

* Fix potential race condition on global yubikey service prompt.

* Add test.
Joerger added a commit that referenced this pull request Apr 25, 2025
…f `tsh daemon` (#54226)

* * Initialize shared hardware key service and client store for tshd

* Replace CustomHardwareKeyPrompt with SetPrompt

* Add lazy loaded tshd event service client and use it to initialize hardware key prompt early.

* Address comments; Set TshdEventsClient in daemon service.

* Fix test.

* Fix potential race condition on global yubikey service prompt.

* Add test.
Joerger added a commit that referenced this pull request Apr 25, 2025
…f `tsh daemon` (#54226)

* * Initialize shared hardware key service and client store for tshd

* Replace CustomHardwareKeyPrompt with SetPrompt

* Add lazy loaded tshd event service client and use it to initialize hardware key prompt early.

* Address comments; Set TshdEventsClient in daemon service.

* Fix test.

* Fix potential race condition on global yubikey service prompt.

* Add test.
Joerger added a commit that referenced this pull request Apr 25, 2025
…f `tsh daemon` (#54226)

* * Initialize shared hardware key service and client store for tshd

* Replace CustomHardwareKeyPrompt with SetPrompt

* Add lazy loaded tshd event service client and use it to initialize hardware key prompt early.

* Address comments; Set TshdEventsClient in daemon service.

* Fix test.

* Fix potential race condition on global yubikey service prompt.

* Add test.
Joerger added a commit that referenced this pull request Apr 25, 2025
…f `tsh daemon` (#54226)

* * Initialize shared hardware key service and client store for tshd

* Replace CustomHardwareKeyPrompt with SetPrompt

* Add lazy loaded tshd event service client and use it to initialize hardware key prompt early.

* Address comments; Set TshdEventsClient in daemon service.

* Fix test.

* Fix potential race condition on global yubikey service prompt.

* Add test.
Joerger added a commit that referenced this pull request Apr 28, 2025
…f `tsh daemon` (#54226)

* * Initialize shared hardware key service and client store for tshd

* Replace CustomHardwareKeyPrompt with SetPrompt

* Add lazy loaded tshd event service client and use it to initialize hardware key prompt early.

* Address comments; Set TshdEventsClient in daemon service.

* Fix test.

* Fix potential race condition on global yubikey service prompt.

* Add test.
Joerger added a commit that referenced this pull request Apr 28, 2025
…f `tsh daemon` (#54226)

* * Initialize shared hardware key service and client store for tshd

* Replace CustomHardwareKeyPrompt with SetPrompt

* Add lazy loaded tshd event service client and use it to initialize hardware key prompt early.

* Address comments; Set TshdEventsClient in daemon service.

* Fix test.

* Fix potential race condition on global yubikey service prompt.

* Add test.
Joerger added a commit that referenced this pull request Apr 28, 2025
…f `tsh daemon` (#54226)

* * Initialize shared hardware key service and client store for tshd

* Replace CustomHardwareKeyPrompt with SetPrompt

* Add lazy loaded tshd event service client and use it to initialize hardware key prompt early.

* Address comments; Set TshdEventsClient in daemon service.

* Fix test.

* Fix potential race condition on global yubikey service prompt.

* Add test.
Joerger added a commit that referenced this pull request Apr 28, 2025
…f `tsh daemon` (#54226)

* * Initialize shared hardware key service and client store for tshd

* Replace CustomHardwareKeyPrompt with SetPrompt

* Add lazy loaded tshd event service client and use it to initialize hardware key prompt early.

* Address comments; Set TshdEventsClient in daemon service.

* Fix test.

* Fix potential race condition on global yubikey service prompt.

* Add test.
github-merge-queue Bot pushed a commit that referenced this pull request Apr 29, 2025
* feat: Hardware Key Agent - Add `api/utils/keys/hardwarekey` package (#53671)

* Move hardware key files into new hardwarekey package.

* Tidy up PIVSlot logic and remove its piv-go dependency.

* Add godoc comments to cliPrompt methods; Update cliprompt.go license year.

* Add godocs.

* feat: Hardware Key Agent - Add `hardwarekey.Service` interface with adapted PIV implementation (#53674)

* Add hardware key service interface; Add mock service for tests.

* Add piv implementation of hardware key service.

* Remove old yubikey parsing logic in favor of hardwarekey.PrivateKeyRef.

* Remove HardwareSigner in favor of hardwarekey.PrivateKey.

* Add test; Cleanup comment; Don't require pin/touch prompts in tests with MockHarwdareKeyService by default.

* Fix tests.

* Add TODOs.

* Use unhashed digest for WarmupHardwareKey.

* Address comments.

* Fix race condition in test service.

* Address comments.

* feat: Hardware Key Agent - Add `api/harwdarekey/piv` package (#53677)

* Remove YubiKeyPrivateKey

* Remove keys package dependencies from PIV implementation.

* Move PIV implementation into new piv package.

* Move newPrivateKey into YubiKeyService.NewPrivateKey.

* * Clean up separation of concerns between YubiKey and YubiKeyService

* Replace hardwarekey.PrivateKey cache with YubiKey cache for proper support for multiple clusters or yubikeys

* Add YubiKey version field for use in version specific signature edge cases

* Change sharedPIVConnection connection from an embedded field.

* Address comments.

* Add getKeyRef helper method.

* feat: Hardware Key Agent - Enrich the PEM encoded hardware private key file (#53675)

* Enrich hardware key PEM file.

* Add test.

* Validate PrivateKeyRef before/after encode/decode.

* Update api/utils/keys/hardwarekey/hardwarekey.go

Co-authored-by: STeve (Xin) Huang <xin.huang@goteleport.com>

* Validate key ref in hardware key service implementations; Fix merge conflict.

---------

Co-authored-by: STeve (Xin) Huang <xin.huang@goteleport.com>

* feat: Hardware Key Agent - set hardware key service in client store (#53563)

* Replace prompt in keystore with hardware key service in client store.

* Add client StoreConfig and StoreConfigOpt.

* Add client store and key store tests.

* Provide nil service for ProfileStatus's AppsForCluster and DatabasesForCluster methods.

* Address comments.

* Fix test.

* Fix test with cmp.Diff.

* feat: Hardware Key Agent - Propagate contextual key info from key store to hardware key prompts (#53703)

* Propagate contextual key info from key store through to hardware key prompts.

* Remove HardwareKeyPromptConstructor.

* Cleanup; add tests.

* feat: Hardware Key Agent - consolidate globally shared PIV service variables (#53974)

* Consolidate process-wide shared prompt mutex and yubikey connections into a shared YubiKeyService, which will also share the prompt.

* Fix interactive piv service tests.

* Fix wording on comment.

* Move RemoveProfile and ListProfileNames into ProfileStore. (#53781)

* feat: Hardware Key PIN caching (#53976)

* Add PinCachingPrompt.

* Add PINCacheTimeout to auth preference proto message.

* Report PIVPINCacheTimeout through ping; Store PIVPINCacheTimeout in profile.

* Set PIV pin cache timeout for tsh and teleterm.

* Add SetPrompt and GetPrompt to hardware key service interface.

* Cleanup; Add test.

* Address comments.

* Rename to PINCacheTTL.

* Apply suggestions.

* Fix lint.

* Simplify randPIN for test.

* Use math/rand/v2.

* Update terraform docs.

* Revert pin caching change for connect to fix race condition. (#54140)

* feat: Hardware Key Agent (#54026)

* Add HardwareKeyAgent proto service.

* Add hardware key agent client and server implementation.

* Add tsh piv agent command.

* Use hardware key agent service when available.

* * Add config option to Teleport connect to start the hardware key agent server

* Add flag to tsh daemon command to start the hardware key agent server

* Fix hardware key agent client connection for Windows.

* Add hardware key agent service; Add tests.

* Minor cleanup.

* Move hardware key agent proto to /api.

* * Restructure packages based on dependencies.

* Add hardware key agent test coverage for RSA, ECDSA, and ED25519 keys.

* Add PIV test coverage for RSA keys.

* Fix lint.

* Fix lint; Fix test.

* Address comments.

* Address comments.

* Fix merge conflict.

* feat: Hardware Key Agent - require users to configure certificate (#54118)

* * Hardware key agent checks whether a key is configured for Teleport clients before performing a signature.

* Add detailed error message and docs for configuring PIV slot certificate.

* Add additional checks for mismatched public key on PIV slot, which can occur when generating a new key on a PIV slot with an active login session.

* Update api/utils/keys/piv/yubikey.go

Co-authored-by: Zac Bergquist <zac.bergquist@goteleport.com>

* Apply suggestions from code review

Co-authored-by: Paul Gottschling <paul.gottschling@goteleport.com>

---------

Co-authored-by: Zac Bergquist <zac.bergquist@goteleport.com>
Co-authored-by: Paul Gottschling <paul.gottschling@goteleport.com>

* Remove MaxUint32 call to fix builds on 32-bit systems. (#54125)

* feat: Hardware Key Agent - command hint (#54090)

* Supply command for context on hardware key prompt.

* * Include command in Teleport Connect hardware key prompts, excluding tshd commands

* Fix proxy host context passed to Teleport connect hardware key prompts

* Only use direct service for `tsh login` to avoid jumping between clients

* Add new line before command.

* Fix story.

* Address comments.

* Trim forward slash for windows.

* Change proxy_host to proxy_hostname; Update comment.

* feat: Hardware Key Agent w/ PIN caching - fix cross-cluster support (#54144)

* Style hardware key prompt with command in Connect (#54258)

* Style hardware key prompt with command in Connect.

* Move `CliCommand.tsx` to `components`

* Extend stories with a command

* Use `CliCommand` component, improve spacing

* Wrap command in the dialog

* End sentences with a dot

* Add a gap between `CliCommand` and errors in `OnlineDocumentGateway`

---------

Co-authored-by: Grzegorz Zdunek <grzegorz.zdunek@goteleport.com>

* feat: Hardware Key Agent - fix socket replacement on Windows (#54126)

* Prevent windows from trying to reuse the addr and getting a bind error.

* Replace unresponsive windows unix sockets.

* Explicitly check for error message instead of os.Stat.

* Move windowsBindErrMessage.

* Add cross-platform ErrAddrInUse constant.

* Move error constants to hardwarekey package.

* feat: Hardware Key Agent - initialize hardware key service at start of `tsh daemon` (#54226)

* * Initialize shared hardware key service and client store for tshd

* Replace CustomHardwareKeyPrompt with SetPrompt

* Add lazy loaded tshd event service client and use it to initialize hardware key prompt early.

* Address comments; Set TshdEventsClient in daemon service.

* Fix test.

* Fix potential race condition on global yubikey service prompt.

* Add test.

* Require ClientStore in `client.Config` (#54227)

* Invert config.EnableEscapeSequences into config.DisableEscapeSequences so that the default value (false) results in the desired default behavior.

* * Replace MakeDefaultClientConfig with CheckAndSetDefaults

* Require ClientStore to be provided in config

* Remove CustomHardwareKeyPrompt from config

* Set client store in tests that were missing it.

* Ensure tsh only initializes client store once.

* Client config uses its own client store.

* Replace uses of KeysDir with ClientStore.

* Remove unused home apth for vnet process.

* Remove unnecessary profile re-load and helper function.

* Replace sync.Once with atomic; add get/setClientStore.

* Fix uncaught merge conflict.

* Fix test; Add comment for why we initialize the client store atomically.

* Return error when using MemKeyStore for tsh puttyconfig.

* Fix merge conflict.

* feat: PIV PIN Caching - add file config option (#54328)

* Add pin_cache_ttl as file config option.

* Add test.

* Update lib/config/fileconf.go

Co-authored-by: Bernard Kim <bernard@goteleport.com>

---------

Co-authored-by: Bernard Kim <bernard@goteleport.com>

* Restore namespace in client config.

---------

Co-authored-by: STeve (Xin) Huang <xin.huang@goteleport.com>
Co-authored-by: Zac Bergquist <zac.bergquist@goteleport.com>
Co-authored-by: Paul Gottschling <paul.gottschling@goteleport.com>
Co-authored-by: Grzegorz Zdunek <grzegorz.zdunek@goteleport.com>
Co-authored-by: Bernard Kim <bernard@goteleport.com>
github-merge-queue Bot pushed a commit that referenced this pull request Apr 29, 2025
* feat: Hardware Key Agent - Add `api/utils/keys/hardwarekey` package (#53671)

* Move hardware key files into new hardwarekey package.

* Tidy up PIVSlot logic and remove its piv-go dependency.

* Add godoc comments to cliPrompt methods; Update cliprompt.go license year.

* Add godocs.

* feat: Hardware Key Agent - Add `hardwarekey.Service` interface with adapted PIV implementation (#53674)

* Add hardware key service interface; Add mock service for tests.

* Add piv implementation of hardware key service.

* Remove old yubikey parsing logic in favor of hardwarekey.PrivateKeyRef.

* Remove HardwareSigner in favor of hardwarekey.PrivateKey.

* Add test; Cleanup comment; Don't require pin/touch prompts in tests with MockHarwdareKeyService by default.

* Fix tests.

* Add TODOs.

* Use unhashed digest for WarmupHardwareKey.

* Address comments.

* Fix race condition in test service.

* Address comments.

* feat: Hardware Key Agent - Add `api/harwdarekey/piv` package (#53677)

* Remove YubiKeyPrivateKey

* Remove keys package dependencies from PIV implementation.

* Move PIV implementation into new piv package.

* Move newPrivateKey into YubiKeyService.NewPrivateKey.

* * Clean up separation of concerns between YubiKey and YubiKeyService

* Replace hardwarekey.PrivateKey cache with YubiKey cache for proper support for multiple clusters or yubikeys

* Add YubiKey version field for use in version specific signature edge cases

* Change sharedPIVConnection connection from an embedded field.

* Address comments.

* Add getKeyRef helper method.

* Rename NewSoftwarePrivateKey to NewPrivateKey (#53598)

* feat: Hardware Key Agent - Enrich the PEM encoded hardware private key file (#53675)

* Enrich hardware key PEM file.

* Add test.

* Validate PrivateKeyRef before/after encode/decode.

* Update api/utils/keys/hardwarekey/hardwarekey.go

Co-authored-by: STeve (Xin) Huang <xin.huang@goteleport.com>

* Validate key ref in hardware key service implementations; Fix merge conflict.

---------

Co-authored-by: STeve (Xin) Huang <xin.huang@goteleport.com>

* feat: Hardware Key Agent - set hardware key service in client store (#53563)

* Replace prompt in keystore with hardware key service in client store.

* Add client StoreConfig and StoreConfigOpt.

* Add client store and key store tests.

* Provide nil service for ProfileStatus's AppsForCluster and DatabasesForCluster methods.

* Address comments.

* Fix test.

* Fix test with cmp.Diff.

* feat: Hardware Key Agent - Propagate contextual key info from key store to hardware key prompts (#53703)

* Propagate contextual key info from key store through to hardware key prompts.

* Remove HardwareKeyPromptConstructor.

* Cleanup; add tests.

* feat: Hardware Key Agent - consolidate globally shared PIV service variables (#53974)

* Consolidate process-wide shared prompt mutex and yubikey connections into a shared YubiKeyService, which will also share the prompt.

* Fix interactive piv service tests.

* Fix wording on comment.

* Move RemoveProfile and ListProfileNames into ProfileStore. (#53781)

* feat: Hardware Key PIN caching (#53976)

* Add PinCachingPrompt.

* Add PINCacheTimeout to auth preference proto message.

* Report PIVPINCacheTimeout through ping; Store PIVPINCacheTimeout in profile.

* Set PIV pin cache timeout for tsh and teleterm.

* Add SetPrompt and GetPrompt to hardware key service interface.

* Cleanup; Add test.

* Address comments.

* Rename to PINCacheTTL.

* Apply suggestions.

* Fix lint.

* Simplify randPIN for test.

* Use math/rand/v2.

* Update terraform docs.

* Revert pin caching change for connect to fix race condition. (#54140)

* feat: Hardware Key Agent (#54026)

* Add HardwareKeyAgent proto service.

* Add hardware key agent client and server implementation.

* Add tsh piv agent command.

* Use hardware key agent service when available.

* * Add config option to Teleport connect to start the hardware key agent server

* Add flag to tsh daemon command to start the hardware key agent server

* Fix hardware key agent client connection for Windows.

* Add hardware key agent service; Add tests.

* Minor cleanup.

* Move hardware key agent proto to /api.

* * Restructure packages based on dependencies.

* Add hardware key agent test coverage for RSA, ECDSA, and ED25519 keys.

* Add PIV test coverage for RSA keys.

* Fix lint.

* Fix lint; Fix test.

* Address comments.

* Address comments.

* Fix merge conflict.

* feat: Hardware Key Agent - require users to configure certificate (#54118)

* * Hardware key agent checks whether a key is configured for Teleport clients before performing a signature.

* Add detailed error message and docs for configuring PIV slot certificate.

* Add additional checks for mismatched public key on PIV slot, which can occur when generating a new key on a PIV slot with an active login session.

* Update api/utils/keys/piv/yubikey.go

Co-authored-by: Zac Bergquist <zac.bergquist@goteleport.com>

* Apply suggestions from code review

Co-authored-by: Paul Gottschling <paul.gottschling@goteleport.com>

---------

Co-authored-by: Zac Bergquist <zac.bergquist@goteleport.com>
Co-authored-by: Paul Gottschling <paul.gottschling@goteleport.com>

* Remove MaxUint32 call to fix builds on 32-bit systems. (#54125)

* feat: Hardware Key Agent - command hint (#54090)

* Supply command for context on hardware key prompt.

* * Include command in Teleport Connect hardware key prompts, excluding tshd commands

* Fix proxy host context passed to Teleport connect hardware key prompts

* Only use direct service for `tsh login` to avoid jumping between clients

* Add new line before command.

* Fix story.

* Address comments.

* Trim forward slash for windows.

* Change proxy_host to proxy_hostname; Update comment.

* feat: Hardware Key Agent w/ PIN caching - fix cross-cluster support (#54144)

* Style hardware key prompt with command in Connect (#54258)

* Style hardware key prompt with command in Connect.

* Move `CliCommand.tsx` to `components`

* Extend stories with a command

* Use `CliCommand` component, improve spacing

* Wrap command in the dialog

* End sentences with a dot

* Add a gap between `CliCommand` and errors in `OnlineDocumentGateway`

---------

Co-authored-by: Grzegorz Zdunek <grzegorz.zdunek@goteleport.com>

* feat: Hardware Key Agent - fix socket replacement on Windows (#54126)

* Prevent windows from trying to reuse the addr and getting a bind error.

* Replace unresponsive windows unix sockets.

* Explicitly check for error message instead of os.Stat.

* Move windowsBindErrMessage.

* Add cross-platform ErrAddrInUse constant.

* Move error constants to hardwarekey package.

* feat: Hardware Key Agent - initialize hardware key service at start of `tsh daemon` (#54226)

* * Initialize shared hardware key service and client store for tshd

* Replace CustomHardwareKeyPrompt with SetPrompt

* Add lazy loaded tshd event service client and use it to initialize hardware key prompt early.

* Address comments; Set TshdEventsClient in daemon service.

* Fix test.

* Fix potential race condition on global yubikey service prompt.

* Add test.

* Require ClientStore in `client.Config` (#54227)

* Invert config.EnableEscapeSequences into config.DisableEscapeSequences so that the default value (false) results in the desired default behavior.

* * Replace MakeDefaultClientConfig with CheckAndSetDefaults

* Require ClientStore to be provided in config

* Remove CustomHardwareKeyPrompt from config

* Set client store in tests that were missing it.

* Ensure tsh only initializes client store once.

* Client config uses its own client store.

* Replace uses of KeysDir with ClientStore.

* Remove unused home apth for vnet process.

* Remove unnecessary profile re-load and helper function.

* Replace sync.Once with atomic; add get/setClientStore.

* Fix uncaught merge conflict.

* Fix test; Add comment for why we initialize the client store atomically.

* Return error when using MemKeyStore for tsh puttyconfig.

* Fix merge conflict.

* feat: PIV PIN Caching - add file config option (#54328)

* Add pin_cache_ttl as file config option.

* Add test.

* Update lib/config/fileconf.go

Co-authored-by: Bernard Kim <bernard@goteleport.com>

---------

Co-authored-by: Bernard Kim <bernard@goteleport.com>

* Restore namespace in client config.

---------

Co-authored-by: STeve (Xin) Huang <xin.huang@goteleport.com>
Co-authored-by: Zac Bergquist <zac.bergquist@goteleport.com>
Co-authored-by: Paul Gottschling <paul.gottschling@goteleport.com>
Co-authored-by: Grzegorz Zdunek <grzegorz.zdunek@goteleport.com>
Co-authored-by: Bernard Kim <bernard@goteleport.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog Indicates that a PR does not require a changelog entry size/md

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants