From f7caa2e487e0ed807f09523969ee12244062623b Mon Sep 17 00:00:00 2001 From: Noah Stride Date: Mon, 22 Apr 2024 18:19:08 +0100 Subject: [PATCH 1/3] Add `ssh_config` option to control generation of SSH config by Identity Output --- lib/tbot/config/output_identity.go | 43 +++++++++++++++++-- lib/tbot/config/output_identity_test.go | 32 ++++++++++++-- .../TestIdentityOutput_YAML/full.golden | 1 + 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/lib/tbot/config/output_identity.go b/lib/tbot/config/output_identity.go index 2f2c684f6867d..eea9def0482cf 100644 --- a/lib/tbot/config/output_identity.go +++ b/lib/tbot/config/output_identity.go @@ -31,6 +31,25 @@ import ( const IdentityOutputType = "identity" +// SSHConfigMode controls whether to write an ssh_config file to the +// destination directory. +type SSHConfigMode string + +const ( + // SSHConfigModeNone will default to SSHConfigModeOn. + SSHConfigModeNone SSHConfigMode = "" + // SSHConfigModeOff will not write an ssh_config file. This is useful where + // you do not want to use SSH functionality and would like to avoid + // pinging the proxy. + SSHConfigModeOff SSHConfigMode = "off" + // SSHConfigModeOn will write an ssh_config file to the destination + // directory. + // Causes the generation of: + // - ssh_config + // - known_hosts + SSHConfigModeOn SSHConfigMode = "on" +) + // IdentityOutput produces credentials which can be used with `tsh`, `tctl`, // `openssh` and most SSH compatible tooling. It can also be used with the // Teleport API and things which use the API client (e.g the terraform provider) @@ -52,19 +71,26 @@ type IdentityOutput struct { // For now, only SSH is supported. Cluster string `yaml:"cluster,omitempty"` + // SSHConfigMode controls whether to write an ssh_config file to the + // destination directory. Defaults to SSHConfigModeOn. + SSHConfigMode SSHConfigMode `yaml:"ssh_config,omitempty"` + destPath string } func (o *IdentityOutput) templates() []template { - return []template{ + templates := []template{ &templateTLSCAs{}, - &templateSSHClient{ + &templateIdentity{}, + } + if o.SSHConfigMode == SSHConfigModeOn { + templates = append(templates, &templateSSHClient{ getSSHVersion: openssh.GetSystemSSHVersion, executablePathGetter: os.Executable, destPath: o.destPath, - }, - &templateIdentity{}, + }) } + return templates } func (o *IdentityOutput) Render(ctx context.Context, p provider, ident *identity.Identity) error { @@ -121,6 +147,15 @@ func (o *IdentityOutput) CheckAndSetDefaults() error { "destination %q.", o.Destination) } + switch o.SSHConfigMode { + case SSHConfigModeNone: + log.DebugContext(context.TODO(), "Defaulting to SSHConfigModeOn") + o.SSHConfigMode = SSHConfigModeOn + case SSHConfigModeOff, SSHConfigModeOn: + default: + return trace.BadParameter("ssh_config: unrecognized value %q", o.SSHConfigMode) + } + return nil } diff --git a/lib/tbot/config/output_identity_test.go b/lib/tbot/config/output_identity_test.go index f2d310af4eca4..c242824ee8784 100644 --- a/lib/tbot/config/output_identity_test.go +++ b/lib/tbot/config/output_identity_test.go @@ -26,9 +26,10 @@ func TestIdentityOutput_YAML(t *testing.T) { { name: "full", in: IdentityOutput{ - Destination: dest, - Roles: []string{"access"}, - Cluster: "leaf.example.com", + Destination: dest, + Roles: []string{"access"}, + Cluster: "leaf.example.com", + SSHConfigMode: SSHConfigModeOff, }, }, { @@ -45,12 +46,25 @@ func TestIdentityOutput_CheckAndSetDefaults(t *testing.T) { tests := []testCheckAndSetDefaultsCase[*IdentityOutput]{ { name: "valid", + in: func() *IdentityOutput { + return &IdentityOutput{ + Destination: memoryDestForTest(), + Roles: []string{"access"}, + SSHConfigMode: SSHConfigModeOn, + } + }, + }, + { + name: "ssh config mode defaults", in: func() *IdentityOutput { return &IdentityOutput{ Destination: memoryDestForTest(), - Roles: []string{"access"}, } }, + want: &IdentityOutput{ + Destination: memoryDestForTest(), + SSHConfigMode: SSHConfigModeOn, + }, }, { name: "missing destination", @@ -61,6 +75,16 @@ func TestIdentityOutput_CheckAndSetDefaults(t *testing.T) { }, wantErr: "no destination configured for output", }, + { + name: "invalid ssh config mode", + in: func() *IdentityOutput { + return &IdentityOutput{ + Destination: memoryDestForTest(), + SSHConfigMode: "invalid", + } + }, + wantErr: "ssh_config: unrecognized value \"invalid\"", + }, } testCheckAndSetDefaults(t, tests) } diff --git a/lib/tbot/config/testdata/TestIdentityOutput_YAML/full.golden b/lib/tbot/config/testdata/TestIdentityOutput_YAML/full.golden index 9cc0f55ba0040..513ac826ef101 100644 --- a/lib/tbot/config/testdata/TestIdentityOutput_YAML/full.golden +++ b/lib/tbot/config/testdata/TestIdentityOutput_YAML/full.golden @@ -4,3 +4,4 @@ destination: roles: - access cluster: leaf.example.com +ssh_config: "off" From daf5d5fedcab6a409479b97057e485976839993a Mon Sep 17 00:00:00 2001 From: Noah Stride Date: Tue, 23 Apr 2024 18:12:32 +0100 Subject: [PATCH 2/3] Update lib/tbot/config/output_identity.go Co-authored-by: Alan Parra --- lib/tbot/config/output_identity.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tbot/config/output_identity.go b/lib/tbot/config/output_identity.go index eea9def0482cf..f7004c444530a 100644 --- a/lib/tbot/config/output_identity.go +++ b/lib/tbot/config/output_identity.go @@ -149,7 +149,7 @@ func (o *IdentityOutput) CheckAndSetDefaults() error { switch o.SSHConfigMode { case SSHConfigModeNone: - log.DebugContext(context.TODO(), "Defaulting to SSHConfigModeOn") + log.DebugContext(context.Background(), "Defaulting to SSHConfigModeOn") o.SSHConfigMode = SSHConfigModeOn case SSHConfigModeOff, SSHConfigModeOn: default: From 87076c812e22309a0ad1c8390a1f1b091f6ca0c8 Mon Sep 17 00:00:00 2001 From: Noah Stride Date: Wed, 24 Apr 2024 14:51:47 +0100 Subject: [PATCH 3/3] use logrus logging style --- lib/tbot/config/output_identity.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tbot/config/output_identity.go b/lib/tbot/config/output_identity.go index f7004c444530a..7fecd33bed2ca 100644 --- a/lib/tbot/config/output_identity.go +++ b/lib/tbot/config/output_identity.go @@ -149,7 +149,7 @@ func (o *IdentityOutput) CheckAndSetDefaults() error { switch o.SSHConfigMode { case SSHConfigModeNone: - log.DebugContext(context.Background(), "Defaulting to SSHConfigModeOn") + log.Debug("Defaulting to SSHConfigModeOn") o.SSHConfigMode = SSHConfigModeOn case SSHConfigModeOff, SSHConfigModeOn: default: