From 35f9f3c0be36c95d61af5a88c88b7717e470d3cd Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Fri, 7 Feb 2025 12:32:10 +0000 Subject: [PATCH 01/23] Move `CertificateTTL` and `RenewalInterval` into a `CertificateLifetime` struct These values are always required together, and moving them into a struct will make it more straightforward to override them per-service/output. --- integrations/lib/embeddedtbot/bot_test.go | 12 +-- integrations/lib/embeddedtbot/config.go | 4 +- .../terraform/provider/credentials.go | 6 +- lib/tbot/cli/start_identity_test.go | 4 +- lib/tbot/cli/start_legacy.go | 12 +-- lib/tbot/cli/start_legacy_test.go | 4 +- lib/tbot/cli/start_shared.go | 12 +-- lib/tbot/cli/start_shared_test.go | 4 +- lib/tbot/config/config.go | 90 +++++++++++++------ lib/tbot/config/config_test.go | 38 ++++---- lib/tbot/config/migrate.go | 18 ++-- lib/tbot/config/migrate_test.go | 42 +++++---- lib/tbot/service_application_output.go | 6 +- lib/tbot/service_application_tunnel.go | 4 +- lib/tbot/service_bot_identity.go | 10 +-- lib/tbot/service_client_credential.go | 4 +- lib/tbot/service_database_output.go | 6 +- lib/tbot/service_database_tunnel.go | 4 +- lib/tbot/service_identity_output.go | 6 +- lib/tbot/service_kubernetes_output.go | 6 +- lib/tbot/service_kubernetes_v2_output.go | 4 +- lib/tbot/service_spiffe_svid_output.go | 8 +- lib/tbot/service_spiffe_workload_api.go | 4 +- lib/tbot/service_spiffe_workload_api_sds.go | 4 +- .../service_spiffe_workload_api_sds_test.go | 4 +- lib/tbot/service_ssh_host_output.go | 6 +- lib/tbot/service_ssh_multiplexer.go | 4 +- lib/tbot/service_workload_identity_api.go | 6 +- lib/tbot/service_workload_identity_jwt.go | 6 +- lib/tbot/service_workload_identity_x509.go | 6 +- tool/tctl/common/terraform_command.go | 8 +- 31 files changed, 205 insertions(+), 147 deletions(-) diff --git a/integrations/lib/embeddedtbot/bot_test.go b/integrations/lib/embeddedtbot/bot_test.go index ca4bc9480af43..55359f054513a 100644 --- a/integrations/lib/embeddedtbot/bot_test.go +++ b/integrations/lib/embeddedtbot/bot_test.go @@ -122,11 +122,13 @@ func TestBotJoinAuth(t *testing.T) { TokenValue: tokenName, JoinMethod: types.JoinMethodToken, }, - AuthServer: authAddr.Addr, - CertificateTTL: defaultCertificateTTL, - RenewalInterval: defaultRenewalInterval, - Oneshot: true, - Debug: true, + AuthServer: authAddr.Addr, + CertificateLifetime: config.CertificateLifetime{ + TTL: defaultCertificateTTL, + RenewalInterval: defaultRenewalInterval, + }, + Oneshot: true, + Debug: true, } bot, err := New(botConfig) require.NoError(t, err) diff --git a/integrations/lib/embeddedtbot/config.go b/integrations/lib/embeddedtbot/config.go index 9140c17282398..bd83628213ff7 100644 --- a/integrations/lib/embeddedtbot/config.go +++ b/integrations/lib/embeddedtbot/config.go @@ -45,8 +45,8 @@ func (c *BotConfig) BindFlags(fs *flag.FlagSet) { fs.StringVar(&c.AuthServer, "auth-server", "127.0.0.1:3025", "Address of the Teleport Auth Server or Proxy Server") fs.StringVar(&c.Onboarding.TokenValue, "token", "teleport-operator", "A bot join token or path to file with token value.") fs.StringVar((*string)(&c.Onboarding.JoinMethod), "join-method", string(types.JoinMethodKubernetes), "Method to use to join the Teleport cluster.") - fs.DurationVar(&c.CertificateTTL, "certificate-ttl", defaultCertificateTTL, "TTL of short-lived machine certificates.") - fs.DurationVar(&c.RenewalInterval, "renewal-interval", defaultRenewalInterval, "Interval at which short-lived certificates are renewed; must be less than the certificate TTL.") + fs.DurationVar(&c.CertificateLifetime.TTL, "certificate-ttl", defaultCertificateTTL, "TTL of short-lived machine certificates.") + fs.DurationVar(&c.CertificateLifetime.RenewalInterval, "renewal-interval", defaultRenewalInterval, "Interval at which short-lived certificates are renewed; must be less than the certificate TTL.") caPinsFlag := StringListVar{ list: &c.Onboarding.CAPins, } diff --git a/integrations/terraform/provider/credentials.go b/integrations/terraform/provider/credentials.go index 2aa463cb04f44..d7bdd64bdba26 100644 --- a/integrations/terraform/provider/credentials.go +++ b/integrations/terraform/provider/credentials.go @@ -521,8 +521,10 @@ See https://goteleport.com/docs/reference/join-methods for more details.`) AudienceTag: audienceTag, }, }, - CertificateTTL: time.Hour, - RenewalInterval: 20 * time.Minute, + CertificateLifetime: tbotconfig.CertificateLifetime{ + TTL: time.Hour, + RenewalInterval: 20 * time.Minute, + }, } bot, err := embeddedtbot.New(botConfig) if err != nil { diff --git a/lib/tbot/cli/start_identity_test.go b/lib/tbot/cli/start_identity_test.go index 909c3a6c57ded..70e7ac0d1203c 100644 --- a/lib/tbot/cli/start_identity_test.go +++ b/lib/tbot/cli/start_identity_test.go @@ -55,8 +55,8 @@ func TestIdentityCommand(t *testing.T) { require.Equal(t, "foo", token) require.ElementsMatch(t, cfg.Onboarding.CAPins, []string{"bar"}) - require.Equal(t, time.Minute*10, cfg.CertificateTTL) - require.Equal(t, time.Minute*5, cfg.RenewalInterval) + require.Equal(t, time.Minute*10, cfg.CertificateLifetime.TTL) + require.Equal(t, time.Minute*5, cfg.CertificateLifetime.RenewalInterval) require.Equal(t, types.JoinMethodGitHub, cfg.Onboarding.JoinMethod) require.True(t, cfg.Oneshot) require.Equal(t, "0.0.0.0:8080", cfg.DiagAddr) diff --git a/lib/tbot/cli/start_legacy.go b/lib/tbot/cli/start_legacy.go index 0d406a2062fa4..8ef4121e9118d 100644 --- a/lib/tbot/cli/start_legacy.go +++ b/lib/tbot/cli/start_legacy.go @@ -188,29 +188,29 @@ func (c *LegacyCommand) ApplyConfig(cfg *config.BotConfig, l *slog.Logger) error } if c.CertificateTTL != 0 { - if cfg.CertificateTTL != 0 { + if cfg.CertificateLifetime.TTL != 0 { log.WarnContext( context.TODO(), "CLI parameters are overriding configuration", "flag", "certificate-ttl", - "config_value", cfg.CertificateTTL, + "config_value", cfg.CertificateLifetime.TTL, "cli_value", c.CertificateTTL, ) } - cfg.CertificateTTL = c.CertificateTTL + cfg.CertificateLifetime.TTL = c.CertificateTTL } if c.RenewalInterval != 0 { - if cfg.RenewalInterval != 0 { + if cfg.CertificateLifetime.RenewalInterval != 0 { log.WarnContext( context.TODO(), "CLI parameters are overriding configuration", "flag", "renewal-interval", - "config_value", cfg.RenewalInterval, + "config_value", cfg.CertificateLifetime.RenewalInterval, "cli_value", c.RenewalInterval, ) } - cfg.RenewalInterval = c.RenewalInterval + cfg.CertificateLifetime.RenewalInterval = c.RenewalInterval } // DataDir overrides any previously-configured storage config diff --git a/lib/tbot/cli/start_legacy_test.go b/lib/tbot/cli/start_legacy_test.go index 93a40a75b3da1..cc866850967ef 100644 --- a/lib/tbot/cli/start_legacy_test.go +++ b/lib/tbot/cli/start_legacy_test.go @@ -53,8 +53,8 @@ func TestLegacyCommand(t *testing.T) { require.Equal(t, "foo", token) require.ElementsMatch(t, cfg.Onboarding.CAPins, []string{"bar"}) - require.Equal(t, time.Minute*10, cfg.CertificateTTL) - require.Equal(t, time.Minute*5, cfg.RenewalInterval) + require.Equal(t, time.Minute*10, cfg.CertificateLifetime.TTL) + require.Equal(t, time.Minute*5, cfg.CertificateLifetime.RenewalInterval) require.Equal(t, types.JoinMethodGitHub, cfg.Onboarding.JoinMethod) require.True(t, cfg.Oneshot) require.Equal(t, "0.0.0.0:8080", cfg.DiagAddr) diff --git a/lib/tbot/cli/start_shared.go b/lib/tbot/cli/start_shared.go index 2e2a07a94020c..f3c37ab925074 100644 --- a/lib/tbot/cli/start_shared.go +++ b/lib/tbot/cli/start_shared.go @@ -153,29 +153,29 @@ func (s *sharedStartArgs) ApplyConfig(cfg *config.BotConfig, l *slog.Logger) err } if s.CertificateTTL != 0 { - if cfg.CertificateTTL != 0 { + if cfg.CertificateLifetime.TTL != 0 { l.WarnContext( context.TODO(), "CLI parameters are overriding configuration", "flag", "certificate-ttl", - "config_value", cfg.CertificateTTL, + "config_value", cfg.CertificateLifetime.TTL, "cli_value", s.CertificateTTL, ) } - cfg.CertificateTTL = s.CertificateTTL + cfg.CertificateLifetime.TTL = s.CertificateTTL } if s.RenewalInterval != 0 { - if cfg.RenewalInterval != 0 { + if cfg.CertificateLifetime.RenewalInterval != 0 { l.WarnContext( context.TODO(), "CLI parameters are overriding configuration", "flag", "renewal-interval", - "config_value", cfg.RenewalInterval, + "config_value", cfg.CertificateLifetime.RenewalInterval, "cli_value", s.RenewalInterval, ) } - cfg.RenewalInterval = s.RenewalInterval + cfg.CertificateLifetime.RenewalInterval = s.RenewalInterval } if s.DiagAddr != "" { diff --git a/lib/tbot/cli/start_shared_test.go b/lib/tbot/cli/start_shared_test.go index 549f04497e806..5d5627d71c6ca 100644 --- a/lib/tbot/cli/start_shared_test.go +++ b/lib/tbot/cli/start_shared_test.go @@ -66,8 +66,8 @@ func TestSharedStartArgs(t *testing.T) { require.Equal(t, "foo", token) require.ElementsMatch(t, cfg.Onboarding.CAPins, []string{"bar"}) - require.Equal(t, time.Minute*10, cfg.CertificateTTL) - require.Equal(t, time.Minute*5, cfg.RenewalInterval) + require.Equal(t, time.Minute*10, cfg.CertificateLifetime.TTL) + require.Equal(t, time.Minute*5, cfg.CertificateLifetime.RenewalInterval) require.Equal(t, types.JoinMethodGitHub, cfg.Onboarding.JoinMethod) require.True(t, cfg.Oneshot) require.Equal(t, "0.0.0.0:8080", cfg.DiagAddr) diff --git a/lib/tbot/config/config.go b/lib/tbot/config/config.go index c7f0631fa273d..e0878b72e4265 100644 --- a/lib/tbot/config/config.go +++ b/lib/tbot/config/config.go @@ -152,10 +152,9 @@ type BotConfig struct { // ProxyServer is the teleport proxy address. Unlike `AuthServer` this must // explicitly point to a Teleport proxy. // Example: "example.teleport.sh:443" - ProxyServer string `yaml:"proxy_server,omitempty"` - CertificateTTL time.Duration `yaml:"certificate_ttl"` - RenewalInterval time.Duration `yaml:"renewal_interval"` - Oneshot bool `yaml:"oneshot"` + ProxyServer string `yaml:"proxy_server,omitempty"` + CertificateLifetime CertificateLifetime `yaml:",inline"` + Oneshot bool `yaml:"oneshot"` // FIPS instructs `tbot` to run in a mode designed to comply with FIPS // regulations. This means the bot should: // - Refuse to run if not compiled with boringcrypto @@ -259,12 +258,12 @@ func (conf *BotConfig) CheckAndSetDefaults() error { } } - if conf.CertificateTTL == 0 { - conf.CertificateTTL = DefaultCertificateTTL + if conf.CertificateLifetime.TTL == 0 { + conf.CertificateLifetime.TTL = DefaultCertificateTTL } - if conf.RenewalInterval == 0 { - conf.RenewalInterval = DefaultRenewInterval + if conf.CertificateLifetime.RenewalInterval == 0 { + conf.CertificateLifetime.RenewalInterval = DefaultRenewInterval } // We require the join method for `configure` and `start` but not for `init` @@ -291,23 +290,9 @@ func (conf *BotConfig) CheckAndSetDefaults() error { } } - // Warn about config where renewals will fail due to weird TTL vs Interval - if !conf.Oneshot && conf.RenewalInterval > conf.CertificateTTL { - log.WarnContext( - context.TODO(), - "Certificate TTL is shorter than the renewal interval. This is likely an invalid configuration. Increase the certificate TTL or decrease the renewal interval", - "ttl", conf.CertificateTTL, - "interval", conf.RenewalInterval, - ) - } - - if conf.CertificateTTL > defaults.MaxRenewableCertTTL { - log.WarnContext( - context.TODO(), - "Requested certificate TTL exceeds the maximum TTL allowed and will likely be reduced by the Teleport server", - "requested_ttl", conf.CertificateTTL, - "maximum_ttl", defaults.MaxRenewableCertTTL, - ) + // Validate CertificateTTL and RenewalInterval options + if err := conf.CertificateLifetime.Validate(conf.Oneshot); err != nil { + return err } return nil @@ -616,3 +601,58 @@ func ReadConfig(reader io.ReadSeeker, manualMigration bool) (*BotConfig, error) return nil, trace.BadParameter("unrecognized config version %q", version.Version) } } + +// CertificateLifetime contains configuration for how long certificates will +// last and the frequency at which they'll be renewed. +// +// It's a member on the BotConfig and service config structs, marked with the +// `inline` YAML tag so its fields become individual fields in the YAML config +// format. +type CertificateLifetime struct { + TTL time.Duration `yaml:"certificate_ttl,omitempty"` + RenewalInterval time.Duration `yaml:"renewal_interval,omitempty"` +} + +// IsEmpty returns whether none of the fields is set (i.e. it is unconfigured). +func (l CertificateLifetime) IsEmpty() bool { + return l == CertificateLifetime{} +} + +// Validate checks whether the combination of the fields is valid. +func (l CertificateLifetime) Validate(oneShot bool) error { + if l.IsEmpty() { + return nil + } + + if l.TTL == 0 || l.RenewalInterval == 0 { + return trace.BadParameter("certificate_ttl and renewal_interval must both be specified if either is") + } + + if l.TTL < 0 { + return trace.BadParameter("certificate_ttl must be positive") + } + + if l.RenewalInterval < 0 { + return trace.BadParameter("renewal_interval must be positive") + } + + if l.TTL < l.RenewalInterval && !oneShot { + log.WarnContext( + context.TODO(), + "Certificate TTL is shorter than the renewal interval. This is likely an invalid configuration. Increase the certificate TTL or decrease the renewal interval", + "ttl", l.TTL, + "interval", l.RenewalInterval, + ) + } + + if l.TTL > defaults.MaxRenewableCertTTL { + log.WarnContext( + context.TODO(), + "Requested certificate TTL exceeds the maximum TTL allowed and will likely be reduced by the Teleport server", + "requested_ttl", l.TTL, + "maximum_ttl", defaults.MaxRenewableCertTTL, + ) + } + + return nil +} diff --git a/lib/tbot/config/config_test.go b/lib/tbot/config/config_test.go index 8bc3138d2ef1c..e34c7a523ed9b 100644 --- a/lib/tbot/config/config_test.go +++ b/lib/tbot/config/config_test.go @@ -42,7 +42,7 @@ func TestConfigFile(t *testing.T) { require.NoError(t, cfg.CheckAndSetDefaults()) require.Equal(t, "auth.example.com", cfg.AuthServer) - require.Equal(t, time.Minute*5, cfg.RenewalInterval) + require.Equal(t, time.Minute*5, cfg.CertificateLifetime.RenewalInterval) require.NotNil(t, cfg.Onboarding) @@ -197,13 +197,15 @@ func TestBotConfig_YAML(t *testing.T) { Symlinks: botfs.SymlinksSecure, }, }, - FIPS: true, - Debug: true, - Oneshot: true, - AuthServer: "example.teleport.sh:443", - DiagAddr: "127.0.0.1:1337", - CertificateTTL: time.Minute, - RenewalInterval: time.Second * 30, + FIPS: true, + Debug: true, + Oneshot: true, + AuthServer: "example.teleport.sh:443", + DiagAddr: "127.0.0.1:1337", + CertificateLifetime: CertificateLifetime{ + TTL: time.Minute, + RenewalInterval: time.Second * 30, + }, Outputs: ServiceConfigs{ &IdentityOutput{ Destination: &DestinationDirectory{ @@ -293,10 +295,12 @@ func TestBotConfig_YAML(t *testing.T) { { name: "minimal config", in: BotConfig{ - Version: V2, - AuthServer: "example.teleport.sh:443", - CertificateTTL: time.Minute, - RenewalInterval: time.Second * 30, + Version: V2, + AuthServer: "example.teleport.sh:443", + CertificateLifetime: CertificateLifetime{ + TTL: time.Minute, + RenewalInterval: time.Second * 30, + }, Outputs: ServiceConfigs{ &IdentityOutput{ Destination: &DestinationMemory{}, @@ -307,10 +311,12 @@ func TestBotConfig_YAML(t *testing.T) { { name: "minimal config using proxy addr", in: BotConfig{ - Version: V2, - ProxyServer: "example.teleport.sh:443", - CertificateTTL: time.Minute, - RenewalInterval: time.Second * 30, + Version: V2, + ProxyServer: "example.teleport.sh:443", + CertificateLifetime: CertificateLifetime{ + TTL: time.Minute, + RenewalInterval: time.Second * 30, + }, Outputs: ServiceConfigs{ &IdentityOutput{ Destination: &DestinationMemory{}, diff --git a/lib/tbot/config/migrate.go b/lib/tbot/config/migrate.go index dcf2c3170e215..6245a6282a666 100644 --- a/lib/tbot/config/migrate.go +++ b/lib/tbot/config/migrate.go @@ -402,14 +402,16 @@ func (c *configV1) migrate() (*BotConfig, error) { return &BotConfig{ Version: V2, - Onboarding: c.Onboarding, - Debug: c.Debug, - AuthServer: c.AuthServer, - CertificateTTL: c.CertificateTTL, - RenewalInterval: c.RenewalInterval, - Oneshot: c.Oneshot, - FIPS: c.FIPS, - DiagAddr: c.DiagAddr, + Onboarding: c.Onboarding, + Debug: c.Debug, + AuthServer: c.AuthServer, + CertificateLifetime: CertificateLifetime{ + TTL: c.CertificateTTL, + RenewalInterval: c.RenewalInterval, + }, + Oneshot: c.Oneshot, + FIPS: c.FIPS, + DiagAddr: c.DiagAddr, Storage: storage, Services: outputs, diff --git a/lib/tbot/config/migrate_test.go b/lib/tbot/config/migrate_test.go index 5b380c4f41685..c1ab04e2b7f9d 100644 --- a/lib/tbot/config/migrate_test.go +++ b/lib/tbot/config/migrate_test.go @@ -106,13 +106,15 @@ destinations: - second.example.com `, wantOutput: &BotConfig{ - Version: V2, - AuthServer: "example.teleport.sh:443", - Oneshot: true, - Debug: true, - RenewalInterval: time.Minute * 10, - CertificateTTL: time.Minute * 30, - DiagAddr: "127.0.0.1:621", + Version: V2, + AuthServer: "example.teleport.sh:443", + Oneshot: true, + Debug: true, + CertificateLifetime: CertificateLifetime{ + RenewalInterval: time.Minute * 10, + TTL: time.Minute * 30, + }, + DiagAddr: "127.0.0.1:621", Onboarding: OnboardingConfig{ JoinMethod: types.JoinMethodToken, TokenValue: "my-token", @@ -354,7 +356,7 @@ storage: directory: /var/lib/teleport/bot destinations: - directory: /opt/machine-id - + database: service: example-server username: alice @@ -400,12 +402,12 @@ storage: directory: /var/lib/teleport/bot destinations: - directory: /opt/machine-id - + database: service: example-server username: alice database: example - + # If using MongoDB, be sure to include the Mongo-formatted certificates: configs: - mongo @@ -451,7 +453,7 @@ storage: directory: /var/lib/teleport/bot destinations: - directory: /opt/machine-id - + database: service: example-server username: alice @@ -501,7 +503,7 @@ storage: directory: /var/lib/teleport/bot destinations: - directory: /opt/machine-id - + database: service: example-server username: alice @@ -574,8 +576,10 @@ oneshot: false "sha256:1234abcd5678efgh910ijklmnop", }, }, - RenewalInterval: DefaultRenewInterval, - CertificateTTL: DefaultCertificateTTL, + CertificateLifetime: CertificateLifetime{ + RenewalInterval: DefaultRenewInterval, + TTL: DefaultCertificateTTL, + }, Storage: &StorageConfig{ Destination: &DestinationDirectory{ Path: "/var/lib/teleport/bot", @@ -921,23 +925,23 @@ onboarding: storage: directory: /var/lib/teleport/bot destinations: - - directory: + - directory: path: /mount/redacted-prod-global acls: off kubernetes_cluster: redacted-prod-global - - directory: + - directory: path: /mount/redacted-prod-au acls: off kubernetes_cluster: redacted-prod-au - - directory: + - directory: path: /mount/redacted-prod-eu2 acls: off kubernetes_cluster: redacted-prod-eu2 - - directory: + - directory: path: /mount/redacted-prod-ca acls: off kubernetes_cluster: redacted-prod-ca - - directory: + - directory: path: /mount/redacted-prod-us acls: off kubernetes_cluster: redacted-prod-us diff --git a/lib/tbot/service_application_output.go b/lib/tbot/service_application_output.go index 75b01bc646672..e7102e5853922 100644 --- a/lib/tbot/service_application_output.go +++ b/lib/tbot/service_application_output.go @@ -62,7 +62,7 @@ func (s *ApplicationOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.RenewalInterval, + interval: s.botCfg.CertificateLifetime.RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -104,7 +104,7 @@ func (s *ApplicationOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { @@ -134,7 +134,7 @@ func (s *ApplicationOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, func(req *proto.UserCertsRequest) { req.RouteToApp = routeToApp }, diff --git a/lib/tbot/service_application_tunnel.go b/lib/tbot/service_application_tunnel.go index 427a4558d4e5c..d84f19dba810f 100644 --- a/lib/tbot/service_application_tunnel.go +++ b/lib/tbot/service_application_tunnel.go @@ -201,7 +201,7 @@ func (s *ApplicationTunnelService) issueCert( s.botClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { @@ -233,7 +233,7 @@ func (s *ApplicationTunnelService) issueCert( s.botClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, func(req *proto.UserCertsRequest) { req.RouteToApp = route }) diff --git a/lib/tbot/service_bot_identity.go b/lib/tbot/service_bot_identity.go index a00287e090e19..b8af2c0b75d01 100644 --- a/lib/tbot/service_bot_identity.go +++ b/lib/tbot/service_bot_identity.go @@ -262,8 +262,8 @@ func (s *identityService) Run(ctx context.Context) error { s.log.InfoContext( ctx, "Beginning bot identity renewal loop", - "ttl", s.cfg.CertificateTTL, - "interval", s.cfg.RenewalInterval, + "ttl", s.cfg.CertificateLifetime.TTL, + "interval", s.cfg.CertificateLifetime.RenewalInterval, ) err := runOnInterval(ctx, runOnIntervalConfig{ @@ -271,7 +271,7 @@ func (s *identityService) Run(ctx context.Context) error { f: func(ctx context.Context) error { return s.renew(ctx, storageDestination) }, - interval: s.cfg.RenewalInterval, + interval: s.cfg.CertificateLifetime.RenewalInterval, exitOnRetryExhausted: true, retryLimit: botIdentityRenewalRetryLimit, log: s.log, @@ -333,7 +333,7 @@ func renewIdentity( // When using a renewable join method, we use GenerateUserCerts to // request a new certificate using our current identity. newIdentity, err := botIdentityFromAuth( - ctx, log, oldIdentity, authClient, botCfg.CertificateTTL, + ctx, log, oldIdentity, authClient, botCfg.CertificateLifetime.TTL, ) if err != nil { return nil, trace.Wrap(err, "renewing identity using GenerateUserCert") @@ -435,7 +435,7 @@ func botIdentityFromToken( return nil, trace.Wrap(err) } - expires := time.Now().Add(cfg.CertificateTTL) + expires := time.Now().Add(cfg.CertificateLifetime.TTL) params := join.RegisterParams{ Token: token, ID: state.IdentityID{ diff --git a/lib/tbot/service_client_credential.go b/lib/tbot/service_client_credential.go index 03583874bb4cf..1044cd2408d84 100644 --- a/lib/tbot/service_client_credential.go +++ b/lib/tbot/service_client_credential.go @@ -57,7 +57,7 @@ func (s *ClientCredentialOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.RenewalInterval, + interval: s.botCfg.CertificateLifetime.RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -83,7 +83,7 @@ func (s *ClientCredentialOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { diff --git a/lib/tbot/service_database_output.go b/lib/tbot/service_database_output.go index 12bcf1b8ef4de..1272f5b0f5258 100644 --- a/lib/tbot/service_database_output.go +++ b/lib/tbot/service_database_output.go @@ -62,7 +62,7 @@ func (s *DatabaseOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.RenewalInterval, + interval: s.botCfg.CertificateLifetime.RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -104,7 +104,7 @@ func (s *DatabaseOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { @@ -136,7 +136,7 @@ func (s *DatabaseOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, func(req *proto.UserCertsRequest) { req.RouteToDatabase = route }, diff --git a/lib/tbot/service_database_tunnel.go b/lib/tbot/service_database_tunnel.go index 4ba5c5c3647cf..d69482a343986 100644 --- a/lib/tbot/service_database_tunnel.go +++ b/lib/tbot/service_database_tunnel.go @@ -240,7 +240,7 @@ func (s *DatabaseTunnelService) getRouteToDatabaseWithImpersonation(ctx context. s.botClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { @@ -280,7 +280,7 @@ func (s *DatabaseTunnelService) issueCert( s.botClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, func(req *proto.UserCertsRequest) { req.RouteToDatabase = route }) diff --git a/lib/tbot/service_identity_output.go b/lib/tbot/service_identity_output.go index 2e7732669d3c0..3b5fd2d8bbc5d 100644 --- a/lib/tbot/service_identity_output.go +++ b/lib/tbot/service_identity_output.go @@ -74,7 +74,7 @@ func (s *IdentityOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.RenewalInterval, + interval: s.botCfg.CertificateLifetime.RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -116,7 +116,7 @@ func (s *IdentityOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, func(req *proto.UserCertsRequest) { req.ReissuableRoleImpersonation = s.cfg.AllowReissue }, @@ -139,7 +139,7 @@ func (s *IdentityOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, func(req *proto.UserCertsRequest) { req.RouteToCluster = s.cfg.Cluster req.ReissuableRoleImpersonation = s.cfg.AllowReissue diff --git a/lib/tbot/service_kubernetes_output.go b/lib/tbot/service_kubernetes_output.go index c93f7a188dfcd..7788b9bc0f44e 100644 --- a/lib/tbot/service_kubernetes_output.go +++ b/lib/tbot/service_kubernetes_output.go @@ -79,7 +79,7 @@ func (s *KubernetesOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.RenewalInterval, + interval: s.botCfg.CertificateLifetime.RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -121,7 +121,7 @@ func (s *KubernetesOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { @@ -152,7 +152,7 @@ func (s *KubernetesOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, func(req *proto.UserCertsRequest) { req.KubernetesCluster = kubeClusterName }, diff --git a/lib/tbot/service_kubernetes_v2_output.go b/lib/tbot/service_kubernetes_v2_output.go index 4dd6eb61e6a5a..4b97f3ad270ce 100644 --- a/lib/tbot/service_kubernetes_v2_output.go +++ b/lib/tbot/service_kubernetes_v2_output.go @@ -78,7 +78,7 @@ func (s *KubernetesV2OutputService) Run(ctx context.Context) error { return trace.Wrap(runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.RenewalInterval, + interval: s.botCfg.CertificateLifetime.RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -115,7 +115,7 @@ func (s *KubernetesV2OutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { diff --git a/lib/tbot/service_spiffe_svid_output.go b/lib/tbot/service_spiffe_svid_output.go index 0190361003a89..8419e08a2acf5 100644 --- a/lib/tbot/service_spiffe_svid_output.go +++ b/lib/tbot/service_spiffe_svid_output.go @@ -134,7 +134,7 @@ func (s *SPIFFESVIDOutputService) Run(ctx context.Context) error { privateKey = nil } bundleSet = newBundleSet - case <-time.After(s.botCfg.RenewalInterval): + case <-time.After(s.botCfg.CertificateLifetime.RenewalInterval): s.log.InfoContext(ctx, "Renewal interval reached, renewing SVIDs") res = nil privateKey = nil @@ -183,7 +183,7 @@ func (s *SPIFFESVIDOutputService) requestSVID( s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { @@ -202,7 +202,7 @@ func (s *SPIFFESVIDOutputService) requestSVID( ctx, impersonatedClient, []config.SVIDRequest{s.cfg.SVID}, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, ) if err != nil { return nil, nil, nil, trace.Wrap(err, "generating X509 SVID") @@ -213,7 +213,7 @@ func (s *SPIFFESVIDOutputService) requestSVID( impersonatedClient, s.cfg.SVID, s.cfg.JWTs, - s.botCfg.CertificateTTL) + s.botCfg.CertificateLifetime.TTL) if err != nil { return nil, nil, nil, trace.Wrap(err, "generating JWT SVIDs") } diff --git a/lib/tbot/service_spiffe_workload_api.go b/lib/tbot/service_spiffe_workload_api.go index b8a5675673657..25fb1a9da8321 100644 --- a/lib/tbot/service_spiffe_workload_api.go +++ b/lib/tbot/service_spiffe_workload_api.go @@ -323,7 +323,7 @@ func (s *SPIFFEWorkloadAPIService) fetchX509SVIDs( s.client, svidRequests, // For TTL, we use the one globally configured. - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, ) if err != nil { return nil, trace.Wrap(err) @@ -646,7 +646,7 @@ func (s *SPIFFEWorkloadAPIService) FetchX509SVID( } bundleSet = newBundleSet continue - case <-time.After(s.botCfg.RenewalInterval): + case <-time.After(s.botCfg.CertificateLifetime.RenewalInterval): log.DebugContext(ctx, "Renewal interval reached, renewing SVIDs") svids = nil continue diff --git a/lib/tbot/service_spiffe_workload_api_sds.go b/lib/tbot/service_spiffe_workload_api_sds.go index 547e0ccf3605f..5c3768e7c0789 100644 --- a/lib/tbot/service_spiffe_workload_api_sds.go +++ b/lib/tbot/service_spiffe_workload_api_sds.go @@ -200,7 +200,7 @@ func (s *spiffeSDSHandler) StreamSecrets( } }() - renewalTimer := time.NewTimer(s.botCfg.RenewalInterval) + renewalTimer := time.NewTimer(s.botCfg.CertificateLifetime.RenewalInterval) // Stop the timer immediately so we can start timing after the first // response is sent. renewalTimer.Stop() @@ -334,7 +334,7 @@ func (s *spiffeSDSHandler) StreamSecrets( ), ) - renewalTimer.Reset(s.botCfg.RenewalInterval) + renewalTimer.Reset(s.botCfg.CertificateLifetime.RenewalInterval) } } diff --git a/lib/tbot/service_spiffe_workload_api_sds_test.go b/lib/tbot/service_spiffe_workload_api_sds_test.go index da52f683140b9..14eee26df4983 100644 --- a/lib/tbot/service_spiffe_workload_api_sds_test.go +++ b/lib/tbot/service_spiffe_workload_api_sds_test.go @@ -112,7 +112,9 @@ func TestSDS_FetchSecrets(t *testing.T) { }, } botConfig := &config.BotConfig{ - RenewalInterval: time.Minute, + CertificateLifetime: config.CertificateLifetime{ + RenewalInterval: time.Minute, + }, } tests := []struct { diff --git a/lib/tbot/service_ssh_host_output.go b/lib/tbot/service_ssh_host_output.go index 3115b7e0c888d..4bf9bcc46e6bd 100644 --- a/lib/tbot/service_ssh_host_output.go +++ b/lib/tbot/service_ssh_host_output.go @@ -65,7 +65,7 @@ func (s *SSHHostOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.RenewalInterval, + interval: s.botCfg.CertificateLifetime.RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -107,7 +107,7 @@ func (s *SSHHostOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { @@ -143,7 +143,7 @@ func (s *SSHHostOutputService) generate(ctx context.Context) error { Principals: s.cfg.Principals, ClusterName: clusterName, Role: string(types.RoleNode), - Ttl: durationpb.New(s.botCfg.CertificateTTL), + Ttl: durationpb.New(s.botCfg.CertificateLifetime.TTL), }, ) if err != nil { diff --git a/lib/tbot/service_ssh_multiplexer.go b/lib/tbot/service_ssh_multiplexer.go index 490633f7ca4d2..525f3cad41597 100644 --- a/lib/tbot/service_ssh_multiplexer.go +++ b/lib/tbot/service_ssh_multiplexer.go @@ -345,7 +345,7 @@ func (s *SSHMultiplexerService) generateIdentity(ctx context.Context) (*identity s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { @@ -396,7 +396,7 @@ func (s *SSHMultiplexerService) identityRenewalLoop( s.identity.Set(id) return s.writeArtifacts(ctx, proxyHost, authClient) }, - interval: s.botCfg.RenewalInterval, + interval: s.botCfg.CertificateLifetime.RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, diff --git a/lib/tbot/service_workload_identity_api.go b/lib/tbot/service_workload_identity_api.go index e9159dfe9cf73..5a22cb298fdc3 100644 --- a/lib/tbot/service_workload_identity_api.go +++ b/lib/tbot/service_workload_identity_api.go @@ -350,7 +350,7 @@ func (s *WorkloadIdentityAPIService) FetchX509SVID( } bundleSet = newBundleSet continue - case <-time.After(s.botCfg.RenewalInterval): + case <-time.After(s.botCfg.CertificateLifetime.RenewalInterval): log.DebugContext(ctx, "Renewal interval reached, renewing SVIDs") svids = nil continue @@ -408,7 +408,7 @@ func (s *WorkloadIdentityAPIService) fetchX509SVIDs( log, s.client, s.cfg.Selector, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, attest, ) if err != nil { @@ -490,7 +490,7 @@ func (s *WorkloadIdentityAPIService) FetchJWTSVID( s.client, s.cfg.Selector, req.Audience, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, attr, ) if err != nil { diff --git a/lib/tbot/service_workload_identity_jwt.go b/lib/tbot/service_workload_identity_jwt.go index 0f3093ea8caf7..3edae05c721ce 100644 --- a/lib/tbot/service_workload_identity_jwt.go +++ b/lib/tbot/service_workload_identity_jwt.go @@ -111,7 +111,7 @@ func (s *WorkloadIdentityJWTService) Run(ctx context.Context) error { cred = nil } bundleSet = newBundleSet - case <-time.After(s.botCfg.RenewalInterval): + case <-time.After(s.botCfg.CertificateLifetime.RenewalInterval): s.log.InfoContext(ctx, "Renewal interval reached, renewing SVIDs") cred = nil case <-firstRun: @@ -157,7 +157,7 @@ func (s *WorkloadIdentityJWTService) requestJWTSVID( s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { @@ -178,7 +178,7 @@ func (s *WorkloadIdentityJWTService) requestJWTSVID( impersonatedClient, s.cfg.Selector, s.cfg.Audiences, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { diff --git a/lib/tbot/service_workload_identity_x509.go b/lib/tbot/service_workload_identity_x509.go index 0ca146dc0b3d4..86c559caa8d0f 100644 --- a/lib/tbot/service_workload_identity_x509.go +++ b/lib/tbot/service_workload_identity_x509.go @@ -126,7 +126,7 @@ func (s *WorkloadIdentityX509Service) Run(ctx context.Context) error { privateKey = nil } bundleSet = newBundleSet - case <-time.After(s.botCfg.RenewalInterval): + case <-time.After(s.botCfg.CertificateLifetime.RenewalInterval): s.log.InfoContext(ctx, "Renewal interval reached, renewing SVIDs") x509Cred = nil privateKey = nil @@ -174,7 +174,7 @@ func (s *WorkloadIdentityX509Service) requestSVID( s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { @@ -194,7 +194,7 @@ func (s *WorkloadIdentityX509Service) requestSVID( s.log, impersonatedClient, s.cfg.Selector, - s.botCfg.CertificateTTL, + s.botCfg.CertificateLifetime.TTL, nil, ) if err != nil { diff --git a/tool/tctl/common/terraform_command.go b/tool/tctl/common/terraform_command.go index 90b2a2241f941..04000b296f792 100644 --- a/tool/tctl/common/terraform_command.go +++ b/tool/tctl/common/terraform_command.go @@ -303,10 +303,10 @@ func (c *TerraformCommand) useBotToObtainIdentity(ctx context.Context, addr util TokenValue: token, JoinMethod: types.JoinMethodToken, }, - Storage: &config.StorageConfig{Destination: &config.DestinationMemory{}}, - Services: config.ServiceConfigs{credential}, - CertificateTTL: c.botTTL, - Oneshot: true, + Storage: &config.StorageConfig{Destination: &config.DestinationMemory{}}, + Services: config.ServiceConfigs{credential}, + CertificateLifetime: config.CertificateLifetime{TTL: c.botTTL}, + Oneshot: true, // If --insecure is passed, the bot will trust the certificate on first use. // This does not truly disable TLS validation, only trusts the certificate on first connection. Insecure: clt.Config().InsecureSkipVerify, From 0267b0ccbdfa270ccbbb86374c7bf09e471fbdeb Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Fri, 7 Feb 2025 15:38:40 +0000 Subject: [PATCH 02/23] Support custom `certificate_ttl` and `renewal_interval` on identity output --- lib/tbot/config/config.go | 13 ++-- lib/tbot/config/config_test.go | 64 +++++++++++++++++++ lib/tbot/config/service_identity.go | 8 +++ .../TestBotConfig_YAML/standard_config.golden | 2 + lib/tbot/service_identity_output.go | 13 +++- 5 files changed, 93 insertions(+), 7 deletions(-) diff --git a/lib/tbot/config/config.go b/lib/tbot/config/config.go index e0878b72e4265..307939bd58d25 100644 --- a/lib/tbot/config/config.go +++ b/lib/tbot/config/config.go @@ -225,6 +225,11 @@ func (conf *BotConfig) CheckAndSetDefaults() error { if err := service.CheckAndSetDefaults(); err != nil { return trace.Wrap(err, "validating service[%d]", i) } + if v, ok := service.(interface{ GetCertificateLifetime() CertificateLifetime }); ok { + if err := v.GetCertificateLifetime().Validate(conf.Oneshot); err != nil { + return trace.Wrap(err, "validating service[%d]", i) + } + } } destinationPaths := map[string]int{} @@ -603,11 +608,11 @@ func ReadConfig(reader io.ReadSeeker, manualMigration bool) (*BotConfig, error) } // CertificateLifetime contains configuration for how long certificates will -// last and the frequency at which they'll be renewed. +// last (TTL) and the frequency at which they'll be renewed (RenewalInterval). // -// It's a member on the BotConfig and service config structs, marked with the -// `inline` YAML tag so its fields become individual fields in the YAML config -// format. +// It's a member on the BotConfig and service/output config structs, marked with +// the `inline` YAML tag so its fields become individual fields in the YAML +// config format. type CertificateLifetime struct { TTL time.Duration `yaml:"certificate_ttl,omitempty"` RenewalInterval time.Duration `yaml:"renewal_interval,omitempty"` diff --git a/lib/tbot/config/config_test.go b/lib/tbot/config/config_test.go index e34c7a523ed9b..1f6d25562bc84 100644 --- a/lib/tbot/config/config_test.go +++ b/lib/tbot/config/config_test.go @@ -221,6 +221,10 @@ func TestBotConfig_YAML(t *testing.T) { Destination: &DestinationKubernetesSecret{ Name: "my-secret", }, + CertificateLifetime: CertificateLifetime{ + TTL: 30 * time.Second, + RenewalInterval: 15 * time.Second, + }, }, }, Services: []ServiceConfig{ @@ -394,3 +398,63 @@ func TestBotConfig_WithCAPathAndCAPins(t *testing.T) { require.ErrorContains(t, cfg.CheckAndSetDefaults(), "mutually exclusive") } + +func TestBotConfig_ServicePartialCertificateLifetime(t *testing.T) { + cfg := &BotConfig{ + Version: V2, + AuthServer: "example.teleport.sh:443", + Services: []ServiceConfig{ + &IdentityOutput{ + CertificateLifetime: CertificateLifetime{TTL: 5 * time.Minute}, + Destination: &DestinationMemory{}, + }, + }, + } + require.ErrorContains(t, cfg.CheckAndSetDefaults(), "certificate_ttl and renewal_interval") +} + +func TestBotConfig_ServiceInvalidCertificateLifetime(t *testing.T) { + cfg := &BotConfig{ + Version: V2, + AuthServer: "example.teleport.sh:443", + Services: []ServiceConfig{ + &IdentityOutput{ + CertificateLifetime: CertificateLifetime{TTL: 5 * time.Minute}, + Destination: &DestinationMemory{}, + }, + }, + } + require.ErrorContains(t, cfg.CheckAndSetDefaults(), "certificate_ttl and renewal_interval") +} + +func TestCertificateLifetimeValidate(t *testing.T) { + testCases := map[string]struct { + cfg CertificateLifetime + oneShot bool + error string + }{ + "partial config": { + cfg: CertificateLifetime{TTL: 1 * time.Minute}, + error: "certificate_ttl and renewal_interval must both be specified if either is", + }, + "negative TTL": { + cfg: CertificateLifetime{TTL: -time.Minute, RenewalInterval: time.Minute}, + error: "certificate_ttl must be positive", + }, + "negative renewal interval": { + cfg: CertificateLifetime{TTL: time.Minute, RenewalInterval: -time.Minute}, + error: "renewal_interval must be positive", + }, + } + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + err := tc.cfg.Validate(tc.oneShot) + + if tc.error == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tc.error) + } + }) + } +} diff --git a/lib/tbot/config/service_identity.go b/lib/tbot/config/service_identity.go index 686b5e7c66c6f..f0739e22368ae 100644 --- a/lib/tbot/config/service_identity.go +++ b/lib/tbot/config/service_identity.go @@ -101,6 +101,10 @@ type IdentityOutput struct { // // Defaults to false. AllowReissue bool `yaml:"allow_reissue,omitempty"` + + // CertificateLifetime contains configuration for how long certificates will + // last and the frequency at which they'll be renewed. + CertificateLifetime CertificateLifetime `yaml:",inline"` } func (o *IdentityOutput) Init(ctx context.Context) error { @@ -191,3 +195,7 @@ func (o *IdentityOutput) UnmarshalYAML(node *yaml.Node) error { func (o *IdentityOutput) Type() string { return IdentityOutputType } + +func (o *IdentityOutput) GetCertificateLifetime() CertificateLifetime { + return o.CertificateLifetime +} diff --git a/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden b/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden index 79bfdb3b4223f..74747924e51dc 100644 --- a/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden +++ b/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden @@ -19,6 +19,8 @@ outputs: destination: type: kubernetes_secret name: my-secret + certificate_ttl: 30s + renewal_interval: 15s services: - type: spiffe-workload-api listen: unix:///var/run/spiffe.sock diff --git a/lib/tbot/service_identity_output.go b/lib/tbot/service_identity_output.go index 3b5fd2d8bbc5d..2c8b401d4d013 100644 --- a/lib/tbot/service_identity_output.go +++ b/lib/tbot/service_identity_output.go @@ -74,7 +74,7 @@ func (s *IdentityOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.CertificateLifetime.RenewalInterval, + interval: s.certificateLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -116,7 +116,7 @@ func (s *IdentityOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, func(req *proto.UserCertsRequest) { req.ReissuableRoleImpersonation = s.cfg.AllowReissue }, @@ -139,7 +139,7 @@ func (s *IdentityOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, func(req *proto.UserCertsRequest) { req.RouteToCluster = s.cfg.Cluster req.ReissuableRoleImpersonation = s.cfg.AllowReissue @@ -226,6 +226,13 @@ func (s *IdentityOutputService) render( return nil } +func (s *IdentityOutputService) certificateLifetime() config.CertificateLifetime { + if !s.cfg.CertificateLifetime.IsEmpty() { + return s.cfg.CertificateLifetime + } + return s.botCfg.CertificateLifetime +} + type certAuthGetter interface { GetCertAuthority( ctx context.Context, From c6317211dd7ad8545ca3567dca03af55e140d11b Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Fri, 7 Feb 2025 15:49:06 +0000 Subject: [PATCH 03/23] Support custom `certificate_ttl` and `renewal_interval` on application output --- lib/tbot/config/service_application.go | 8 ++++++++ lib/tbot/service_application_output.go | 13 ++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/tbot/config/service_application.go b/lib/tbot/config/service_application.go index b5d65892b4a46..7c1b3bddc72c1 100644 --- a/lib/tbot/config/service_application.go +++ b/lib/tbot/config/service_application.go @@ -47,6 +47,10 @@ type ApplicationOutput struct { // `tls.key` and `tls.cas`. This is unneeded for most clients which can // be configured with specific paths to use, but exists for compatibility. SpecificTLSExtensions bool `yaml:"specific_tls_naming"` + + // CertificateLifetime contains configuration for how long certificates will + // last and the frequency at which they'll be renewed. + CertificateLifetime CertificateLifetime `yaml:",inline"` } func (o *ApplicationOutput) Init(ctx context.Context) error { @@ -121,3 +125,7 @@ func (o *ApplicationOutput) UnmarshalYAML(node *yaml.Node) error { func (o *ApplicationOutput) Type() string { return ApplicationOutputType } + +func (o *ApplicationOutput) GetCertificateLifetime() CertificateLifetime { + return o.CertificateLifetime +} diff --git a/lib/tbot/service_application_output.go b/lib/tbot/service_application_output.go index e7102e5853922..cd4a60c6ab176 100644 --- a/lib/tbot/service_application_output.go +++ b/lib/tbot/service_application_output.go @@ -62,7 +62,7 @@ func (s *ApplicationOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.CertificateLifetime.RenewalInterval, + interval: s.certificateLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -104,7 +104,7 @@ func (s *ApplicationOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, nil, ) if err != nil { @@ -134,7 +134,7 @@ func (s *ApplicationOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, func(req *proto.UserCertsRequest) { req.RouteToApp = routeToApp }, @@ -254,3 +254,10 @@ func getApp(ctx context.Context, clt *authclient.Client, appName string) (types. return apps[0], nil } + +func (s *ApplicationOutputService) certificateLifetime() config.CertificateLifetime { + if !s.cfg.CertificateLifetime.IsEmpty() { + return s.cfg.CertificateLifetime + } + return s.botCfg.CertificateLifetime +} From 07d85d5edd32b6f6f6f94f528ab1b7f1cf87bf7e Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Fri, 7 Feb 2025 15:52:46 +0000 Subject: [PATCH 04/23] Support custom `certificate_ttl` and `renewal_interval` on application tunnel --- lib/tbot/config/service_application_tunnel.go | 8 ++++++++ lib/tbot/service_application_tunnel.go | 11 +++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/tbot/config/service_application_tunnel.go b/lib/tbot/config/service_application_tunnel.go index 1f6e649ebd14a..a52aa8aa78aaa 100644 --- a/lib/tbot/config/service_application_tunnel.go +++ b/lib/tbot/config/service_application_tunnel.go @@ -46,6 +46,10 @@ type ApplicationTunnelService struct { // that you wish to tunnel to. AppName string `yaml:"app_name"` + // CertificateLifetime contains configuration for how long certificates will + // last and the frequency at which they'll be renewed. + CertificateLifetime CertificateLifetime `yaml:",inline"` + // Listener overrides "listen" and directly provides an opened listener to // use. Listener net.Listener `yaml:"-"` @@ -81,3 +85,7 @@ func (s *ApplicationTunnelService) CheckAndSetDefaults() error { } return nil } + +func (o *ApplicationTunnelService) GetCertificateLifetime() CertificateLifetime { + return o.CertificateLifetime +} diff --git a/lib/tbot/service_application_tunnel.go b/lib/tbot/service_application_tunnel.go index d84f19dba810f..49a1ffba6f670 100644 --- a/lib/tbot/service_application_tunnel.go +++ b/lib/tbot/service_application_tunnel.go @@ -201,7 +201,7 @@ func (s *ApplicationTunnelService) issueCert( s.botClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, nil, ) if err != nil { @@ -233,7 +233,7 @@ func (s *ApplicationTunnelService) issueCert( s.botClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, func(req *proto.UserCertsRequest) { req.RouteToApp = route }) @@ -250,3 +250,10 @@ func (s *ApplicationTunnelService) issueCert( func (s *ApplicationTunnelService) String() string { return fmt.Sprintf("%s:%s:%s", config.ApplicationTunnelServiceType, s.cfg.Listen, s.cfg.AppName) } + +func (s *ApplicationTunnelService) certificateLifetime() config.CertificateLifetime { + if !s.cfg.CertificateLifetime.IsEmpty() { + return s.cfg.CertificateLifetime + } + return s.botCfg.CertificateLifetime +} From 21f69b1d205f2ae33547beff4fb397c3d89f78dd Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Fri, 7 Feb 2025 16:00:41 +0000 Subject: [PATCH 05/23] Support custom `certificate_ttl` and `renewal_interval` on Kubernetes output --- lib/tbot/config/service_kubernetes.go | 8 ++++++++ lib/tbot/service_kubernetes_output.go | 13 ++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/tbot/config/service_kubernetes.go b/lib/tbot/config/service_kubernetes.go index 27b3431681b72..8099747e3c138 100644 --- a/lib/tbot/config/service_kubernetes.go +++ b/lib/tbot/config/service_kubernetes.go @@ -54,6 +54,10 @@ type KubernetesOutput struct { // kubeconfig. It does mean that kubectl will not be able to automatically // refresh the credentials within an individual invocation. DisableExecPlugin bool `yaml:"disable_exec_plugin"` + + // CertificateLifetime contains configuration for how long certificates will + // last and the frequency at which they'll be renewed. + CertificateLifetime CertificateLifetime `yaml:",inline"` } func (o *KubernetesOutput) CheckAndSetDefaults() error { @@ -117,3 +121,7 @@ func (o *KubernetesOutput) UnmarshalYAML(node *yaml.Node) error { func (o *KubernetesOutput) Type() string { return KubernetesOutputType } + +func (o *KubernetesOutput) GetCertificateLifetime() CertificateLifetime { + return o.CertificateLifetime +} diff --git a/lib/tbot/service_kubernetes_output.go b/lib/tbot/service_kubernetes_output.go index 7788b9bc0f44e..5d6fd9d56c39c 100644 --- a/lib/tbot/service_kubernetes_output.go +++ b/lib/tbot/service_kubernetes_output.go @@ -79,7 +79,7 @@ func (s *KubernetesOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.CertificateLifetime.RenewalInterval, + interval: s.certificateLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -121,7 +121,7 @@ func (s *KubernetesOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, nil, ) if err != nil { @@ -152,7 +152,7 @@ func (s *KubernetesOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, func(req *proto.UserCertsRequest) { req.KubernetesCluster = kubeClusterName }, @@ -461,3 +461,10 @@ func selectKubeConnectionMethod(proxyPong *proxyPingResponse) ( return "", "", trace.BadParameter("unable to determine kubernetes address") } + +func (s *KubernetesOutputService) certificateLifetime() config.CertificateLifetime { + if !s.cfg.CertificateLifetime.IsEmpty() { + return s.cfg.CertificateLifetime + } + return s.botCfg.CertificateLifetime +} From 0a106f3a1b6f4986802bb3098c743bc99873ab7f Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Fri, 7 Feb 2025 16:03:23 +0000 Subject: [PATCH 06/23] Support custom `certificate_ttl` and `renewal_interval` on Kubernetes V2 output --- lib/tbot/config/service_kubernetes_v2.go | 8 ++++++++ lib/tbot/service_kubernetes_v2_output.go | 11 +++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/tbot/config/service_kubernetes_v2.go b/lib/tbot/config/service_kubernetes_v2.go index f5e4915e9dd84..f76f897a5f867 100644 --- a/lib/tbot/config/service_kubernetes_v2.go +++ b/lib/tbot/config/service_kubernetes_v2.go @@ -50,6 +50,10 @@ type KubernetesV2Output struct { // Selectors is a list of selectors for path-based routing. Multiple // selectors can be used to generate an output containing all matches. Selectors []*KubernetesSelector `yaml:"selectors,omitempty"` + + // CertificateLifetime contains configuration for how long certificates will + // last and the frequency at which they'll be renewed. + CertificateLifetime CertificateLifetime `yaml:",inline"` } func (o *KubernetesV2Output) CheckAndSetDefaults() error { @@ -155,3 +159,7 @@ func (s *KubernetesSelector) UnmarshalYAML(value *yaml.Node) error { *s = KubernetesSelector(out) return nil } + +func (o *KubernetesV2Output) GetCertificateLifetime() CertificateLifetime { + return o.CertificateLifetime +} diff --git a/lib/tbot/service_kubernetes_v2_output.go b/lib/tbot/service_kubernetes_v2_output.go index 4b97f3ad270ce..34ead5207fe63 100644 --- a/lib/tbot/service_kubernetes_v2_output.go +++ b/lib/tbot/service_kubernetes_v2_output.go @@ -78,7 +78,7 @@ func (s *KubernetesV2OutputService) Run(ctx context.Context) error { return trace.Wrap(runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.CertificateLifetime.RenewalInterval, + interval: s.certificateLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -115,7 +115,7 @@ func (s *KubernetesV2OutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, nil, ) if err != nil { @@ -448,3 +448,10 @@ func generateKubeConfigV2WithoutPlugin(ks *kubernetesStatusV2) (*clientcmdapi.Co return config, nil } + +func (s *KubernetesV2OutputService) certificateLifetime() config.CertificateLifetime { + if !s.cfg.CertificateLifetime.IsEmpty() { + return s.cfg.CertificateLifetime + } + return s.botCfg.CertificateLifetime +} From a2b093573b86462708a03ea010979f32386b24c2 Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Fri, 7 Feb 2025 16:06:25 +0000 Subject: [PATCH 07/23] Support custom `certificate_ttl` and `renewal_interval` on database tunnel --- lib/tbot/config/service_database_tunnel.go | 8 ++++++++ lib/tbot/service_database_tunnel.go | 11 +++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/tbot/config/service_database_tunnel.go b/lib/tbot/config/service_database_tunnel.go index be035a5091ff4..41c7afa84e8a7 100644 --- a/lib/tbot/config/service_database_tunnel.go +++ b/lib/tbot/config/service_database_tunnel.go @@ -46,6 +46,10 @@ type DatabaseTunnelService struct { // Username is the database username to proxy as. Username string `yaml:"username"` + // CertificateLifetime contains configuration for how long certificates will + // last and the frequency at which they'll be renewed. + CertificateLifetime CertificateLifetime `yaml:",inline"` + // Listener overrides "listen" and directly provides an opened listener to // use. Listener net.Listener `yaml:"-"` @@ -85,3 +89,7 @@ func (s *DatabaseTunnelService) CheckAndSetDefaults() error { } return nil } + +func (s *DatabaseTunnelService) GetCertificateLifetime() CertificateLifetime { + return s.CertificateLifetime +} diff --git a/lib/tbot/service_database_tunnel.go b/lib/tbot/service_database_tunnel.go index d69482a343986..c64297807572a 100644 --- a/lib/tbot/service_database_tunnel.go +++ b/lib/tbot/service_database_tunnel.go @@ -240,7 +240,7 @@ func (s *DatabaseTunnelService) getRouteToDatabaseWithImpersonation(ctx context. s.botClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, nil, ) if err != nil { @@ -280,7 +280,7 @@ func (s *DatabaseTunnelService) issueCert( s.botClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, func(req *proto.UserCertsRequest) { req.RouteToDatabase = route }) @@ -297,3 +297,10 @@ func (s *DatabaseTunnelService) issueCert( func (s *DatabaseTunnelService) String() string { return fmt.Sprintf("%s:%s:%s", config.DatabaseTunnelServiceType, s.cfg.Listen, s.cfg.Service) } + +func (s *DatabaseTunnelService) certificateLifetime() config.CertificateLifetime { + if !s.cfg.CertificateLifetime.IsEmpty() { + return s.cfg.CertificateLifetime + } + return s.botCfg.CertificateLifetime +} From 5f9b697e14e7463c0d1fe6f8f3104c2e1a3477cb Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Fri, 7 Feb 2025 16:13:25 +0000 Subject: [PATCH 08/23] Support custom `certificate_ttl` and `renewal_interval` on SSH host output --- lib/tbot/config/service_ssh_host.go | 8 ++++++++ lib/tbot/service_ssh_host_output.go | 13 ++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/tbot/config/service_ssh_host.go b/lib/tbot/config/service_ssh_host.go index 813046d971e49..0839753b69593 100644 --- a/lib/tbot/config/service_ssh_host.go +++ b/lib/tbot/config/service_ssh_host.go @@ -57,6 +57,10 @@ type SSHHostOutput struct { // Principals is a list of principals to request for the host cert. Principals []string `yaml:"principals"` + + // CertificateLifetime contains configuration for how long certificates will + // last and the frequency at which they'll be renewed. + CertificateLifetime CertificateLifetime `yaml:",inline"` } func (o *SSHHostOutput) Init(ctx context.Context) error { @@ -114,3 +118,7 @@ func (o *SSHHostOutput) UnmarshalYAML(node *yaml.Node) error { func (o *SSHHostOutput) Type() string { return SSHHostOutputType } + +func (o *SSHHostOutput) GetCertificateLifetime() CertificateLifetime { + return o.CertificateLifetime +} diff --git a/lib/tbot/service_ssh_host_output.go b/lib/tbot/service_ssh_host_output.go index 4bf9bcc46e6bd..89e59799d940e 100644 --- a/lib/tbot/service_ssh_host_output.go +++ b/lib/tbot/service_ssh_host_output.go @@ -65,7 +65,7 @@ func (s *SSHHostOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.CertificateLifetime.RenewalInterval, + interval: s.certificateLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -107,7 +107,7 @@ func (s *SSHHostOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, nil, ) if err != nil { @@ -143,7 +143,7 @@ func (s *SSHHostOutputService) generate(ctx context.Context) error { Principals: s.cfg.Principals, ClusterName: clusterName, Role: string(types.RoleNode), - Ttl: durationpb.New(s.botCfg.CertificateLifetime.TTL), + Ttl: durationpb.New(s.certificateLifetime().TTL), }, ) if err != nil { @@ -226,3 +226,10 @@ func exportSSHUserCAs(cas []types.CertAuthority, localAuthName string) (string, return exported, nil } + +func (s *SSHHostOutputService) certificateLifetime() config.CertificateLifetime { + if !s.cfg.CertificateLifetime.IsEmpty() { + return s.cfg.CertificateLifetime + } + return s.botCfg.CertificateLifetime +} From 06c64fa61bdc363bc65d770e5ea3f68b657e82ff Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Fri, 7 Feb 2025 16:19:41 +0000 Subject: [PATCH 09/23] Support custom `certificate_ttl` and `renewal_interval` on SSH multiplexer --- lib/tbot/config/service_ssh_multiplexer.go | 8 ++++++++ lib/tbot/service_ssh_multiplexer.go | 11 +++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/tbot/config/service_ssh_multiplexer.go b/lib/tbot/config/service_ssh_multiplexer.go index 11b7093f1f25c..91390108d3634 100644 --- a/lib/tbot/config/service_ssh_multiplexer.go +++ b/lib/tbot/config/service_ssh_multiplexer.go @@ -48,6 +48,10 @@ type SSHMultiplexerService struct { // will be automatically appended. // Optional: If not provided, it will default to the `tbot` binary. ProxyCommand []string `yaml:"proxy_command,omitempty"` + + // CertificateLifetime contains configuration for how long certificates will + // last and the frequency at which they'll be renewed. + CertificateLifetime CertificateLifetime `yaml:",inline"` } func (s *SSHMultiplexerService) SessionResumptionEnabled() bool { @@ -93,3 +97,7 @@ func (s *SSHMultiplexerService) CheckAndSetDefaults() error { } return nil } + +func (o *SSHMultiplexerService) GetCertificateLifetime() CertificateLifetime { + return o.CertificateLifetime +} diff --git a/lib/tbot/service_ssh_multiplexer.go b/lib/tbot/service_ssh_multiplexer.go index 525f3cad41597..b1edc62b13ad5 100644 --- a/lib/tbot/service_ssh_multiplexer.go +++ b/lib/tbot/service_ssh_multiplexer.go @@ -345,7 +345,7 @@ func (s *SSHMultiplexerService) generateIdentity(ctx context.Context) (*identity s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, nil, ) if err != nil { @@ -396,7 +396,7 @@ func (s *SSHMultiplexerService) identityRenewalLoop( s.identity.Set(id) return s.writeArtifacts(ctx, proxyHost, authClient) }, - interval: s.botCfg.CertificateLifetime.RenewalInterval, + interval: s.certificateLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -865,3 +865,10 @@ func (s *cyclingHostDialClient) DialHost(ctx context.Context, target string, clu wrappedConn.parent.Store(currentClt) return wrappedConn, details, nil } + +func (s *SSHMultiplexerService) certificateLifetime() config.CertificateLifetime { + if !s.cfg.CertificateLifetime.IsEmpty() { + return s.cfg.CertificateLifetime + } + return s.botCfg.CertificateLifetime +} From 0e075b0fbd1bd9ed2ac3bbc2f1ae32cfd429c41f Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Mon, 10 Feb 2025 10:41:44 +0000 Subject: [PATCH 10/23] Support custom `certificate_ttl` and `renewal_interval` on SPIFFE SVID output --- lib/tbot/config/service_spiffe_svid.go | 8 ++++++++ lib/tbot/service_spiffe_svid_output.go | 15 +++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/tbot/config/service_spiffe_svid.go b/lib/tbot/config/service_spiffe_svid.go index c72928608804d..6c3558f65a0a5 100644 --- a/lib/tbot/config/service_spiffe_svid.go +++ b/lib/tbot/config/service_spiffe_svid.go @@ -123,6 +123,10 @@ type SPIFFESVIDOutput struct { // JWTs is an optional list of audiences and file names to write JWT SVIDs // to. JWTs []JWTSVID `yaml:"jwts,omitempty"` + + // CertificateLifetime contains configuration for how long certificates will + // last and the frequency at which they'll be renewed. + CertificateLifetime CertificateLifetime `yaml:",inline"` } // Init initializes the destination. @@ -194,3 +198,7 @@ func (o *SPIFFESVIDOutput) UnmarshalYAML(node *yaml.Node) error { o.Destination = dest return nil } + +func (o *SPIFFESVIDOutput) GetCertificateLifetime() CertificateLifetime { + return o.CertificateLifetime +} diff --git a/lib/tbot/service_spiffe_svid_output.go b/lib/tbot/service_spiffe_svid_output.go index 8419e08a2acf5..5dd9b85f8684a 100644 --- a/lib/tbot/service_spiffe_svid_output.go +++ b/lib/tbot/service_spiffe_svid_output.go @@ -134,7 +134,7 @@ func (s *SPIFFESVIDOutputService) Run(ctx context.Context) error { privateKey = nil } bundleSet = newBundleSet - case <-time.After(s.botCfg.CertificateLifetime.RenewalInterval): + case <-time.After(s.certificateLifetime().RenewalInterval): s.log.InfoContext(ctx, "Renewal interval reached, renewing SVIDs") res = nil privateKey = nil @@ -183,7 +183,7 @@ func (s *SPIFFESVIDOutputService) requestSVID( s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, nil, ) if err != nil { @@ -202,7 +202,7 @@ func (s *SPIFFESVIDOutputService) requestSVID( ctx, impersonatedClient, []config.SVIDRequest{s.cfg.SVID}, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, ) if err != nil { return nil, nil, nil, trace.Wrap(err, "generating X509 SVID") @@ -213,7 +213,7 @@ func (s *SPIFFESVIDOutputService) requestSVID( impersonatedClient, s.cfg.SVID, s.cfg.JWTs, - s.botCfg.CertificateLifetime.TTL) + s.certificateLifetime().TTL) if err != nil { return nil, nil, nil, trace.Wrap(err, "generating JWT SVIDs") } @@ -401,3 +401,10 @@ func generateSVID( return res, privateKey, nil } + +func (s *SPIFFESVIDOutputService) certificateLifetime() config.CertificateLifetime { + if !s.cfg.CertificateLifetime.IsEmpty() { + return s.cfg.CertificateLifetime + } + return s.botCfg.CertificateLifetime +} From e640b0d0730640514905fc294847b7b39414a0ab Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Mon, 10 Feb 2025 10:54:20 +0000 Subject: [PATCH 11/23] Support custom `certificate_ttl` and `renewal_interval` on database output --- lib/tbot/config/service_database.go | 8 ++++++++ lib/tbot/service_database_output.go | 13 ++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/tbot/config/service_database.go b/lib/tbot/config/service_database.go index 764f5364c07cd..9588220764af6 100644 --- a/lib/tbot/config/service_database.go +++ b/lib/tbot/config/service_database.go @@ -95,6 +95,10 @@ type DatabaseOutput struct { Database string `yaml:"database,omitempty"` // Username is the database username to request access as. Username string `yaml:"username,omitempty"` + + // CertificateLifetime contains configuration for how long certificates will + // last and the frequency at which they'll be renewed. + CertificateLifetime CertificateLifetime `yaml:",inline"` } func (o *DatabaseOutput) Init(ctx context.Context) error { @@ -197,6 +201,10 @@ func (o *DatabaseOutput) Type() string { return DatabaseOutputType } +func (o *DatabaseOutput) GetCertificateLifetime() CertificateLifetime { + return o.CertificateLifetime +} + // SupportedDatabaseFormatStrings returns a constant list of all valid // DatabaseFormat values as strings. func SupportedDatabaseFormatStrings() (ret []string) { diff --git a/lib/tbot/service_database_output.go b/lib/tbot/service_database_output.go index 1272f5b0f5258..91f59c223bf58 100644 --- a/lib/tbot/service_database_output.go +++ b/lib/tbot/service_database_output.go @@ -62,7 +62,7 @@ func (s *DatabaseOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.CertificateLifetime.RenewalInterval, + interval: s.certificateLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -104,7 +104,7 @@ func (s *DatabaseOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, nil, ) if err != nil { @@ -136,7 +136,7 @@ func (s *DatabaseOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, func(req *proto.UserCertsRequest) { req.RouteToDatabase = route }, @@ -303,3 +303,10 @@ func writeMongoDatabaseFiles( func chooseOneDatabase(databases []types.Database, name string) (types.Database, error) { return chooseOneResource(databases, name, "database") } + +func (s *DatabaseOutputService) certificateLifetime() config.CertificateLifetime { + if !s.cfg.CertificateLifetime.IsEmpty() { + return s.cfg.CertificateLifetime + } + return s.botCfg.CertificateLifetime +} From fefc20e5aa5d891fa99b46a47d74d5a768e9570b Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Mon, 10 Feb 2025 11:19:18 +0000 Subject: [PATCH 12/23] Support custom `certificate_ttl` and `renewal_interval` on workload API --- lib/tbot/config/service_spiffe_workload_api.go | 8 ++++++++ lib/tbot/config/service_workload_identity_api.go | 8 ++++++++ lib/tbot/service_spiffe_workload_api.go | 12 +++++++++--- lib/tbot/service_workload_identity_api.go | 13 ++++++++++--- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/lib/tbot/config/service_spiffe_workload_api.go b/lib/tbot/config/service_spiffe_workload_api.go index 799da41ebb9ef..0652638cb1e20 100644 --- a/lib/tbot/config/service_spiffe_workload_api.go +++ b/lib/tbot/config/service_spiffe_workload_api.go @@ -126,6 +126,10 @@ type SPIFFEWorkloadAPIService struct { // Workload API server are valid for. If unspecified, this falls back to // the globally configured default. JWTSVIDTTL time.Duration `yaml:"jwt_svid_ttl,omitempty"` + + // CertificateLifetime contains configuration for how long X.509 SVIDs will + // last and the frequency at which they'll be renewed. + CertificateLifetime CertificateLifetime `yaml:",inline"` } func (s *SPIFFEWorkloadAPIService) Type() string { @@ -163,3 +167,7 @@ func (s *SPIFFEWorkloadAPIService) CheckAndSetDefaults() error { } return nil } + +func (o *SPIFFEWorkloadAPIService) GetCertificateLifetime() CertificateLifetime { + return o.CertificateLifetime +} diff --git a/lib/tbot/config/service_workload_identity_api.go b/lib/tbot/config/service_workload_identity_api.go index 2c9d056868d25..5d32c55663bea 100644 --- a/lib/tbot/config/service_workload_identity_api.go +++ b/lib/tbot/config/service_workload_identity_api.go @@ -40,6 +40,10 @@ type WorkloadIdentityAPIService struct { // Selector is the selector for the WorkloadIdentity resource that // will be used to issue WICs. Selector WorkloadIdentitySelector `yaml:"selector"` + + // CertificateLifetime contains configuration for how long X.509 SVIDs will + // last and the frequency at which they'll be renewed. + CertificateLifetime CertificateLifetime `yaml:",inline"` } // CheckAndSetDefaults checks the SPIFFESVIDOutput values and sets any defaults. @@ -76,3 +80,7 @@ func (o *WorkloadIdentityAPIService) UnmarshalYAML(node *yaml.Node) error { } return nil } + +func (o *WorkloadIdentityAPIService) GetCertificateLifetime() CertificateLifetime { + return o.CertificateLifetime +} diff --git a/lib/tbot/service_spiffe_workload_api.go b/lib/tbot/service_spiffe_workload_api.go index 25fb1a9da8321..84d662e86ec0c 100644 --- a/lib/tbot/service_spiffe_workload_api.go +++ b/lib/tbot/service_spiffe_workload_api.go @@ -322,8 +322,7 @@ func (s *SPIFFEWorkloadAPIService) fetchX509SVIDs( ctx, s.client, svidRequests, - // For TTL, we use the one globally configured. - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, ) if err != nil { return nil, trace.Wrap(err) @@ -646,7 +645,7 @@ func (s *SPIFFEWorkloadAPIService) FetchX509SVID( } bundleSet = newBundleSet continue - case <-time.After(s.botCfg.CertificateLifetime.RenewalInterval): + case <-time.After(s.certificateLifetime().RenewalInterval): log.DebugContext(ctx, "Renewal interval reached, renewing SVIDs") svids = nil continue @@ -896,3 +895,10 @@ func (s *SPIFFEWorkloadAPIService) ValidateJWTSVID( func (s *SPIFFEWorkloadAPIService) String() string { return fmt.Sprintf("%s:%s", config.SPIFFEWorkloadAPIServiceType, s.cfg.Listen) } + +func (s *SPIFFEWorkloadAPIService) certificateLifetime() config.CertificateLifetime { + if !s.cfg.CertificateLifetime.IsEmpty() { + return s.cfg.CertificateLifetime + } + return s.botCfg.CertificateLifetime +} diff --git a/lib/tbot/service_workload_identity_api.go b/lib/tbot/service_workload_identity_api.go index 5a22cb298fdc3..cc3ded39ff064 100644 --- a/lib/tbot/service_workload_identity_api.go +++ b/lib/tbot/service_workload_identity_api.go @@ -350,7 +350,7 @@ func (s *WorkloadIdentityAPIService) FetchX509SVID( } bundleSet = newBundleSet continue - case <-time.After(s.botCfg.CertificateLifetime.RenewalInterval): + case <-time.After(s.certificateLifetime().RenewalInterval): log.DebugContext(ctx, "Renewal interval reached, renewing SVIDs") svids = nil continue @@ -408,7 +408,7 @@ func (s *WorkloadIdentityAPIService) fetchX509SVIDs( log, s.client, s.cfg.Selector, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, attest, ) if err != nil { @@ -490,7 +490,7 @@ func (s *WorkloadIdentityAPIService) FetchJWTSVID( s.client, s.cfg.Selector, req.Audience, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, attr, ) if err != nil { @@ -660,3 +660,10 @@ func (s *WorkloadIdentityAPIService) ValidateJWTSVID( func (s *WorkloadIdentityAPIService) String() string { return fmt.Sprintf("%s:%s", config.WorkloadIdentityAPIServiceType, s.cfg.Listen) } + +func (s *WorkloadIdentityAPIService) certificateLifetime() config.CertificateLifetime { + if !s.cfg.CertificateLifetime.IsEmpty() { + return s.cfg.CertificateLifetime + } + return s.botCfg.CertificateLifetime +} From 389030459de1a414d8150ecb279091d44117d158 Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Mon, 10 Feb 2025 11:39:21 +0000 Subject: [PATCH 13/23] Support custom `certificate_ttl` and `renewal_interval` on workload identity output --- lib/tbot/config/service_workload_identity_x509.go | 8 ++++++++ lib/tbot/service_workload_identity_x509.go | 13 ++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/tbot/config/service_workload_identity_x509.go b/lib/tbot/config/service_workload_identity_x509.go index adff17f991eee..5907d7ffda429 100644 --- a/lib/tbot/config/service_workload_identity_x509.go +++ b/lib/tbot/config/service_workload_identity_x509.go @@ -71,6 +71,10 @@ type WorkloadIdentityX509Service struct { // IncludeFederatedTrustBundles controls whether to include federated trust // bundles in the output. IncludeFederatedTrustBundles bool `yaml:"include_federated_trust_bundles,omitempty"` + + // CertificateLifetime contains configuration for how long certificates will + // last and the frequency at which they'll be renewed. + CertificateLifetime CertificateLifetime `yaml:",inline"` } // Init initializes the destination. @@ -134,3 +138,7 @@ func (o *WorkloadIdentityX509Service) UnmarshalYAML(node *yaml.Node) error { o.Destination = dest return nil } + +func (o *WorkloadIdentityX509Service) GetCertificateLifetime() CertificateLifetime { + return o.CertificateLifetime +} diff --git a/lib/tbot/service_workload_identity_x509.go b/lib/tbot/service_workload_identity_x509.go index 86c559caa8d0f..1bf8825c2f5de 100644 --- a/lib/tbot/service_workload_identity_x509.go +++ b/lib/tbot/service_workload_identity_x509.go @@ -126,7 +126,7 @@ func (s *WorkloadIdentityX509Service) Run(ctx context.Context) error { privateKey = nil } bundleSet = newBundleSet - case <-time.After(s.botCfg.CertificateLifetime.RenewalInterval): + case <-time.After(s.certificateLifetime().RenewalInterval): s.log.InfoContext(ctx, "Renewal interval reached, renewing SVIDs") x509Cred = nil privateKey = nil @@ -174,7 +174,7 @@ func (s *WorkloadIdentityX509Service) requestSVID( s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, nil, ) if err != nil { @@ -194,7 +194,7 @@ func (s *WorkloadIdentityX509Service) requestSVID( s.log, impersonatedClient, s.cfg.Selector, - s.botCfg.CertificateLifetime.TTL, + s.certificateLifetime().TTL, nil, ) if err != nil { @@ -303,3 +303,10 @@ func (s *WorkloadIdentityX509Service) render( ) return nil } + +func (s *WorkloadIdentityX509Service) certificateLifetime() config.CertificateLifetime { + if !s.cfg.CertificateLifetime.IsEmpty() { + return s.cfg.CertificateLifetime + } + return s.botCfg.CertificateLifetime +} From 0e3222418b10743ffd3f1347cc7f53ee6e124e04 Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Mon, 10 Feb 2025 11:52:12 +0000 Subject: [PATCH 14/23] Add `GetCertificateLifetime` to service config interface --- lib/tbot/config/config.go | 11 +++++++---- lib/tbot/config/service_client_credential.go | 4 ++++ lib/tbot/config/service_example.go | 4 ++++ lib/tbot/config/service_workload_identity_jwt.go | 4 ++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/tbot/config/config.go b/lib/tbot/config/config.go index 307939bd58d25..5dcd156a7f647 100644 --- a/lib/tbot/config/config.go +++ b/lib/tbot/config/config.go @@ -225,10 +225,8 @@ func (conf *BotConfig) CheckAndSetDefaults() error { if err := service.CheckAndSetDefaults(); err != nil { return trace.Wrap(err, "validating service[%d]", i) } - if v, ok := service.(interface{ GetCertificateLifetime() CertificateLifetime }); ok { - if err := v.GetCertificateLifetime().Validate(conf.Oneshot); err != nil { - return trace.Wrap(err, "validating service[%d]", i) - } + if err := service.GetCertificateLifetime().Validate(conf.Oneshot); err != nil { + return trace.Wrap(err, "validating service[%d]", i) } } @@ -307,6 +305,11 @@ func (conf *BotConfig) CheckAndSetDefaults() error { type ServiceConfig interface { Type() string CheckAndSetDefaults() error + + // GetCertificateLifetime returns the service's custom certificate TTL and + // RenewalInterval. It's used for validation purposes; services that do not + // support these options should return the zero value. + GetCertificateLifetime() CertificateLifetime } // ServiceConfigs assists polymorphic unmarshaling of a slice of ServiceConfigs. diff --git a/lib/tbot/config/service_client_credential.go b/lib/tbot/config/service_client_credential.go index e5c58adb63980..574666f1f0337 100644 --- a/lib/tbot/config/service_client_credential.go +++ b/lib/tbot/config/service_client_credential.go @@ -148,3 +148,7 @@ func (o *UnstableClientCredentialOutput) MarshalYAML() (interface{}, error) { func (o *UnstableClientCredentialOutput) Type() string { return UnstableClientCredentialOutputType } + +func (o *UnstableClientCredentialOutput) GetCertificateLifetime() CertificateLifetime { + return CertificateLifetime{} +} diff --git a/lib/tbot/config/service_example.go b/lib/tbot/config/service_example.go index 471b53bf5c1cd..7a342dd5290c2 100644 --- a/lib/tbot/config/service_example.go +++ b/lib/tbot/config/service_example.go @@ -56,3 +56,7 @@ func (s *ExampleService) CheckAndSetDefaults() error { } return nil } + +func (s *ExampleService) GetCertificateLifetime() CertificateLifetime { + return CertificateLifetime{} +} diff --git a/lib/tbot/config/service_workload_identity_jwt.go b/lib/tbot/config/service_workload_identity_jwt.go index 4c71dace4bcee..02b3de7ae894e 100644 --- a/lib/tbot/config/service_workload_identity_jwt.go +++ b/lib/tbot/config/service_workload_identity_jwt.go @@ -104,3 +104,7 @@ func (o *WorkloadIdentityJWTService) UnmarshalYAML(node *yaml.Node) error { func (o *WorkloadIdentityJWTService) GetDestination() bot.Destination { return o.Destination } + +func (o *WorkloadIdentityJWTService) GetCertificateLifetime() CertificateLifetime { + return CertificateLifetime{} +} From 62f42d178c9d9c4732a97444695774964fb22a17 Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Mon, 10 Feb 2025 12:40:23 +0000 Subject: [PATCH 15/23] Update the docs --- .../includes/machine-id/common-output-config.yaml | 10 ++++++++++ docs/pages/reference/machine-id/configuration.mdx | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/docs/pages/includes/machine-id/common-output-config.yaml b/docs/pages/includes/machine-id/common-output-config.yaml index 98f0bb4972d99..b3d126943cbe5 100644 --- a/docs/pages/includes/machine-id/common-output-config.yaml +++ b/docs/pages/includes/machine-id/common-output-config.yaml @@ -15,3 +15,13 @@ destination: # if no roles are specified, all roles the bot is allowed to impersonate are used. roles: - editor + +# certificate_ttl and renewal_interval override the certificate TTL and renewal +# interval for this specific output, so that you can make its certificates valid +# for shorter than `tbot`'s internal certificates. +# +# This is particularly useful when using `tbot` in one-shot as part of a cron job +# where you need `tbot`'s internal certificate to live long enough to be renewed +# on the next invocation, but don't want long-lived workload certificates on-disk. +certificate_ttl: 30m +renewal_interval: 15m diff --git a/docs/pages/reference/machine-id/configuration.mdx b/docs/pages/reference/machine-id/configuration.mdx index 8d97964dd1ec2..2f23eaa440ad6 100644 --- a/docs/pages/reference/machine-id/configuration.mdx +++ b/docs/pages/reference/machine-id/configuration.mdx @@ -47,6 +47,9 @@ proxy_server: "teleport.example.com:443" # or "example.teleport.sh:443" for Tele # live for. It should be a positive, numeric value with an `m` (for minutes) or # `h` (for hours) suffix. By default, this value is `1h`. # This has a maximum value of `24h`. +# +# It can be overridden for most outputs and services to give them a shorter TTL +# than `tbot`'s internal certificates. certificate_ttl: "1h" # renewal_interval specifies how often `tbot` should aim to renew the @@ -54,6 +57,9 @@ certificate_ttl: "1h" # `m` (for minutes) or `h` (for hours) suffix. The default value is `20m`. # This value must be lower than `certificate_ttl`. # This value is ignored when using `tbot` is running in one-shot mode. +# +# It can be overridden for most outputs and services to give them a shorter +# renewal interval than `tbot`'s internal certificates. renewal_interval: "20m" # oneshot configures `tbot` to exit immediately after generating the outputs. From c75a7978c5f57ee50a3bf8e3fa27cd16d57eb58c Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Mon, 10 Feb 2025 12:48:18 +0000 Subject: [PATCH 16/23] Add more examples to the standard config --- lib/tbot/config/config_test.go | 20 +++++++++++++++++++ .../TestBotConfig_YAML/standard_config.golden | 10 ++++++++++ 2 files changed, 30 insertions(+) diff --git a/lib/tbot/config/config_test.go b/lib/tbot/config/config_test.go index 1f6d25562bc84..5a65d55a30dc3 100644 --- a/lib/tbot/config/config_test.go +++ b/lib/tbot/config/config_test.go @@ -256,6 +256,10 @@ func TestBotConfig_YAML(t *testing.T) { }, }, }, + CertificateLifetime: CertificateLifetime{ + TTL: 30 * time.Second, + RenewalInterval: 15 * time.Second, + }, }, &ExampleService{ Message: "llama", @@ -264,11 +268,19 @@ func TestBotConfig_YAML(t *testing.T) { Destination: &DestinationDirectory{ Path: "/bot/output", }, + CertificateLifetime: CertificateLifetime{ + TTL: 30 * time.Second, + RenewalInterval: 15 * time.Second, + }, }, &ApplicationTunnelService{ Listen: "tcp://127.0.0.1:123", Roles: []string{"access"}, AppName: "my-app", + CertificateLifetime: CertificateLifetime{ + TTL: 30 * time.Second, + RenewalInterval: 15 * time.Second, + }, }, &WorkloadIdentityX509Service{ Destination: &DestinationDirectory{ @@ -277,12 +289,20 @@ func TestBotConfig_YAML(t *testing.T) { Selector: WorkloadIdentitySelector{ Name: "my-workload-identity", }, + CertificateLifetime: CertificateLifetime{ + TTL: 30 * time.Second, + RenewalInterval: 15 * time.Second, + }, }, &WorkloadIdentityAPIService{ Listen: "tcp://127.0.0.1:123", Selector: WorkloadIdentitySelector{ Name: "my-workload-identity", }, + CertificateLifetime: CertificateLifetime{ + TTL: 30 * time.Second, + RenewalInterval: 15 * time.Second, + }, }, &WorkloadIdentityJWTService{ Destination: &DestinationDirectory{ diff --git a/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden b/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden index 74747924e51dc..45964ed36c746 100644 --- a/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden +++ b/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden @@ -44,6 +44,8 @@ services: attestors: kubernetes: enabled: false + certificate_ttl: 30s + renewal_interval: 15s - type: example message: llama - type: ssh-multiplexer @@ -52,17 +54,23 @@ services: path: /bot/output enable_resumption: null proxy_templates_path: "" + certificate_ttl: 30s + renewal_interval: 15s - type: application-tunnel listen: tcp://127.0.0.1:123 roles: - access app_name: my-app + certificate_ttl: 30s + renewal_interval: 15s - type: workload-identity-x509 selector: name: my-workload-identity destination: type: directory path: /an/output/path + certificate_ttl: 30s + renewal_interval: 15s - type: workload-identity-api listen: tcp://127.0.0.1:123 attestors: @@ -70,6 +78,8 @@ services: enabled: false selector: name: my-workload-identity + certificate_ttl: 30s + renewal_interval: 15s - type: workload-identity-jwt selector: name: my-workload-identity From 4593fa20e13bea8114f1587d76106ec8137d4992 Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Tue, 11 Feb 2025 12:17:38 +0000 Subject: [PATCH 17/23] Rename `CertificateLifetime` to `CredentialLifetime` So it can be used for non-certificate credentials like JWTs --- integrations/lib/embeddedtbot/bot_test.go | 2 +- integrations/lib/embeddedtbot/config.go | 4 +- .../terraform/provider/credentials.go | 2 +- lib/tbot/cli/start_identity_test.go | 4 +- lib/tbot/cli/start_legacy.go | 12 +++--- lib/tbot/cli/start_legacy_test.go | 4 +- lib/tbot/cli/start_shared.go | 12 +++--- lib/tbot/cli/start_shared_test.go | 4 +- lib/tbot/config/config.go | 32 +++++++------- lib/tbot/config/config_test.go | 42 +++++++++---------- lib/tbot/config/migrate.go | 2 +- lib/tbot/config/migrate_test.go | 4 +- lib/tbot/config/service_application.go | 8 ++-- lib/tbot/config/service_application_tunnel.go | 8 ++-- lib/tbot/config/service_client_credential.go | 4 +- lib/tbot/config/service_database.go | 8 ++-- lib/tbot/config/service_database_tunnel.go | 8 ++-- lib/tbot/config/service_example.go | 4 +- lib/tbot/config/service_identity.go | 8 ++-- lib/tbot/config/service_kubernetes.go | 8 ++-- lib/tbot/config/service_kubernetes_v2.go | 8 ++-- lib/tbot/config/service_spiffe_svid.go | 8 ++-- .../config/service_spiffe_workload_api.go | 8 ++-- lib/tbot/config/service_ssh_host.go | 8 ++-- lib/tbot/config/service_ssh_multiplexer.go | 8 ++-- .../config/service_workload_identity_api.go | 8 ++-- .../config/service_workload_identity_jwt.go | 4 +- .../config/service_workload_identity_x509.go | 8 ++-- lib/tbot/service_application_output.go | 14 +++---- lib/tbot/service_application_tunnel.go | 12 +++--- lib/tbot/service_bot_identity.go | 10 ++--- lib/tbot/service_client_credential.go | 4 +- lib/tbot/service_database_output.go | 14 +++---- lib/tbot/service_database_tunnel.go | 12 +++--- lib/tbot/service_identity_output.go | 14 +++---- lib/tbot/service_kubernetes_output.go | 14 +++---- lib/tbot/service_kubernetes_v2_output.go | 12 +++--- lib/tbot/service_spiffe_svid_output.go | 16 +++---- lib/tbot/service_spiffe_workload_api.go | 12 +++--- lib/tbot/service_spiffe_workload_api_sds.go | 4 +- .../service_spiffe_workload_api_sds_test.go | 2 +- lib/tbot/service_ssh_host_output.go | 14 +++---- lib/tbot/service_ssh_multiplexer.go | 12 +++--- lib/tbot/service_workload_identity_api.go | 14 +++---- lib/tbot/service_workload_identity_jwt.go | 6 +-- lib/tbot/service_workload_identity_x509.go | 14 +++---- tool/tctl/common/terraform_command.go | 8 ++-- 47 files changed, 224 insertions(+), 224 deletions(-) diff --git a/integrations/lib/embeddedtbot/bot_test.go b/integrations/lib/embeddedtbot/bot_test.go index 55359f054513a..512c220580cc7 100644 --- a/integrations/lib/embeddedtbot/bot_test.go +++ b/integrations/lib/embeddedtbot/bot_test.go @@ -123,7 +123,7 @@ func TestBotJoinAuth(t *testing.T) { JoinMethod: types.JoinMethodToken, }, AuthServer: authAddr.Addr, - CertificateLifetime: config.CertificateLifetime{ + CredentialLifetime: config.CredentialLifetime{ TTL: defaultCertificateTTL, RenewalInterval: defaultRenewalInterval, }, diff --git a/integrations/lib/embeddedtbot/config.go b/integrations/lib/embeddedtbot/config.go index bd83628213ff7..08749ae1e4c94 100644 --- a/integrations/lib/embeddedtbot/config.go +++ b/integrations/lib/embeddedtbot/config.go @@ -45,8 +45,8 @@ func (c *BotConfig) BindFlags(fs *flag.FlagSet) { fs.StringVar(&c.AuthServer, "auth-server", "127.0.0.1:3025", "Address of the Teleport Auth Server or Proxy Server") fs.StringVar(&c.Onboarding.TokenValue, "token", "teleport-operator", "A bot join token or path to file with token value.") fs.StringVar((*string)(&c.Onboarding.JoinMethod), "join-method", string(types.JoinMethodKubernetes), "Method to use to join the Teleport cluster.") - fs.DurationVar(&c.CertificateLifetime.TTL, "certificate-ttl", defaultCertificateTTL, "TTL of short-lived machine certificates.") - fs.DurationVar(&c.CertificateLifetime.RenewalInterval, "renewal-interval", defaultRenewalInterval, "Interval at which short-lived certificates are renewed; must be less than the certificate TTL.") + fs.DurationVar(&c.CredentialLifetime.TTL, "certificate-ttl", defaultCertificateTTL, "TTL of short-lived machine certificates.") + fs.DurationVar(&c.CredentialLifetime.RenewalInterval, "renewal-interval", defaultRenewalInterval, "Interval at which short-lived certificates are renewed; must be less than the certificate TTL.") caPinsFlag := StringListVar{ list: &c.Onboarding.CAPins, } diff --git a/integrations/terraform/provider/credentials.go b/integrations/terraform/provider/credentials.go index d7bdd64bdba26..5f4b2c15d3d12 100644 --- a/integrations/terraform/provider/credentials.go +++ b/integrations/terraform/provider/credentials.go @@ -521,7 +521,7 @@ See https://goteleport.com/docs/reference/join-methods for more details.`) AudienceTag: audienceTag, }, }, - CertificateLifetime: tbotconfig.CertificateLifetime{ + CredentialLifetime: tbotconfig.CredentialLifetime{ TTL: time.Hour, RenewalInterval: 20 * time.Minute, }, diff --git a/lib/tbot/cli/start_identity_test.go b/lib/tbot/cli/start_identity_test.go index 70e7ac0d1203c..646c11ecfb3fa 100644 --- a/lib/tbot/cli/start_identity_test.go +++ b/lib/tbot/cli/start_identity_test.go @@ -55,8 +55,8 @@ func TestIdentityCommand(t *testing.T) { require.Equal(t, "foo", token) require.ElementsMatch(t, cfg.Onboarding.CAPins, []string{"bar"}) - require.Equal(t, time.Minute*10, cfg.CertificateLifetime.TTL) - require.Equal(t, time.Minute*5, cfg.CertificateLifetime.RenewalInterval) + require.Equal(t, time.Minute*10, cfg.CredentialLifetime.TTL) + require.Equal(t, time.Minute*5, cfg.CredentialLifetime.RenewalInterval) require.Equal(t, types.JoinMethodGitHub, cfg.Onboarding.JoinMethod) require.True(t, cfg.Oneshot) require.Equal(t, "0.0.0.0:8080", cfg.DiagAddr) diff --git a/lib/tbot/cli/start_legacy.go b/lib/tbot/cli/start_legacy.go index 8ef4121e9118d..e765c0d99b428 100644 --- a/lib/tbot/cli/start_legacy.go +++ b/lib/tbot/cli/start_legacy.go @@ -188,29 +188,29 @@ func (c *LegacyCommand) ApplyConfig(cfg *config.BotConfig, l *slog.Logger) error } if c.CertificateTTL != 0 { - if cfg.CertificateLifetime.TTL != 0 { + if cfg.CredentialLifetime.TTL != 0 { log.WarnContext( context.TODO(), "CLI parameters are overriding configuration", "flag", "certificate-ttl", - "config_value", cfg.CertificateLifetime.TTL, + "config_value", cfg.CredentialLifetime.TTL, "cli_value", c.CertificateTTL, ) } - cfg.CertificateLifetime.TTL = c.CertificateTTL + cfg.CredentialLifetime.TTL = c.CertificateTTL } if c.RenewalInterval != 0 { - if cfg.CertificateLifetime.RenewalInterval != 0 { + if cfg.CredentialLifetime.RenewalInterval != 0 { log.WarnContext( context.TODO(), "CLI parameters are overriding configuration", "flag", "renewal-interval", - "config_value", cfg.CertificateLifetime.RenewalInterval, + "config_value", cfg.CredentialLifetime.RenewalInterval, "cli_value", c.RenewalInterval, ) } - cfg.CertificateLifetime.RenewalInterval = c.RenewalInterval + cfg.CredentialLifetime.RenewalInterval = c.RenewalInterval } // DataDir overrides any previously-configured storage config diff --git a/lib/tbot/cli/start_legacy_test.go b/lib/tbot/cli/start_legacy_test.go index cc866850967ef..11aad07d230bc 100644 --- a/lib/tbot/cli/start_legacy_test.go +++ b/lib/tbot/cli/start_legacy_test.go @@ -53,8 +53,8 @@ func TestLegacyCommand(t *testing.T) { require.Equal(t, "foo", token) require.ElementsMatch(t, cfg.Onboarding.CAPins, []string{"bar"}) - require.Equal(t, time.Minute*10, cfg.CertificateLifetime.TTL) - require.Equal(t, time.Minute*5, cfg.CertificateLifetime.RenewalInterval) + require.Equal(t, time.Minute*10, cfg.CredentialLifetime.TTL) + require.Equal(t, time.Minute*5, cfg.CredentialLifetime.RenewalInterval) require.Equal(t, types.JoinMethodGitHub, cfg.Onboarding.JoinMethod) require.True(t, cfg.Oneshot) require.Equal(t, "0.0.0.0:8080", cfg.DiagAddr) diff --git a/lib/tbot/cli/start_shared.go b/lib/tbot/cli/start_shared.go index f3c37ab925074..e8c2b895d0d34 100644 --- a/lib/tbot/cli/start_shared.go +++ b/lib/tbot/cli/start_shared.go @@ -153,29 +153,29 @@ func (s *sharedStartArgs) ApplyConfig(cfg *config.BotConfig, l *slog.Logger) err } if s.CertificateTTL != 0 { - if cfg.CertificateLifetime.TTL != 0 { + if cfg.CredentialLifetime.TTL != 0 { l.WarnContext( context.TODO(), "CLI parameters are overriding configuration", "flag", "certificate-ttl", - "config_value", cfg.CertificateLifetime.TTL, + "config_value", cfg.CredentialLifetime.TTL, "cli_value", s.CertificateTTL, ) } - cfg.CertificateLifetime.TTL = s.CertificateTTL + cfg.CredentialLifetime.TTL = s.CertificateTTL } if s.RenewalInterval != 0 { - if cfg.CertificateLifetime.RenewalInterval != 0 { + if cfg.CredentialLifetime.RenewalInterval != 0 { l.WarnContext( context.TODO(), "CLI parameters are overriding configuration", "flag", "renewal-interval", - "config_value", cfg.CertificateLifetime.RenewalInterval, + "config_value", cfg.CredentialLifetime.RenewalInterval, "cli_value", s.RenewalInterval, ) } - cfg.CertificateLifetime.RenewalInterval = s.RenewalInterval + cfg.CredentialLifetime.RenewalInterval = s.RenewalInterval } if s.DiagAddr != "" { diff --git a/lib/tbot/cli/start_shared_test.go b/lib/tbot/cli/start_shared_test.go index 5d5627d71c6ca..e1b4252edf9a0 100644 --- a/lib/tbot/cli/start_shared_test.go +++ b/lib/tbot/cli/start_shared_test.go @@ -66,8 +66,8 @@ func TestSharedStartArgs(t *testing.T) { require.Equal(t, "foo", token) require.ElementsMatch(t, cfg.Onboarding.CAPins, []string{"bar"}) - require.Equal(t, time.Minute*10, cfg.CertificateLifetime.TTL) - require.Equal(t, time.Minute*5, cfg.CertificateLifetime.RenewalInterval) + require.Equal(t, time.Minute*10, cfg.CredentialLifetime.TTL) + require.Equal(t, time.Minute*5, cfg.CredentialLifetime.RenewalInterval) require.Equal(t, types.JoinMethodGitHub, cfg.Onboarding.JoinMethod) require.True(t, cfg.Oneshot) require.Equal(t, "0.0.0.0:8080", cfg.DiagAddr) diff --git a/lib/tbot/config/config.go b/lib/tbot/config/config.go index 5dcd156a7f647..b69ccde6b6170 100644 --- a/lib/tbot/config/config.go +++ b/lib/tbot/config/config.go @@ -152,9 +152,9 @@ type BotConfig struct { // ProxyServer is the teleport proxy address. Unlike `AuthServer` this must // explicitly point to a Teleport proxy. // Example: "example.teleport.sh:443" - ProxyServer string `yaml:"proxy_server,omitempty"` - CertificateLifetime CertificateLifetime `yaml:",inline"` - Oneshot bool `yaml:"oneshot"` + ProxyServer string `yaml:"proxy_server,omitempty"` + CredentialLifetime CredentialLifetime `yaml:",inline"` + Oneshot bool `yaml:"oneshot"` // FIPS instructs `tbot` to run in a mode designed to comply with FIPS // regulations. This means the bot should: // - Refuse to run if not compiled with boringcrypto @@ -225,7 +225,7 @@ func (conf *BotConfig) CheckAndSetDefaults() error { if err := service.CheckAndSetDefaults(); err != nil { return trace.Wrap(err, "validating service[%d]", i) } - if err := service.GetCertificateLifetime().Validate(conf.Oneshot); err != nil { + if err := service.GetCredentialLifetime().Validate(conf.Oneshot); err != nil { return trace.Wrap(err, "validating service[%d]", i) } } @@ -261,12 +261,12 @@ func (conf *BotConfig) CheckAndSetDefaults() error { } } - if conf.CertificateLifetime.TTL == 0 { - conf.CertificateLifetime.TTL = DefaultCertificateTTL + if conf.CredentialLifetime.TTL == 0 { + conf.CredentialLifetime.TTL = DefaultCertificateTTL } - if conf.CertificateLifetime.RenewalInterval == 0 { - conf.CertificateLifetime.RenewalInterval = DefaultRenewInterval + if conf.CredentialLifetime.RenewalInterval == 0 { + conf.CredentialLifetime.RenewalInterval = DefaultRenewInterval } // We require the join method for `configure` and `start` but not for `init` @@ -294,7 +294,7 @@ func (conf *BotConfig) CheckAndSetDefaults() error { } // Validate CertificateTTL and RenewalInterval options - if err := conf.CertificateLifetime.Validate(conf.Oneshot); err != nil { + if err := conf.CredentialLifetime.Validate(conf.Oneshot); err != nil { return err } @@ -306,10 +306,10 @@ type ServiceConfig interface { Type() string CheckAndSetDefaults() error - // GetCertificateLifetime returns the service's custom certificate TTL and + // GetCredentialLifetime returns the service's custom certificate TTL and // RenewalInterval. It's used for validation purposes; services that do not // support these options should return the zero value. - GetCertificateLifetime() CertificateLifetime + GetCredentialLifetime() CredentialLifetime } // ServiceConfigs assists polymorphic unmarshaling of a slice of ServiceConfigs. @@ -610,24 +610,24 @@ func ReadConfig(reader io.ReadSeeker, manualMigration bool) (*BotConfig, error) } } -// CertificateLifetime contains configuration for how long certificates will +// CredentialLifetime contains configuration for how long credentials will // last (TTL) and the frequency at which they'll be renewed (RenewalInterval). // // It's a member on the BotConfig and service/output config structs, marked with // the `inline` YAML tag so its fields become individual fields in the YAML // config format. -type CertificateLifetime struct { +type CredentialLifetime struct { TTL time.Duration `yaml:"certificate_ttl,omitempty"` RenewalInterval time.Duration `yaml:"renewal_interval,omitempty"` } // IsEmpty returns whether none of the fields is set (i.e. it is unconfigured). -func (l CertificateLifetime) IsEmpty() bool { - return l == CertificateLifetime{} +func (l CredentialLifetime) IsEmpty() bool { + return l == CredentialLifetime{} } // Validate checks whether the combination of the fields is valid. -func (l CertificateLifetime) Validate(oneShot bool) error { +func (l CredentialLifetime) Validate(oneShot bool) error { if l.IsEmpty() { return nil } diff --git a/lib/tbot/config/config_test.go b/lib/tbot/config/config_test.go index 5a65d55a30dc3..345de32db2f2c 100644 --- a/lib/tbot/config/config_test.go +++ b/lib/tbot/config/config_test.go @@ -42,7 +42,7 @@ func TestConfigFile(t *testing.T) { require.NoError(t, cfg.CheckAndSetDefaults()) require.Equal(t, "auth.example.com", cfg.AuthServer) - require.Equal(t, time.Minute*5, cfg.CertificateLifetime.RenewalInterval) + require.Equal(t, time.Minute*5, cfg.CredentialLifetime.RenewalInterval) require.NotNil(t, cfg.Onboarding) @@ -202,7 +202,7 @@ func TestBotConfig_YAML(t *testing.T) { Oneshot: true, AuthServer: "example.teleport.sh:443", DiagAddr: "127.0.0.1:1337", - CertificateLifetime: CertificateLifetime{ + CredentialLifetime: CredentialLifetime{ TTL: time.Minute, RenewalInterval: time.Second * 30, }, @@ -221,7 +221,7 @@ func TestBotConfig_YAML(t *testing.T) { Destination: &DestinationKubernetesSecret{ Name: "my-secret", }, - CertificateLifetime: CertificateLifetime{ + CredentialLifetime: CredentialLifetime{ TTL: 30 * time.Second, RenewalInterval: 15 * time.Second, }, @@ -256,7 +256,7 @@ func TestBotConfig_YAML(t *testing.T) { }, }, }, - CertificateLifetime: CertificateLifetime{ + CredentialLifetime: CredentialLifetime{ TTL: 30 * time.Second, RenewalInterval: 15 * time.Second, }, @@ -268,7 +268,7 @@ func TestBotConfig_YAML(t *testing.T) { Destination: &DestinationDirectory{ Path: "/bot/output", }, - CertificateLifetime: CertificateLifetime{ + CredentialLifetime: CredentialLifetime{ TTL: 30 * time.Second, RenewalInterval: 15 * time.Second, }, @@ -277,7 +277,7 @@ func TestBotConfig_YAML(t *testing.T) { Listen: "tcp://127.0.0.1:123", Roles: []string{"access"}, AppName: "my-app", - CertificateLifetime: CertificateLifetime{ + CredentialLifetime: CredentialLifetime{ TTL: 30 * time.Second, RenewalInterval: 15 * time.Second, }, @@ -289,7 +289,7 @@ func TestBotConfig_YAML(t *testing.T) { Selector: WorkloadIdentitySelector{ Name: "my-workload-identity", }, - CertificateLifetime: CertificateLifetime{ + CredentialLifetime: CredentialLifetime{ TTL: 30 * time.Second, RenewalInterval: 15 * time.Second, }, @@ -299,7 +299,7 @@ func TestBotConfig_YAML(t *testing.T) { Selector: WorkloadIdentitySelector{ Name: "my-workload-identity", }, - CertificateLifetime: CertificateLifetime{ + CredentialLifetime: CredentialLifetime{ TTL: 30 * time.Second, RenewalInterval: 15 * time.Second, }, @@ -321,7 +321,7 @@ func TestBotConfig_YAML(t *testing.T) { in: BotConfig{ Version: V2, AuthServer: "example.teleport.sh:443", - CertificateLifetime: CertificateLifetime{ + CredentialLifetime: CredentialLifetime{ TTL: time.Minute, RenewalInterval: time.Second * 30, }, @@ -337,7 +337,7 @@ func TestBotConfig_YAML(t *testing.T) { in: BotConfig{ Version: V2, ProxyServer: "example.teleport.sh:443", - CertificateLifetime: CertificateLifetime{ + CredentialLifetime: CredentialLifetime{ TTL: time.Minute, RenewalInterval: time.Second * 30, }, @@ -419,50 +419,50 @@ func TestBotConfig_WithCAPathAndCAPins(t *testing.T) { require.ErrorContains(t, cfg.CheckAndSetDefaults(), "mutually exclusive") } -func TestBotConfig_ServicePartialCertificateLifetime(t *testing.T) { +func TestBotConfig_ServicePartialCredentialLifetime(t *testing.T) { cfg := &BotConfig{ Version: V2, AuthServer: "example.teleport.sh:443", Services: []ServiceConfig{ &IdentityOutput{ - CertificateLifetime: CertificateLifetime{TTL: 5 * time.Minute}, - Destination: &DestinationMemory{}, + CredentialLifetime: CredentialLifetime{TTL: 5 * time.Minute}, + Destination: &DestinationMemory{}, }, }, } require.ErrorContains(t, cfg.CheckAndSetDefaults(), "certificate_ttl and renewal_interval") } -func TestBotConfig_ServiceInvalidCertificateLifetime(t *testing.T) { +func TestBotConfig_ServiceInvalidCredentialLifetime(t *testing.T) { cfg := &BotConfig{ Version: V2, AuthServer: "example.teleport.sh:443", Services: []ServiceConfig{ &IdentityOutput{ - CertificateLifetime: CertificateLifetime{TTL: 5 * time.Minute}, - Destination: &DestinationMemory{}, + CredentialLifetime: CredentialLifetime{TTL: 5 * time.Minute}, + Destination: &DestinationMemory{}, }, }, } require.ErrorContains(t, cfg.CheckAndSetDefaults(), "certificate_ttl and renewal_interval") } -func TestCertificateLifetimeValidate(t *testing.T) { +func TestCredentialLifetimeValidate(t *testing.T) { testCases := map[string]struct { - cfg CertificateLifetime + cfg CredentialLifetime oneShot bool error string }{ "partial config": { - cfg: CertificateLifetime{TTL: 1 * time.Minute}, + cfg: CredentialLifetime{TTL: 1 * time.Minute}, error: "certificate_ttl and renewal_interval must both be specified if either is", }, "negative TTL": { - cfg: CertificateLifetime{TTL: -time.Minute, RenewalInterval: time.Minute}, + cfg: CredentialLifetime{TTL: -time.Minute, RenewalInterval: time.Minute}, error: "certificate_ttl must be positive", }, "negative renewal interval": { - cfg: CertificateLifetime{TTL: time.Minute, RenewalInterval: -time.Minute}, + cfg: CredentialLifetime{TTL: time.Minute, RenewalInterval: -time.Minute}, error: "renewal_interval must be positive", }, } diff --git a/lib/tbot/config/migrate.go b/lib/tbot/config/migrate.go index 6245a6282a666..2db890bd8d712 100644 --- a/lib/tbot/config/migrate.go +++ b/lib/tbot/config/migrate.go @@ -405,7 +405,7 @@ func (c *configV1) migrate() (*BotConfig, error) { Onboarding: c.Onboarding, Debug: c.Debug, AuthServer: c.AuthServer, - CertificateLifetime: CertificateLifetime{ + CredentialLifetime: CredentialLifetime{ TTL: c.CertificateTTL, RenewalInterval: c.RenewalInterval, }, diff --git a/lib/tbot/config/migrate_test.go b/lib/tbot/config/migrate_test.go index c1ab04e2b7f9d..db87a895b2e38 100644 --- a/lib/tbot/config/migrate_test.go +++ b/lib/tbot/config/migrate_test.go @@ -110,7 +110,7 @@ destinations: AuthServer: "example.teleport.sh:443", Oneshot: true, Debug: true, - CertificateLifetime: CertificateLifetime{ + CredentialLifetime: CredentialLifetime{ RenewalInterval: time.Minute * 10, TTL: time.Minute * 30, }, @@ -576,7 +576,7 @@ oneshot: false "sha256:1234abcd5678efgh910ijklmnop", }, }, - CertificateLifetime: CertificateLifetime{ + CredentialLifetime: CredentialLifetime{ RenewalInterval: DefaultRenewInterval, TTL: DefaultCertificateTTL, }, diff --git a/lib/tbot/config/service_application.go b/lib/tbot/config/service_application.go index 7c1b3bddc72c1..cd4148d702910 100644 --- a/lib/tbot/config/service_application.go +++ b/lib/tbot/config/service_application.go @@ -48,9 +48,9 @@ type ApplicationOutput struct { // be configured with specific paths to use, but exists for compatibility. SpecificTLSExtensions bool `yaml:"specific_tls_naming"` - // CertificateLifetime contains configuration for how long certificates will + // CredentialLifetime contains configuration for how long credentials will // last and the frequency at which they'll be renewed. - CertificateLifetime CertificateLifetime `yaml:",inline"` + CredentialLifetime CredentialLifetime `yaml:",inline"` } func (o *ApplicationOutput) Init(ctx context.Context) error { @@ -126,6 +126,6 @@ func (o *ApplicationOutput) Type() string { return ApplicationOutputType } -func (o *ApplicationOutput) GetCertificateLifetime() CertificateLifetime { - return o.CertificateLifetime +func (o *ApplicationOutput) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime } diff --git a/lib/tbot/config/service_application_tunnel.go b/lib/tbot/config/service_application_tunnel.go index a52aa8aa78aaa..ede5b1a4ac44f 100644 --- a/lib/tbot/config/service_application_tunnel.go +++ b/lib/tbot/config/service_application_tunnel.go @@ -46,9 +46,9 @@ type ApplicationTunnelService struct { // that you wish to tunnel to. AppName string `yaml:"app_name"` - // CertificateLifetime contains configuration for how long certificates will + // CredentialLifetime contains configuration for how long credentials will // last and the frequency at which they'll be renewed. - CertificateLifetime CertificateLifetime `yaml:",inline"` + CredentialLifetime CredentialLifetime `yaml:",inline"` // Listener overrides "listen" and directly provides an opened listener to // use. @@ -86,6 +86,6 @@ func (s *ApplicationTunnelService) CheckAndSetDefaults() error { return nil } -func (o *ApplicationTunnelService) GetCertificateLifetime() CertificateLifetime { - return o.CertificateLifetime +func (o *ApplicationTunnelService) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime } diff --git a/lib/tbot/config/service_client_credential.go b/lib/tbot/config/service_client_credential.go index 574666f1f0337..f685aa7100c99 100644 --- a/lib/tbot/config/service_client_credential.go +++ b/lib/tbot/config/service_client_credential.go @@ -149,6 +149,6 @@ func (o *UnstableClientCredentialOutput) Type() string { return UnstableClientCredentialOutputType } -func (o *UnstableClientCredentialOutput) GetCertificateLifetime() CertificateLifetime { - return CertificateLifetime{} +func (o *UnstableClientCredentialOutput) GetCredentialLifetime() CredentialLifetime { + return CredentialLifetime{} } diff --git a/lib/tbot/config/service_database.go b/lib/tbot/config/service_database.go index 9588220764af6..205e5df49f3c7 100644 --- a/lib/tbot/config/service_database.go +++ b/lib/tbot/config/service_database.go @@ -96,9 +96,9 @@ type DatabaseOutput struct { // Username is the database username to request access as. Username string `yaml:"username,omitempty"` - // CertificateLifetime contains configuration for how long certificates will + // CredentialLifetime contains configuration for how long credentials will // last and the frequency at which they'll be renewed. - CertificateLifetime CertificateLifetime `yaml:",inline"` + CredentialLifetime CredentialLifetime `yaml:",inline"` } func (o *DatabaseOutput) Init(ctx context.Context) error { @@ -201,8 +201,8 @@ func (o *DatabaseOutput) Type() string { return DatabaseOutputType } -func (o *DatabaseOutput) GetCertificateLifetime() CertificateLifetime { - return o.CertificateLifetime +func (o *DatabaseOutput) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime } // SupportedDatabaseFormatStrings returns a constant list of all valid diff --git a/lib/tbot/config/service_database_tunnel.go b/lib/tbot/config/service_database_tunnel.go index 41c7afa84e8a7..0e68563980a8e 100644 --- a/lib/tbot/config/service_database_tunnel.go +++ b/lib/tbot/config/service_database_tunnel.go @@ -46,9 +46,9 @@ type DatabaseTunnelService struct { // Username is the database username to proxy as. Username string `yaml:"username"` - // CertificateLifetime contains configuration for how long certificates will + // CredentialLifetime contains configuration for how long credentials will // last and the frequency at which they'll be renewed. - CertificateLifetime CertificateLifetime `yaml:",inline"` + CredentialLifetime CredentialLifetime `yaml:",inline"` // Listener overrides "listen" and directly provides an opened listener to // use. @@ -90,6 +90,6 @@ func (s *DatabaseTunnelService) CheckAndSetDefaults() error { return nil } -func (s *DatabaseTunnelService) GetCertificateLifetime() CertificateLifetime { - return s.CertificateLifetime +func (s *DatabaseTunnelService) GetCredentialLifetime() CredentialLifetime { + return s.CredentialLifetime } diff --git a/lib/tbot/config/service_example.go b/lib/tbot/config/service_example.go index 7a342dd5290c2..7a09dd38b9cbd 100644 --- a/lib/tbot/config/service_example.go +++ b/lib/tbot/config/service_example.go @@ -57,6 +57,6 @@ func (s *ExampleService) CheckAndSetDefaults() error { return nil } -func (s *ExampleService) GetCertificateLifetime() CertificateLifetime { - return CertificateLifetime{} +func (s *ExampleService) GetCredentialLifetime() CredentialLifetime { + return CredentialLifetime{} } diff --git a/lib/tbot/config/service_identity.go b/lib/tbot/config/service_identity.go index f0739e22368ae..8d51fd43564db 100644 --- a/lib/tbot/config/service_identity.go +++ b/lib/tbot/config/service_identity.go @@ -102,9 +102,9 @@ type IdentityOutput struct { // Defaults to false. AllowReissue bool `yaml:"allow_reissue,omitempty"` - // CertificateLifetime contains configuration for how long certificates will + // CredentialLifetime contains configuration for how long credentials will // last and the frequency at which they'll be renewed. - CertificateLifetime CertificateLifetime `yaml:",inline"` + CredentialLifetime CredentialLifetime `yaml:",inline"` } func (o *IdentityOutput) Init(ctx context.Context) error { @@ -196,6 +196,6 @@ func (o *IdentityOutput) Type() string { return IdentityOutputType } -func (o *IdentityOutput) GetCertificateLifetime() CertificateLifetime { - return o.CertificateLifetime +func (o *IdentityOutput) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime } diff --git a/lib/tbot/config/service_kubernetes.go b/lib/tbot/config/service_kubernetes.go index 8099747e3c138..09a7572bba49a 100644 --- a/lib/tbot/config/service_kubernetes.go +++ b/lib/tbot/config/service_kubernetes.go @@ -55,9 +55,9 @@ type KubernetesOutput struct { // refresh the credentials within an individual invocation. DisableExecPlugin bool `yaml:"disable_exec_plugin"` - // CertificateLifetime contains configuration for how long certificates will + // CredentialLifetime contains configuration for how long credentials will // last and the frequency at which they'll be renewed. - CertificateLifetime CertificateLifetime `yaml:",inline"` + CredentialLifetime CredentialLifetime `yaml:",inline"` } func (o *KubernetesOutput) CheckAndSetDefaults() error { @@ -122,6 +122,6 @@ func (o *KubernetesOutput) Type() string { return KubernetesOutputType } -func (o *KubernetesOutput) GetCertificateLifetime() CertificateLifetime { - return o.CertificateLifetime +func (o *KubernetesOutput) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime } diff --git a/lib/tbot/config/service_kubernetes_v2.go b/lib/tbot/config/service_kubernetes_v2.go index f76f897a5f867..eb0b651dd6ce2 100644 --- a/lib/tbot/config/service_kubernetes_v2.go +++ b/lib/tbot/config/service_kubernetes_v2.go @@ -51,9 +51,9 @@ type KubernetesV2Output struct { // selectors can be used to generate an output containing all matches. Selectors []*KubernetesSelector `yaml:"selectors,omitempty"` - // CertificateLifetime contains configuration for how long certificates will + // CredentialLifetime contains configuration for how long credentials will // last and the frequency at which they'll be renewed. - CertificateLifetime CertificateLifetime `yaml:",inline"` + CredentialLifetime CredentialLifetime `yaml:",inline"` } func (o *KubernetesV2Output) CheckAndSetDefaults() error { @@ -160,6 +160,6 @@ func (s *KubernetesSelector) UnmarshalYAML(value *yaml.Node) error { return nil } -func (o *KubernetesV2Output) GetCertificateLifetime() CertificateLifetime { - return o.CertificateLifetime +func (o *KubernetesV2Output) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime } diff --git a/lib/tbot/config/service_spiffe_svid.go b/lib/tbot/config/service_spiffe_svid.go index 6c3558f65a0a5..b2c145f1e478b 100644 --- a/lib/tbot/config/service_spiffe_svid.go +++ b/lib/tbot/config/service_spiffe_svid.go @@ -124,9 +124,9 @@ type SPIFFESVIDOutput struct { // to. JWTs []JWTSVID `yaml:"jwts,omitempty"` - // CertificateLifetime contains configuration for how long certificates will + // CredentialLifetime contains configuration for how long credentials will // last and the frequency at which they'll be renewed. - CertificateLifetime CertificateLifetime `yaml:",inline"` + CredentialLifetime CredentialLifetime `yaml:",inline"` } // Init initializes the destination. @@ -199,6 +199,6 @@ func (o *SPIFFESVIDOutput) UnmarshalYAML(node *yaml.Node) error { return nil } -func (o *SPIFFESVIDOutput) GetCertificateLifetime() CertificateLifetime { - return o.CertificateLifetime +func (o *SPIFFESVIDOutput) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime } diff --git a/lib/tbot/config/service_spiffe_workload_api.go b/lib/tbot/config/service_spiffe_workload_api.go index 0652638cb1e20..c5e0917bf0666 100644 --- a/lib/tbot/config/service_spiffe_workload_api.go +++ b/lib/tbot/config/service_spiffe_workload_api.go @@ -127,9 +127,9 @@ type SPIFFEWorkloadAPIService struct { // the globally configured default. JWTSVIDTTL time.Duration `yaml:"jwt_svid_ttl,omitempty"` - // CertificateLifetime contains configuration for how long X.509 SVIDs will + // CredentialLifetime contains configuration for how long X.509 SVIDs will // last and the frequency at which they'll be renewed. - CertificateLifetime CertificateLifetime `yaml:",inline"` + CredentialLifetime CredentialLifetime `yaml:",inline"` } func (s *SPIFFEWorkloadAPIService) Type() string { @@ -168,6 +168,6 @@ func (s *SPIFFEWorkloadAPIService) CheckAndSetDefaults() error { return nil } -func (o *SPIFFEWorkloadAPIService) GetCertificateLifetime() CertificateLifetime { - return o.CertificateLifetime +func (o *SPIFFEWorkloadAPIService) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime } diff --git a/lib/tbot/config/service_ssh_host.go b/lib/tbot/config/service_ssh_host.go index 0839753b69593..7729cfc0a8c06 100644 --- a/lib/tbot/config/service_ssh_host.go +++ b/lib/tbot/config/service_ssh_host.go @@ -58,9 +58,9 @@ type SSHHostOutput struct { // Principals is a list of principals to request for the host cert. Principals []string `yaml:"principals"` - // CertificateLifetime contains configuration for how long certificates will + // CredentialLifetime contains configuration for how long credentials will // last and the frequency at which they'll be renewed. - CertificateLifetime CertificateLifetime `yaml:",inline"` + CredentialLifetime CredentialLifetime `yaml:",inline"` } func (o *SSHHostOutput) Init(ctx context.Context) error { @@ -119,6 +119,6 @@ func (o *SSHHostOutput) Type() string { return SSHHostOutputType } -func (o *SSHHostOutput) GetCertificateLifetime() CertificateLifetime { - return o.CertificateLifetime +func (o *SSHHostOutput) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime } diff --git a/lib/tbot/config/service_ssh_multiplexer.go b/lib/tbot/config/service_ssh_multiplexer.go index 91390108d3634..3d538647518cc 100644 --- a/lib/tbot/config/service_ssh_multiplexer.go +++ b/lib/tbot/config/service_ssh_multiplexer.go @@ -49,9 +49,9 @@ type SSHMultiplexerService struct { // Optional: If not provided, it will default to the `tbot` binary. ProxyCommand []string `yaml:"proxy_command,omitempty"` - // CertificateLifetime contains configuration for how long certificates will + // CredentialLifetime contains configuration for how long credentials will // last and the frequency at which they'll be renewed. - CertificateLifetime CertificateLifetime `yaml:",inline"` + CredentialLifetime CredentialLifetime `yaml:",inline"` } func (s *SSHMultiplexerService) SessionResumptionEnabled() bool { @@ -98,6 +98,6 @@ func (s *SSHMultiplexerService) CheckAndSetDefaults() error { return nil } -func (o *SSHMultiplexerService) GetCertificateLifetime() CertificateLifetime { - return o.CertificateLifetime +func (o *SSHMultiplexerService) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime } diff --git a/lib/tbot/config/service_workload_identity_api.go b/lib/tbot/config/service_workload_identity_api.go index 5d32c55663bea..11ed061a04349 100644 --- a/lib/tbot/config/service_workload_identity_api.go +++ b/lib/tbot/config/service_workload_identity_api.go @@ -41,9 +41,9 @@ type WorkloadIdentityAPIService struct { // will be used to issue WICs. Selector WorkloadIdentitySelector `yaml:"selector"` - // CertificateLifetime contains configuration for how long X.509 SVIDs will + // CredentialLifetime contains configuration for how long X.509 SVIDs will // last and the frequency at which they'll be renewed. - CertificateLifetime CertificateLifetime `yaml:",inline"` + CredentialLifetime CredentialLifetime `yaml:",inline"` } // CheckAndSetDefaults checks the SPIFFESVIDOutput values and sets any defaults. @@ -81,6 +81,6 @@ func (o *WorkloadIdentityAPIService) UnmarshalYAML(node *yaml.Node) error { return nil } -func (o *WorkloadIdentityAPIService) GetCertificateLifetime() CertificateLifetime { - return o.CertificateLifetime +func (o *WorkloadIdentityAPIService) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime } diff --git a/lib/tbot/config/service_workload_identity_jwt.go b/lib/tbot/config/service_workload_identity_jwt.go index 02b3de7ae894e..fd206b219bc20 100644 --- a/lib/tbot/config/service_workload_identity_jwt.go +++ b/lib/tbot/config/service_workload_identity_jwt.go @@ -105,6 +105,6 @@ func (o *WorkloadIdentityJWTService) GetDestination() bot.Destination { return o.Destination } -func (o *WorkloadIdentityJWTService) GetCertificateLifetime() CertificateLifetime { - return CertificateLifetime{} +func (o *WorkloadIdentityJWTService) GetCredentialLifetime() CredentialLifetime { + return CredentialLifetime{} } diff --git a/lib/tbot/config/service_workload_identity_x509.go b/lib/tbot/config/service_workload_identity_x509.go index 5907d7ffda429..d5055585e9fc8 100644 --- a/lib/tbot/config/service_workload_identity_x509.go +++ b/lib/tbot/config/service_workload_identity_x509.go @@ -72,9 +72,9 @@ type WorkloadIdentityX509Service struct { // bundles in the output. IncludeFederatedTrustBundles bool `yaml:"include_federated_trust_bundles,omitempty"` - // CertificateLifetime contains configuration for how long certificates will + // CredentialLifetime contains configuration for how long credentials will // last and the frequency at which they'll be renewed. - CertificateLifetime CertificateLifetime `yaml:",inline"` + CredentialLifetime CredentialLifetime `yaml:",inline"` } // Init initializes the destination. @@ -139,6 +139,6 @@ func (o *WorkloadIdentityX509Service) UnmarshalYAML(node *yaml.Node) error { return nil } -func (o *WorkloadIdentityX509Service) GetCertificateLifetime() CertificateLifetime { - return o.CertificateLifetime +func (o *WorkloadIdentityX509Service) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime } diff --git a/lib/tbot/service_application_output.go b/lib/tbot/service_application_output.go index cd4a60c6ab176..197bb38f796bb 100644 --- a/lib/tbot/service_application_output.go +++ b/lib/tbot/service_application_output.go @@ -62,7 +62,7 @@ func (s *ApplicationOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.certificateLifetime().RenewalInterval, + interval: s.credentialLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -104,7 +104,7 @@ func (s *ApplicationOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, nil, ) if err != nil { @@ -134,7 +134,7 @@ func (s *ApplicationOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, func(req *proto.UserCertsRequest) { req.RouteToApp = routeToApp }, @@ -255,9 +255,9 @@ func getApp(ctx context.Context, clt *authclient.Client, appName string) (types. return apps[0], nil } -func (s *ApplicationOutputService) certificateLifetime() config.CertificateLifetime { - if !s.cfg.CertificateLifetime.IsEmpty() { - return s.cfg.CertificateLifetime +func (s *ApplicationOutputService) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime } - return s.botCfg.CertificateLifetime + return s.botCfg.CredentialLifetime } diff --git a/lib/tbot/service_application_tunnel.go b/lib/tbot/service_application_tunnel.go index 49a1ffba6f670..f80b33cad3f78 100644 --- a/lib/tbot/service_application_tunnel.go +++ b/lib/tbot/service_application_tunnel.go @@ -201,7 +201,7 @@ func (s *ApplicationTunnelService) issueCert( s.botClient, s.getBotIdentity(), roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, nil, ) if err != nil { @@ -233,7 +233,7 @@ func (s *ApplicationTunnelService) issueCert( s.botClient, s.getBotIdentity(), roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, func(req *proto.UserCertsRequest) { req.RouteToApp = route }) @@ -251,9 +251,9 @@ func (s *ApplicationTunnelService) String() string { return fmt.Sprintf("%s:%s:%s", config.ApplicationTunnelServiceType, s.cfg.Listen, s.cfg.AppName) } -func (s *ApplicationTunnelService) certificateLifetime() config.CertificateLifetime { - if !s.cfg.CertificateLifetime.IsEmpty() { - return s.cfg.CertificateLifetime +func (s *ApplicationTunnelService) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime } - return s.botCfg.CertificateLifetime + return s.botCfg.CredentialLifetime } diff --git a/lib/tbot/service_bot_identity.go b/lib/tbot/service_bot_identity.go index b8af2c0b75d01..0fa5f07a0b938 100644 --- a/lib/tbot/service_bot_identity.go +++ b/lib/tbot/service_bot_identity.go @@ -262,8 +262,8 @@ func (s *identityService) Run(ctx context.Context) error { s.log.InfoContext( ctx, "Beginning bot identity renewal loop", - "ttl", s.cfg.CertificateLifetime.TTL, - "interval", s.cfg.CertificateLifetime.RenewalInterval, + "ttl", s.cfg.CredentialLifetime.TTL, + "interval", s.cfg.CredentialLifetime.RenewalInterval, ) err := runOnInterval(ctx, runOnIntervalConfig{ @@ -271,7 +271,7 @@ func (s *identityService) Run(ctx context.Context) error { f: func(ctx context.Context) error { return s.renew(ctx, storageDestination) }, - interval: s.cfg.CertificateLifetime.RenewalInterval, + interval: s.cfg.CredentialLifetime.RenewalInterval, exitOnRetryExhausted: true, retryLimit: botIdentityRenewalRetryLimit, log: s.log, @@ -333,7 +333,7 @@ func renewIdentity( // When using a renewable join method, we use GenerateUserCerts to // request a new certificate using our current identity. newIdentity, err := botIdentityFromAuth( - ctx, log, oldIdentity, authClient, botCfg.CertificateLifetime.TTL, + ctx, log, oldIdentity, authClient, botCfg.CredentialLifetime.TTL, ) if err != nil { return nil, trace.Wrap(err, "renewing identity using GenerateUserCert") @@ -435,7 +435,7 @@ func botIdentityFromToken( return nil, trace.Wrap(err) } - expires := time.Now().Add(cfg.CertificateLifetime.TTL) + expires := time.Now().Add(cfg.CredentialLifetime.TTL) params := join.RegisterParams{ Token: token, ID: state.IdentityID{ diff --git a/lib/tbot/service_client_credential.go b/lib/tbot/service_client_credential.go index 1044cd2408d84..f44f168535329 100644 --- a/lib/tbot/service_client_credential.go +++ b/lib/tbot/service_client_credential.go @@ -57,7 +57,7 @@ func (s *ClientCredentialOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.botCfg.CertificateLifetime.RenewalInterval, + interval: s.botCfg.CredentialLifetime.RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -83,7 +83,7 @@ func (s *ClientCredentialOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.botCfg.CredentialLifetime.TTL, nil, ) if err != nil { diff --git a/lib/tbot/service_database_output.go b/lib/tbot/service_database_output.go index 91f59c223bf58..e76b9bddbf982 100644 --- a/lib/tbot/service_database_output.go +++ b/lib/tbot/service_database_output.go @@ -62,7 +62,7 @@ func (s *DatabaseOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.certificateLifetime().RenewalInterval, + interval: s.credentialLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -104,7 +104,7 @@ func (s *DatabaseOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, nil, ) if err != nil { @@ -136,7 +136,7 @@ func (s *DatabaseOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, func(req *proto.UserCertsRequest) { req.RouteToDatabase = route }, @@ -304,9 +304,9 @@ func chooseOneDatabase(databases []types.Database, name string) (types.Database, return chooseOneResource(databases, name, "database") } -func (s *DatabaseOutputService) certificateLifetime() config.CertificateLifetime { - if !s.cfg.CertificateLifetime.IsEmpty() { - return s.cfg.CertificateLifetime +func (s *DatabaseOutputService) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime } - return s.botCfg.CertificateLifetime + return s.botCfg.CredentialLifetime } diff --git a/lib/tbot/service_database_tunnel.go b/lib/tbot/service_database_tunnel.go index c64297807572a..fb629295f74fb 100644 --- a/lib/tbot/service_database_tunnel.go +++ b/lib/tbot/service_database_tunnel.go @@ -240,7 +240,7 @@ func (s *DatabaseTunnelService) getRouteToDatabaseWithImpersonation(ctx context. s.botClient, s.getBotIdentity(), roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, nil, ) if err != nil { @@ -280,7 +280,7 @@ func (s *DatabaseTunnelService) issueCert( s.botClient, s.getBotIdentity(), roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, func(req *proto.UserCertsRequest) { req.RouteToDatabase = route }) @@ -298,9 +298,9 @@ func (s *DatabaseTunnelService) String() string { return fmt.Sprintf("%s:%s:%s", config.DatabaseTunnelServiceType, s.cfg.Listen, s.cfg.Service) } -func (s *DatabaseTunnelService) certificateLifetime() config.CertificateLifetime { - if !s.cfg.CertificateLifetime.IsEmpty() { - return s.cfg.CertificateLifetime +func (s *DatabaseTunnelService) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime } - return s.botCfg.CertificateLifetime + return s.botCfg.CredentialLifetime } diff --git a/lib/tbot/service_identity_output.go b/lib/tbot/service_identity_output.go index 2c8b401d4d013..3d7389ad285ec 100644 --- a/lib/tbot/service_identity_output.go +++ b/lib/tbot/service_identity_output.go @@ -74,7 +74,7 @@ func (s *IdentityOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.certificateLifetime().RenewalInterval, + interval: s.credentialLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -116,7 +116,7 @@ func (s *IdentityOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, func(req *proto.UserCertsRequest) { req.ReissuableRoleImpersonation = s.cfg.AllowReissue }, @@ -139,7 +139,7 @@ func (s *IdentityOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, func(req *proto.UserCertsRequest) { req.RouteToCluster = s.cfg.Cluster req.ReissuableRoleImpersonation = s.cfg.AllowReissue @@ -226,11 +226,11 @@ func (s *IdentityOutputService) render( return nil } -func (s *IdentityOutputService) certificateLifetime() config.CertificateLifetime { - if !s.cfg.CertificateLifetime.IsEmpty() { - return s.cfg.CertificateLifetime +func (s *IdentityOutputService) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime } - return s.botCfg.CertificateLifetime + return s.botCfg.CredentialLifetime } type certAuthGetter interface { diff --git a/lib/tbot/service_kubernetes_output.go b/lib/tbot/service_kubernetes_output.go index 5d6fd9d56c39c..6a769af49a324 100644 --- a/lib/tbot/service_kubernetes_output.go +++ b/lib/tbot/service_kubernetes_output.go @@ -79,7 +79,7 @@ func (s *KubernetesOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.certificateLifetime().RenewalInterval, + interval: s.credentialLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -121,7 +121,7 @@ func (s *KubernetesOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, nil, ) if err != nil { @@ -152,7 +152,7 @@ func (s *KubernetesOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, func(req *proto.UserCertsRequest) { req.KubernetesCluster = kubeClusterName }, @@ -462,9 +462,9 @@ func selectKubeConnectionMethod(proxyPong *proxyPingResponse) ( return "", "", trace.BadParameter("unable to determine kubernetes address") } -func (s *KubernetesOutputService) certificateLifetime() config.CertificateLifetime { - if !s.cfg.CertificateLifetime.IsEmpty() { - return s.cfg.CertificateLifetime +func (s *KubernetesOutputService) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime } - return s.botCfg.CertificateLifetime + return s.botCfg.CredentialLifetime } diff --git a/lib/tbot/service_kubernetes_v2_output.go b/lib/tbot/service_kubernetes_v2_output.go index 34ead5207fe63..d8ccde4a621d4 100644 --- a/lib/tbot/service_kubernetes_v2_output.go +++ b/lib/tbot/service_kubernetes_v2_output.go @@ -78,7 +78,7 @@ func (s *KubernetesV2OutputService) Run(ctx context.Context) error { return trace.Wrap(runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.certificateLifetime().RenewalInterval, + interval: s.credentialLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -115,7 +115,7 @@ func (s *KubernetesV2OutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, nil, ) if err != nil { @@ -449,9 +449,9 @@ func generateKubeConfigV2WithoutPlugin(ks *kubernetesStatusV2) (*clientcmdapi.Co return config, nil } -func (s *KubernetesV2OutputService) certificateLifetime() config.CertificateLifetime { - if !s.cfg.CertificateLifetime.IsEmpty() { - return s.cfg.CertificateLifetime +func (s *KubernetesV2OutputService) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime } - return s.botCfg.CertificateLifetime + return s.botCfg.CredentialLifetime } diff --git a/lib/tbot/service_spiffe_svid_output.go b/lib/tbot/service_spiffe_svid_output.go index 5dd9b85f8684a..15ec632e0f829 100644 --- a/lib/tbot/service_spiffe_svid_output.go +++ b/lib/tbot/service_spiffe_svid_output.go @@ -134,7 +134,7 @@ func (s *SPIFFESVIDOutputService) Run(ctx context.Context) error { privateKey = nil } bundleSet = newBundleSet - case <-time.After(s.certificateLifetime().RenewalInterval): + case <-time.After(s.credentialLifetime().RenewalInterval): s.log.InfoContext(ctx, "Renewal interval reached, renewing SVIDs") res = nil privateKey = nil @@ -183,7 +183,7 @@ func (s *SPIFFESVIDOutputService) requestSVID( s.botAuthClient, s.getBotIdentity(), roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, nil, ) if err != nil { @@ -202,7 +202,7 @@ func (s *SPIFFESVIDOutputService) requestSVID( ctx, impersonatedClient, []config.SVIDRequest{s.cfg.SVID}, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, ) if err != nil { return nil, nil, nil, trace.Wrap(err, "generating X509 SVID") @@ -213,7 +213,7 @@ func (s *SPIFFESVIDOutputService) requestSVID( impersonatedClient, s.cfg.SVID, s.cfg.JWTs, - s.certificateLifetime().TTL) + s.credentialLifetime().TTL) if err != nil { return nil, nil, nil, trace.Wrap(err, "generating JWT SVIDs") } @@ -402,9 +402,9 @@ func generateSVID( return res, privateKey, nil } -func (s *SPIFFESVIDOutputService) certificateLifetime() config.CertificateLifetime { - if !s.cfg.CertificateLifetime.IsEmpty() { - return s.cfg.CertificateLifetime +func (s *SPIFFESVIDOutputService) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime } - return s.botCfg.CertificateLifetime + return s.botCfg.CredentialLifetime } diff --git a/lib/tbot/service_spiffe_workload_api.go b/lib/tbot/service_spiffe_workload_api.go index 84d662e86ec0c..ba2379f121f4a 100644 --- a/lib/tbot/service_spiffe_workload_api.go +++ b/lib/tbot/service_spiffe_workload_api.go @@ -322,7 +322,7 @@ func (s *SPIFFEWorkloadAPIService) fetchX509SVIDs( ctx, s.client, svidRequests, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, ) if err != nil { return nil, trace.Wrap(err) @@ -645,7 +645,7 @@ func (s *SPIFFEWorkloadAPIService) FetchX509SVID( } bundleSet = newBundleSet continue - case <-time.After(s.certificateLifetime().RenewalInterval): + case <-time.After(s.credentialLifetime().RenewalInterval): log.DebugContext(ctx, "Renewal interval reached, renewing SVIDs") svids = nil continue @@ -896,9 +896,9 @@ func (s *SPIFFEWorkloadAPIService) String() string { return fmt.Sprintf("%s:%s", config.SPIFFEWorkloadAPIServiceType, s.cfg.Listen) } -func (s *SPIFFEWorkloadAPIService) certificateLifetime() config.CertificateLifetime { - if !s.cfg.CertificateLifetime.IsEmpty() { - return s.cfg.CertificateLifetime +func (s *SPIFFEWorkloadAPIService) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime } - return s.botCfg.CertificateLifetime + return s.botCfg.CredentialLifetime } diff --git a/lib/tbot/service_spiffe_workload_api_sds.go b/lib/tbot/service_spiffe_workload_api_sds.go index 5c3768e7c0789..6bcd55bfce6d9 100644 --- a/lib/tbot/service_spiffe_workload_api_sds.go +++ b/lib/tbot/service_spiffe_workload_api_sds.go @@ -200,7 +200,7 @@ func (s *spiffeSDSHandler) StreamSecrets( } }() - renewalTimer := time.NewTimer(s.botCfg.CertificateLifetime.RenewalInterval) + renewalTimer := time.NewTimer(s.botCfg.CredentialLifetime.RenewalInterval) // Stop the timer immediately so we can start timing after the first // response is sent. renewalTimer.Stop() @@ -334,7 +334,7 @@ func (s *spiffeSDSHandler) StreamSecrets( ), ) - renewalTimer.Reset(s.botCfg.CertificateLifetime.RenewalInterval) + renewalTimer.Reset(s.botCfg.CredentialLifetime.RenewalInterval) } } diff --git a/lib/tbot/service_spiffe_workload_api_sds_test.go b/lib/tbot/service_spiffe_workload_api_sds_test.go index 14eee26df4983..283ff16c08ce6 100644 --- a/lib/tbot/service_spiffe_workload_api_sds_test.go +++ b/lib/tbot/service_spiffe_workload_api_sds_test.go @@ -112,7 +112,7 @@ func TestSDS_FetchSecrets(t *testing.T) { }, } botConfig := &config.BotConfig{ - CertificateLifetime: config.CertificateLifetime{ + CredentialLifetime: config.CredentialLifetime{ RenewalInterval: time.Minute, }, } diff --git a/lib/tbot/service_ssh_host_output.go b/lib/tbot/service_ssh_host_output.go index 89e59799d940e..5369b7f2c9778 100644 --- a/lib/tbot/service_ssh_host_output.go +++ b/lib/tbot/service_ssh_host_output.go @@ -65,7 +65,7 @@ func (s *SSHHostOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.certificateLifetime().RenewalInterval, + interval: s.credentialLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -107,7 +107,7 @@ func (s *SSHHostOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, nil, ) if err != nil { @@ -143,7 +143,7 @@ func (s *SSHHostOutputService) generate(ctx context.Context) error { Principals: s.cfg.Principals, ClusterName: clusterName, Role: string(types.RoleNode), - Ttl: durationpb.New(s.certificateLifetime().TTL), + Ttl: durationpb.New(s.credentialLifetime().TTL), }, ) if err != nil { @@ -227,9 +227,9 @@ func exportSSHUserCAs(cas []types.CertAuthority, localAuthName string) (string, return exported, nil } -func (s *SSHHostOutputService) certificateLifetime() config.CertificateLifetime { - if !s.cfg.CertificateLifetime.IsEmpty() { - return s.cfg.CertificateLifetime +func (s *SSHHostOutputService) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime } - return s.botCfg.CertificateLifetime + return s.botCfg.CredentialLifetime } diff --git a/lib/tbot/service_ssh_multiplexer.go b/lib/tbot/service_ssh_multiplexer.go index b1edc62b13ad5..fe5df448c5a40 100644 --- a/lib/tbot/service_ssh_multiplexer.go +++ b/lib/tbot/service_ssh_multiplexer.go @@ -345,7 +345,7 @@ func (s *SSHMultiplexerService) generateIdentity(ctx context.Context) (*identity s.botAuthClient, s.getBotIdentity(), roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, nil, ) if err != nil { @@ -396,7 +396,7 @@ func (s *SSHMultiplexerService) identityRenewalLoop( s.identity.Set(id) return s.writeArtifacts(ctx, proxyHost, authClient) }, - interval: s.certificateLifetime().RenewalInterval, + interval: s.credentialLifetime().RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -866,9 +866,9 @@ func (s *cyclingHostDialClient) DialHost(ctx context.Context, target string, clu return wrappedConn, details, nil } -func (s *SSHMultiplexerService) certificateLifetime() config.CertificateLifetime { - if !s.cfg.CertificateLifetime.IsEmpty() { - return s.cfg.CertificateLifetime +func (s *SSHMultiplexerService) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime } - return s.botCfg.CertificateLifetime + return s.botCfg.CredentialLifetime } diff --git a/lib/tbot/service_workload_identity_api.go b/lib/tbot/service_workload_identity_api.go index cc3ded39ff064..2aec39efc2670 100644 --- a/lib/tbot/service_workload_identity_api.go +++ b/lib/tbot/service_workload_identity_api.go @@ -350,7 +350,7 @@ func (s *WorkloadIdentityAPIService) FetchX509SVID( } bundleSet = newBundleSet continue - case <-time.After(s.certificateLifetime().RenewalInterval): + case <-time.After(s.credentialLifetime().RenewalInterval): log.DebugContext(ctx, "Renewal interval reached, renewing SVIDs") svids = nil continue @@ -408,7 +408,7 @@ func (s *WorkloadIdentityAPIService) fetchX509SVIDs( log, s.client, s.cfg.Selector, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, attest, ) if err != nil { @@ -490,7 +490,7 @@ func (s *WorkloadIdentityAPIService) FetchJWTSVID( s.client, s.cfg.Selector, req.Audience, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, attr, ) if err != nil { @@ -661,9 +661,9 @@ func (s *WorkloadIdentityAPIService) String() string { return fmt.Sprintf("%s:%s", config.WorkloadIdentityAPIServiceType, s.cfg.Listen) } -func (s *WorkloadIdentityAPIService) certificateLifetime() config.CertificateLifetime { - if !s.cfg.CertificateLifetime.IsEmpty() { - return s.cfg.CertificateLifetime +func (s *WorkloadIdentityAPIService) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime } - return s.botCfg.CertificateLifetime + return s.botCfg.CredentialLifetime } diff --git a/lib/tbot/service_workload_identity_jwt.go b/lib/tbot/service_workload_identity_jwt.go index 3edae05c721ce..ea5669af1bcee 100644 --- a/lib/tbot/service_workload_identity_jwt.go +++ b/lib/tbot/service_workload_identity_jwt.go @@ -111,7 +111,7 @@ func (s *WorkloadIdentityJWTService) Run(ctx context.Context) error { cred = nil } bundleSet = newBundleSet - case <-time.After(s.botCfg.CertificateLifetime.RenewalInterval): + case <-time.After(s.botCfg.CredentialLifetime.RenewalInterval): s.log.InfoContext(ctx, "Renewal interval reached, renewing SVIDs") cred = nil case <-firstRun: @@ -157,7 +157,7 @@ func (s *WorkloadIdentityJWTService) requestJWTSVID( s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CertificateLifetime.TTL, + s.botCfg.CredentialLifetime.TTL, nil, ) if err != nil { @@ -178,7 +178,7 @@ func (s *WorkloadIdentityJWTService) requestJWTSVID( impersonatedClient, s.cfg.Selector, s.cfg.Audiences, - s.botCfg.CertificateLifetime.TTL, + s.botCfg.CredentialLifetime.TTL, nil, ) if err != nil { diff --git a/lib/tbot/service_workload_identity_x509.go b/lib/tbot/service_workload_identity_x509.go index 1bf8825c2f5de..76e0e4dcb9f28 100644 --- a/lib/tbot/service_workload_identity_x509.go +++ b/lib/tbot/service_workload_identity_x509.go @@ -126,7 +126,7 @@ func (s *WorkloadIdentityX509Service) Run(ctx context.Context) error { privateKey = nil } bundleSet = newBundleSet - case <-time.After(s.certificateLifetime().RenewalInterval): + case <-time.After(s.credentialLifetime().RenewalInterval): s.log.InfoContext(ctx, "Renewal interval reached, renewing SVIDs") x509Cred = nil privateKey = nil @@ -174,7 +174,7 @@ func (s *WorkloadIdentityX509Service) requestSVID( s.botAuthClient, s.getBotIdentity(), roles, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, nil, ) if err != nil { @@ -194,7 +194,7 @@ func (s *WorkloadIdentityX509Service) requestSVID( s.log, impersonatedClient, s.cfg.Selector, - s.certificateLifetime().TTL, + s.credentialLifetime().TTL, nil, ) if err != nil { @@ -304,9 +304,9 @@ func (s *WorkloadIdentityX509Service) render( return nil } -func (s *WorkloadIdentityX509Service) certificateLifetime() config.CertificateLifetime { - if !s.cfg.CertificateLifetime.IsEmpty() { - return s.cfg.CertificateLifetime +func (s *WorkloadIdentityX509Service) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime } - return s.botCfg.CertificateLifetime + return s.botCfg.CredentialLifetime } diff --git a/tool/tctl/common/terraform_command.go b/tool/tctl/common/terraform_command.go index 04000b296f792..68b909bf09cd8 100644 --- a/tool/tctl/common/terraform_command.go +++ b/tool/tctl/common/terraform_command.go @@ -303,10 +303,10 @@ func (c *TerraformCommand) useBotToObtainIdentity(ctx context.Context, addr util TokenValue: token, JoinMethod: types.JoinMethodToken, }, - Storage: &config.StorageConfig{Destination: &config.DestinationMemory{}}, - Services: config.ServiceConfigs{credential}, - CertificateLifetime: config.CertificateLifetime{TTL: c.botTTL}, - Oneshot: true, + Storage: &config.StorageConfig{Destination: &config.DestinationMemory{}}, + Services: config.ServiceConfigs{credential}, + CredentialLifetime: config.CredentialLifetime{TTL: c.botTTL}, + Oneshot: true, // If --insecure is passed, the bot will trust the certificate on first use. // This does not truly disable TLS validation, only trusts the certificate on first connection. Insecure: clt.Config().InsecureSkipVerify, From ed871575a481d0321f750b1f862de917eabf9f35 Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Tue, 11 Feb 2025 13:31:24 +0000 Subject: [PATCH 18/23] Deprecate `certificate_ttl` option and replace it with `credential_ttl` --- .../pages/enroll-resources/machine-id/faq.mdx | 2 +- .../machine-id/common-output-config.yaml | 4 +-- .../reference/machine-id/configuration.mdx | 6 ++-- lib/tbot/config/config.go | 34 +++++++++++++++++-- lib/tbot/config/config_test.go | 33 +++++++++++++++--- .../TestBotConfig_YAML/minimal_config.golden | 2 +- .../minimal_config_using_proxy_addr.golden | 2 +- .../TestBotConfig_YAML/standard_config.golden | 14 ++++---- .../all_parameters_provided#01/file.golden | 2 +- .../all_parameters_provided#01/stdout.golden | 2 +- .../all_parameters_provided/file.golden | 2 +- .../all_parameters_provided/stdout.golden | 2 +- .../no_parameters_provided/file.golden | 2 +- .../no_parameters_provided/stdout.golden | 2 +- 14 files changed, 81 insertions(+), 28 deletions(-) diff --git a/docs/pages/enroll-resources/machine-id/faq.mdx b/docs/pages/enroll-resources/machine-id/faq.mdx index 1685773dc41cd..25d2ea9914485 100644 --- a/docs/pages/enroll-resources/machine-id/faq.mdx +++ b/docs/pages/enroll-resources/machine-id/faq.mdx @@ -79,7 +79,7 @@ Machine ID. ## Can Machine ID be used to generate long-lived certificates? Machine ID cannot currently be used to generate certificates valid for longer -than 24 hours, and requests for longer certificates using the `certificate_ttl` +than 24 hours, and requests for longer certificates using the `credential_ttl` parameter will be reduced to this 24 hour limit. This limit serves multiple purposes. For one, it encourages security best diff --git a/docs/pages/includes/machine-id/common-output-config.yaml b/docs/pages/includes/machine-id/common-output-config.yaml index b3d126943cbe5..37a2f0ec37b8e 100644 --- a/docs/pages/includes/machine-id/common-output-config.yaml +++ b/docs/pages/includes/machine-id/common-output-config.yaml @@ -16,12 +16,12 @@ destination: roles: - editor -# certificate_ttl and renewal_interval override the certificate TTL and renewal +# credential_ttl and renewal_interval override the credential TTL and renewal # interval for this specific output, so that you can make its certificates valid # for shorter than `tbot`'s internal certificates. # # This is particularly useful when using `tbot` in one-shot as part of a cron job # where you need `tbot`'s internal certificate to live long enough to be renewed # on the next invocation, but don't want long-lived workload certificates on-disk. -certificate_ttl: 30m +credential_ttl: 30m renewal_interval: 15m diff --git a/docs/pages/reference/machine-id/configuration.mdx b/docs/pages/reference/machine-id/configuration.mdx index 2f23eaa440ad6..68ac72706eb7a 100644 --- a/docs/pages/reference/machine-id/configuration.mdx +++ b/docs/pages/reference/machine-id/configuration.mdx @@ -43,19 +43,19 @@ auth_server: "teleport.example.com:3025" # Teleport Cloud, the address of your Teleport Cloud instance. proxy_server: "teleport.example.com:443" # or "example.teleport.sh:443" for Teleport Cloud -# certificate_ttl specifies how long certificates generated by `tbot` should +# credential_ttl specifies how long certificates generated by `tbot` should # live for. It should be a positive, numeric value with an `m` (for minutes) or # `h` (for hours) suffix. By default, this value is `1h`. # This has a maximum value of `24h`. # # It can be overridden for most outputs and services to give them a shorter TTL # than `tbot`'s internal certificates. -certificate_ttl: "1h" +credential_ttl: "1h" # renewal_interval specifies how often `tbot` should aim to renew the # outputs it has generated. It should be a positive, numeric value with an # `m` (for minutes) or `h` (for hours) suffix. The default value is `20m`. -# This value must be lower than `certificate_ttl`. +# This value must be lower than `credential_ttl`. # This value is ignored when using `tbot` is running in one-shot mode. # # It can be overridden for most outputs and services to give them a shorter diff --git a/lib/tbot/config/config.go b/lib/tbot/config/config.go index b69ccde6b6170..cb269141a877f 100644 --- a/lib/tbot/config/config.go +++ b/lib/tbot/config/config.go @@ -206,6 +206,34 @@ func (conf *BotConfig) CipherSuites() []uint16 { return utils.DefaultCipherSuites() } +func (conf *BotConfig) UnmarshalYAML(node *yaml.Node) error { + // Wrap conf in an anonymous struct to avoid having the deprecated field on + // the BotConfig or CredentialLifetime structs, and keep it purely a config + // file parsing concern. + // + // The type alias prevents infinite recursion by obscuring UnmarshalYAML. + type alias BotConfig + output := struct { + *alias `yaml:",inline"` + DeprecatedCertificateTTL *time.Duration `yaml:"certificate_ttl"` + }{alias: (*alias)(conf)} + if err := node.Decode(&output); err != nil { + return err + } + + if output.DeprecatedCertificateTTL != nil { + log.WarnContext(context.TODO(), "Config option certificate_ttl is deprecated and will be removed in a future release. Please use credential_ttl instead.") + + if conf.CredentialLifetime.TTL == 0 { + conf.CredentialLifetime.TTL = *output.DeprecatedCertificateTTL + } else { + log.WarnContext(context.TODO(), "Both certificate_ttl and credential_ttl config options were given, credential_ttl will be used.") + } + } + + return nil +} + func (conf *BotConfig) CheckAndSetDefaults() error { if conf.Version == "" { conf.Version = V2 @@ -617,7 +645,7 @@ func ReadConfig(reader io.ReadSeeker, manualMigration bool) (*BotConfig, error) // the `inline` YAML tag so its fields become individual fields in the YAML // config format. type CredentialLifetime struct { - TTL time.Duration `yaml:"certificate_ttl,omitempty"` + TTL time.Duration `yaml:"credential_ttl,omitempty"` RenewalInterval time.Duration `yaml:"renewal_interval,omitempty"` } @@ -633,11 +661,11 @@ func (l CredentialLifetime) Validate(oneShot bool) error { } if l.TTL == 0 || l.RenewalInterval == 0 { - return trace.BadParameter("certificate_ttl and renewal_interval must both be specified if either is") + return trace.BadParameter("credential_ttl and renewal_interval must both be specified if either is") } if l.TTL < 0 { - return trace.BadParameter("certificate_ttl must be positive") + return trace.BadParameter("credential_ttl must be positive") } if l.RenewalInterval < 0 { diff --git a/lib/tbot/config/config_test.go b/lib/tbot/config/config_test.go index 345de32db2f2c..d82b714a97d83 100644 --- a/lib/tbot/config/config_test.go +++ b/lib/tbot/config/config_test.go @@ -430,7 +430,7 @@ func TestBotConfig_ServicePartialCredentialLifetime(t *testing.T) { }, }, } - require.ErrorContains(t, cfg.CheckAndSetDefaults(), "certificate_ttl and renewal_interval") + require.ErrorContains(t, cfg.CheckAndSetDefaults(), "credential_ttl and renewal_interval") } func TestBotConfig_ServiceInvalidCredentialLifetime(t *testing.T) { @@ -444,7 +444,32 @@ func TestBotConfig_ServiceInvalidCredentialLifetime(t *testing.T) { }, }, } - require.ErrorContains(t, cfg.CheckAndSetDefaults(), "certificate_ttl and renewal_interval") + require.ErrorContains(t, cfg.CheckAndSetDefaults(), "credential_ttl and renewal_interval") +} + +func TestBotConfig_DeprecatedCertificateTTL(t *testing.T) { + t.Run("just deprecated option", func(t *testing.T) { + const config = ` +version: v2 +certificate_ttl: 5m +` + + cfg, err := ReadConfig(strings.NewReader(config), false) + require.NoError(t, err) + require.Equal(t, 5*time.Minute, cfg.CredentialLifetime.TTL) + }) + + t.Run("both options", func(t *testing.T) { + const config = ` +version: v2 +certificate_ttl: 5m +credential_ttl: 10m +` + + cfg, err := ReadConfig(strings.NewReader(config), false) + require.NoError(t, err) + require.Equal(t, 10*time.Minute, cfg.CredentialLifetime.TTL) + }) } func TestCredentialLifetimeValidate(t *testing.T) { @@ -455,11 +480,11 @@ func TestCredentialLifetimeValidate(t *testing.T) { }{ "partial config": { cfg: CredentialLifetime{TTL: 1 * time.Minute}, - error: "certificate_ttl and renewal_interval must both be specified if either is", + error: "credential_ttl and renewal_interval must both be specified if either is", }, "negative TTL": { cfg: CredentialLifetime{TTL: -time.Minute, RenewalInterval: time.Minute}, - error: "certificate_ttl must be positive", + error: "credential_ttl must be positive", }, "negative renewal interval": { cfg: CredentialLifetime{TTL: time.Minute, RenewalInterval: -time.Minute}, diff --git a/lib/tbot/config/testdata/TestBotConfig_YAML/minimal_config.golden b/lib/tbot/config/testdata/TestBotConfig_YAML/minimal_config.golden index d7c7e1c311518..5b38ba25a3189 100644 --- a/lib/tbot/config/testdata/TestBotConfig_YAML/minimal_config.golden +++ b/lib/tbot/config/testdata/TestBotConfig_YAML/minimal_config.golden @@ -5,7 +5,7 @@ outputs: type: memory debug: false auth_server: example.teleport.sh:443 -certificate_ttl: 1m0s +credential_ttl: 1m0s renewal_interval: 30s oneshot: false fips: false diff --git a/lib/tbot/config/testdata/TestBotConfig_YAML/minimal_config_using_proxy_addr.golden b/lib/tbot/config/testdata/TestBotConfig_YAML/minimal_config_using_proxy_addr.golden index 9328ff75099bb..5f6f1d2a1ec31 100644 --- a/lib/tbot/config/testdata/TestBotConfig_YAML/minimal_config_using_proxy_addr.golden +++ b/lib/tbot/config/testdata/TestBotConfig_YAML/minimal_config_using_proxy_addr.golden @@ -5,7 +5,7 @@ outputs: type: memory debug: false proxy_server: example.teleport.sh:443 -certificate_ttl: 1m0s +credential_ttl: 1m0s renewal_interval: 30s oneshot: false fips: false diff --git a/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden b/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden index 45964ed36c746..958e2ccaf8ce1 100644 --- a/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden +++ b/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden @@ -19,7 +19,7 @@ outputs: destination: type: kubernetes_secret name: my-secret - certificate_ttl: 30s + credential_ttl: 30s renewal_interval: 15s services: - type: spiffe-workload-api @@ -44,7 +44,7 @@ services: attestors: kubernetes: enabled: false - certificate_ttl: 30s + credential_ttl: 30s renewal_interval: 15s - type: example message: llama @@ -54,14 +54,14 @@ services: path: /bot/output enable_resumption: null proxy_templates_path: "" - certificate_ttl: 30s + credential_ttl: 30s renewal_interval: 15s - type: application-tunnel listen: tcp://127.0.0.1:123 roles: - access app_name: my-app - certificate_ttl: 30s + credential_ttl: 30s renewal_interval: 15s - type: workload-identity-x509 selector: @@ -69,7 +69,7 @@ services: destination: type: directory path: /an/output/path - certificate_ttl: 30s + credential_ttl: 30s renewal_interval: 15s - type: workload-identity-api listen: tcp://127.0.0.1:123 @@ -78,7 +78,7 @@ services: enabled: false selector: name: my-workload-identity - certificate_ttl: 30s + credential_ttl: 30s renewal_interval: 15s - type: workload-identity-jwt selector: @@ -91,7 +91,7 @@ services: - audience2 debug: true auth_server: example.teleport.sh:443 -certificate_ttl: 1m0s +credential_ttl: 1m0s renewal_interval: 30s oneshot: true fips: true diff --git a/tool/tbot/testdata/TestRun_Configure/all_parameters_provided#01/file.golden b/tool/tbot/testdata/TestRun_Configure/all_parameters_provided#01/file.golden index 91469b967aa8c..838559fa01366 100644 --- a/tool/tbot/testdata/TestRun_Configure/all_parameters_provided#01/file.golden +++ b/tool/tbot/testdata/TestRun_Configure/all_parameters_provided#01/file.golden @@ -9,7 +9,7 @@ storage: acls: try debug: false proxy_server: proxy.example.com:443 -certificate_ttl: 1h0m0s +credential_ttl: 1h0m0s renewal_interval: 20m0s oneshot: false fips: false diff --git a/tool/tbot/testdata/TestRun_Configure/all_parameters_provided#01/stdout.golden b/tool/tbot/testdata/TestRun_Configure/all_parameters_provided#01/stdout.golden index 91469b967aa8c..838559fa01366 100644 --- a/tool/tbot/testdata/TestRun_Configure/all_parameters_provided#01/stdout.golden +++ b/tool/tbot/testdata/TestRun_Configure/all_parameters_provided#01/stdout.golden @@ -9,7 +9,7 @@ storage: acls: try debug: false proxy_server: proxy.example.com:443 -certificate_ttl: 1h0m0s +credential_ttl: 1h0m0s renewal_interval: 20m0s oneshot: false fips: false diff --git a/tool/tbot/testdata/TestRun_Configure/all_parameters_provided/file.golden b/tool/tbot/testdata/TestRun_Configure/all_parameters_provided/file.golden index 6aed3c59c9cb8..f40152f83bb16 100644 --- a/tool/tbot/testdata/TestRun_Configure/all_parameters_provided/file.golden +++ b/tool/tbot/testdata/TestRun_Configure/all_parameters_provided/file.golden @@ -12,7 +12,7 @@ storage: acls: try debug: false auth_server: example.com -certificate_ttl: 42m0s +credential_ttl: 42m0s renewal_interval: 21m0s oneshot: true fips: true diff --git a/tool/tbot/testdata/TestRun_Configure/all_parameters_provided/stdout.golden b/tool/tbot/testdata/TestRun_Configure/all_parameters_provided/stdout.golden index 6aed3c59c9cb8..f40152f83bb16 100644 --- a/tool/tbot/testdata/TestRun_Configure/all_parameters_provided/stdout.golden +++ b/tool/tbot/testdata/TestRun_Configure/all_parameters_provided/stdout.golden @@ -12,7 +12,7 @@ storage: acls: try debug: false auth_server: example.com -certificate_ttl: 42m0s +credential_ttl: 42m0s renewal_interval: 21m0s oneshot: true fips: true diff --git a/tool/tbot/testdata/TestRun_Configure/no_parameters_provided/file.golden b/tool/tbot/testdata/TestRun_Configure/no_parameters_provided/file.golden index b14ed6c58f811..979f28ce38fc3 100644 --- a/tool/tbot/testdata/TestRun_Configure/no_parameters_provided/file.golden +++ b/tool/tbot/testdata/TestRun_Configure/no_parameters_provided/file.golden @@ -8,7 +8,7 @@ storage: symlinks: secure acls: try debug: false -certificate_ttl: 1h0m0s +credential_ttl: 1h0m0s renewal_interval: 20m0s oneshot: false fips: false diff --git a/tool/tbot/testdata/TestRun_Configure/no_parameters_provided/stdout.golden b/tool/tbot/testdata/TestRun_Configure/no_parameters_provided/stdout.golden index b14ed6c58f811..979f28ce38fc3 100644 --- a/tool/tbot/testdata/TestRun_Configure/no_parameters_provided/stdout.golden +++ b/tool/tbot/testdata/TestRun_Configure/no_parameters_provided/stdout.golden @@ -8,7 +8,7 @@ storage: symlinks: secure acls: try debug: false -certificate_ttl: 1h0m0s +credential_ttl: 1h0m0s renewal_interval: 20m0s oneshot: false fips: false From ab6d6219227ab2b887b4d9b30b69be4df0290a59 Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Tue, 11 Feb 2025 13:59:57 +0000 Subject: [PATCH 19/23] Return TTL warnings as errors and let the caller decide what to do with them --- lib/tbot/config/config.go | 70 +++++++++++++++++++++++++++------- lib/tbot/config/config_test.go | 14 +++++++ 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/lib/tbot/config/config.go b/lib/tbot/config/config.go index cb269141a877f..18c5380307440 100644 --- a/lib/tbot/config/config.go +++ b/lib/tbot/config/config.go @@ -20,6 +20,7 @@ package config import ( "context" + "errors" "fmt" "io" "net/url" @@ -322,7 +323,14 @@ func (conf *BotConfig) CheckAndSetDefaults() error { } // Validate CertificateTTL and RenewalInterval options - if err := conf.CredentialLifetime.Validate(conf.Oneshot); err != nil { + var ttlErr SuboptimalCredentialTTLError + err := conf.CredentialLifetime.Validate(conf.Oneshot) + switch { + case errors.As(err, &ttlErr): + // Note: we log this as a warning for backward-compatibility, but should + // just reject the configuration in a future release. + log.WarnContext(context.TODO(), ttlErr.msg, ttlErr.LogLabels()...) + case err != nil: return err } @@ -673,22 +681,58 @@ func (l CredentialLifetime) Validate(oneShot bool) error { } if l.TTL < l.RenewalInterval && !oneShot { - log.WarnContext( - context.TODO(), - "Certificate TTL is shorter than the renewal interval. This is likely an invalid configuration. Increase the certificate TTL or decrease the renewal interval", - "ttl", l.TTL, - "interval", l.RenewalInterval, - ) + return SuboptimalCredentialTTLError{ + msg: "Credential TTL is shorter than the renewal interval. This is likely an invalid configuration. Increase the credential TTL or decrease the renewal interval", + details: map[string]any{ + "ttl": l.TTL, + "interval": l.RenewalInterval, + }, + } } if l.TTL > defaults.MaxRenewableCertTTL { - log.WarnContext( - context.TODO(), - "Requested certificate TTL exceeds the maximum TTL allowed and will likely be reduced by the Teleport server", - "requested_ttl", l.TTL, - "maximum_ttl", defaults.MaxRenewableCertTTL, - ) + return SuboptimalCredentialTTLError{ + msg: "Requested certificate TTL exceeds the maximum TTL allowed and will likely be reduced by the Teleport server", + details: map[string]any{ + "requested_ttl": l.TTL, + "maximum_ttl": defaults.MaxRenewableCertTTL, + }, + } } return nil } + +// SuboptimalCredentialTTLError is returned from CredentialLifetime.Validate +// when the user has set CredentialTTL to something unusual that we can work +// around (e.g. if they exceed MaxRenewableCertTTL the server will reduce it) +// rather than rejecting their configuration. +// +// In the future, these probably *should* be hard failures - but that would be +// a breaking change. +type SuboptimalCredentialTTLError struct { + msg string + details map[string]any +} + +// Error satisfies the error interface. +func (e SuboptimalCredentialTTLError) Error() string { + if len(e.details) == 0 { + return e.msg + } + parts := make([]string, 0, len(e.details)) + for k, v := range e.details { + parts = append(parts, fmt.Sprintf("%s=%v", k, v)) + } + return fmt.Sprintf("%s (%s)", e.msg, strings.Join(parts, ", ")) +} + +// LogLabels returns the error's details as a slice that can be passed as the +// varadic args parameter to log functions. +func (e SuboptimalCredentialTTLError) LogLabels() []any { + labels := make([]any, 0, len(e.details)*2) + for k, v := range e.details { + labels = append(labels, k, v) + } + return labels +} diff --git a/lib/tbot/config/config_test.go b/lib/tbot/config/config_test.go index d82b714a97d83..1cdb24c6266d7 100644 --- a/lib/tbot/config/config_test.go +++ b/lib/tbot/config/config_test.go @@ -30,6 +30,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" + "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/tbot/bot" "github.com/gravitational/teleport/lib/tbot/botfs" "github.com/gravitational/teleport/lib/utils/testutils/golden" @@ -490,6 +491,19 @@ func TestCredentialLifetimeValidate(t *testing.T) { cfg: CredentialLifetime{TTL: time.Minute, RenewalInterval: -time.Minute}, error: "renewal_interval must be positive", }, + "TTL less than renewal interval": { + cfg: CredentialLifetime{TTL: time.Minute, RenewalInterval: 2 * time.Minute}, + error: "TTL is shorter than the renewal interval", + }, + "TTL less than renewal interval (one-shot)": { + cfg: CredentialLifetime{TTL: time.Minute, RenewalInterval: 2 * time.Minute}, + oneShot: true, + error: "", + }, + "TTL too long": { + cfg: CredentialLifetime{TTL: defaults.MaxRenewableCertTTL * 2, RenewalInterval: time.Minute}, + error: "TTL exceeds the maximum TTL allowed", + }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { From 438d716fb9de21e43d7c88799ce0af80d32545f2 Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Tue, 11 Feb 2025 14:05:34 +0000 Subject: [PATCH 20/23] Add `CredentialLifetime` to the "full" service config tests --- lib/tbot/config/service_application_test.go | 5 ++ .../config/service_application_tunnel_test.go | 9 ++- lib/tbot/config/service_database_test.go | 9 ++- .../config/service_database_tunnel_test.go | 9 ++- lib/tbot/config/service_identity_test.go | 5 ++ lib/tbot/config/service_kubernetes_test.go | 9 ++- lib/tbot/config/service_kubernetes_v2_test.go | 9 ++- lib/tbot/config/service_spiffe_svid_test.go | 5 ++ .../service_spiffe_workload_api_test.go | 4 + lib/tbot/config/service_ssh_host_test.go | 9 ++- .../config/service_ssh_multiplexer_test.go | 5 ++ .../service_workload_identity_api_test.go | 5 ++ .../service_workload_identity_x509_test.go | 5 ++ .../TestApplicationOutput_YAML/full.golden | 2 + .../full.golden | 2 + .../TestDatabaseOutput_YAML/full.golden | 2 + .../full.golden | 2 + .../TestIdentityOutput_YAML/full.golden | 2 + .../TestKubernetesOutput_YAML/full.golden | 2 + .../TestKubernetesV2Output_YAML/full.golden | 2 + .../TestSPIFFESVIDOutput_YAML/full.golden | 2 + .../full.golden | 2 + .../TestSSHHostOutput_YAML/full.golden | 2 + .../full.golden | 2 + .../full.golden | 2 + .../full.golden | 2 + .../testdata/TestSDS_FetchSecrets/all.golden | 76 +++++++++---------- .../TestSDS_FetchSecrets/special_ALL.golden | 32 ++++---- .../special_ROOTCA.golden | 26 +++---- .../special_default.golden | 18 ++--- .../TestSDS_FetchSecrets/specific_ca.golden | 26 +++---- .../specific_ca_federated.golden | 26 +++---- .../TestSDS_FetchSecrets/specific_svid.golden | 18 ++--- 33 files changed, 219 insertions(+), 117 deletions(-) diff --git a/lib/tbot/config/service_application_test.go b/lib/tbot/config/service_application_test.go index bfb599bf8679f..8788a1a44b78e 100644 --- a/lib/tbot/config/service_application_test.go +++ b/lib/tbot/config/service_application_test.go @@ -20,6 +20,7 @@ package config import ( "testing" + "time" ) func TestApplicationOutput_YAML(t *testing.T) { @@ -31,6 +32,10 @@ func TestApplicationOutput_YAML(t *testing.T) { Destination: dest, Roles: []string{"access"}, AppName: "my-app", + CredentialLifetime: CredentialLifetime{ + TTL: 1 * time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, { diff --git a/lib/tbot/config/service_application_tunnel_test.go b/lib/tbot/config/service_application_tunnel_test.go index acfa593e924e9..2443bbb550a68 100644 --- a/lib/tbot/config/service_application_tunnel_test.go +++ b/lib/tbot/config/service_application_tunnel_test.go @@ -18,7 +18,10 @@ package config -import "testing" +import ( + "testing" + "time" +) func TestApplicationTunnelService_YAML(t *testing.T) { t.Parallel() @@ -29,6 +32,10 @@ func TestApplicationTunnelService_YAML(t *testing.T) { in: ApplicationTunnelService{ Listen: "tcp://0.0.0.0:3621", AppName: "my-app", + CredentialLifetime: CredentialLifetime{ + TTL: 1 * time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, } diff --git a/lib/tbot/config/service_database_test.go b/lib/tbot/config/service_database_test.go index 040ec8e031353..7318017d5c411 100644 --- a/lib/tbot/config/service_database_test.go +++ b/lib/tbot/config/service_database_test.go @@ -18,7 +18,10 @@ package config -import "testing" +import ( + "testing" + "time" +) func TestDatabaseOutput_YAML(t *testing.T) { dest := &DestinationMemory{} @@ -32,6 +35,10 @@ func TestDatabaseOutput_YAML(t *testing.T) { Service: "my-database-service", Database: "my-database", Username: "my-username", + CredentialLifetime: CredentialLifetime{ + TTL: 1 * time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, { diff --git a/lib/tbot/config/service_database_tunnel_test.go b/lib/tbot/config/service_database_tunnel_test.go index eb6303d8f0153..28d08d10634ca 100644 --- a/lib/tbot/config/service_database_tunnel_test.go +++ b/lib/tbot/config/service_database_tunnel_test.go @@ -18,7 +18,10 @@ package config -import "testing" +import ( + "testing" + "time" +) func TestDatabaseTunnelService_YAML(t *testing.T) { t.Parallel() @@ -32,6 +35,10 @@ func TestDatabaseTunnelService_YAML(t *testing.T) { Service: "service", Database: "database", Username: "username", + CredentialLifetime: CredentialLifetime{ + TTL: 1 * time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, } diff --git a/lib/tbot/config/service_identity_test.go b/lib/tbot/config/service_identity_test.go index 482cc888345aa..287c4cb4fc01e 100644 --- a/lib/tbot/config/service_identity_test.go +++ b/lib/tbot/config/service_identity_test.go @@ -20,6 +20,7 @@ package config import ( "testing" + "time" ) func TestIdentityOutput_YAML(t *testing.T) { @@ -33,6 +34,10 @@ func TestIdentityOutput_YAML(t *testing.T) { Cluster: "leaf.example.com", SSHConfigMode: SSHConfigModeOff, AllowReissue: true, + CredentialLifetime: CredentialLifetime{ + TTL: 1 * time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, { diff --git a/lib/tbot/config/service_kubernetes_test.go b/lib/tbot/config/service_kubernetes_test.go index fc2c92afb2462..034e67eca9139 100644 --- a/lib/tbot/config/service_kubernetes_test.go +++ b/lib/tbot/config/service_kubernetes_test.go @@ -18,7 +18,10 @@ package config -import "testing" +import ( + "testing" + "time" +) func TestKubernetesOutput_YAML(t *testing.T) { dest := &DestinationMemory{} @@ -29,6 +32,10 @@ func TestKubernetesOutput_YAML(t *testing.T) { Destination: dest, Roles: []string{"access"}, KubernetesCluster: "k8s.example.com", + CredentialLifetime: CredentialLifetime{ + TTL: 1 * time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, { diff --git a/lib/tbot/config/service_kubernetes_v2_test.go b/lib/tbot/config/service_kubernetes_v2_test.go index 1fea76e45bef6..65fbb60c32755 100644 --- a/lib/tbot/config/service_kubernetes_v2_test.go +++ b/lib/tbot/config/service_kubernetes_v2_test.go @@ -18,7 +18,10 @@ package config -import "testing" +import ( + "testing" + "time" +) func TestKubernetesV2Output_YAML(t *testing.T) { dest := &DestinationMemory{} @@ -45,6 +48,10 @@ func TestKubernetesV2Output_YAML(t *testing.T) { }, }, }, + CredentialLifetime: CredentialLifetime{ + TTL: 1 * time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, { diff --git a/lib/tbot/config/service_spiffe_svid_test.go b/lib/tbot/config/service_spiffe_svid_test.go index dbf3e51273577..44190da0cf8f1 100644 --- a/lib/tbot/config/service_spiffe_svid_test.go +++ b/lib/tbot/config/service_spiffe_svid_test.go @@ -20,6 +20,7 @@ package config import ( "testing" + "time" ) func TestSPIFFESVIDOutput_YAML(t *testing.T) { @@ -50,6 +51,10 @@ func TestSPIFFESVIDOutput_YAML(t *testing.T) { FileName: "bar", }, }, + CredentialLifetime: CredentialLifetime{ + TTL: 1 * time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, { diff --git a/lib/tbot/config/service_spiffe_workload_api_test.go b/lib/tbot/config/service_spiffe_workload_api_test.go index 46de57dd58d13..fed6c9ef0519c 100644 --- a/lib/tbot/config/service_spiffe_workload_api_test.go +++ b/lib/tbot/config/service_spiffe_workload_api_test.go @@ -81,6 +81,10 @@ func TestSPIFFEWorkloadAPIService_YAML(t *testing.T) { }, }, }, + CredentialLifetime: CredentialLifetime{ + TTL: 1 * time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, { diff --git a/lib/tbot/config/service_ssh_host_test.go b/lib/tbot/config/service_ssh_host_test.go index d1f60a7e22b8b..5b1ba9f817fbf 100644 --- a/lib/tbot/config/service_ssh_host_test.go +++ b/lib/tbot/config/service_ssh_host_test.go @@ -18,7 +18,10 @@ package config -import "testing" +import ( + "testing" + "time" +) func TestSSHHostOutput_YAML(t *testing.T) { dest := &DestinationMemory{} @@ -29,6 +32,10 @@ func TestSSHHostOutput_YAML(t *testing.T) { Destination: dest, Roles: []string{"access"}, Principals: []string{"host.example.com"}, + CredentialLifetime: CredentialLifetime{ + TTL: 1 * time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, { diff --git a/lib/tbot/config/service_ssh_multiplexer_test.go b/lib/tbot/config/service_ssh_multiplexer_test.go index a828ef87535c2..29c2100f09c90 100644 --- a/lib/tbot/config/service_ssh_multiplexer_test.go +++ b/lib/tbot/config/service_ssh_multiplexer_test.go @@ -20,6 +20,7 @@ package config import ( "testing" + "time" "github.com/gravitational/teleport/lib/tbot/botfs" ) @@ -37,6 +38,10 @@ func TestSSHMultiplexerService_YAML(t *testing.T) { EnableResumption: ptr[bool](true), ProxyTemplatesPath: "/etc/teleport/templates", ProxyCommand: []string{"rusty-boi"}, + CredentialLifetime: CredentialLifetime{ + TTL: 1 * time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, } diff --git a/lib/tbot/config/service_workload_identity_api_test.go b/lib/tbot/config/service_workload_identity_api_test.go index b1d6645dd9e57..6fdd8507af66e 100644 --- a/lib/tbot/config/service_workload_identity_api_test.go +++ b/lib/tbot/config/service_workload_identity_api_test.go @@ -18,6 +18,7 @@ package config import ( "testing" + "time" "github.com/gravitational/teleport/lib/tbot/workloadidentity/workloadattest" ) @@ -45,6 +46,10 @@ func TestWorkloadIdentityAPIService_YAML(t *testing.T) { Selector: WorkloadIdentitySelector{ Name: "my-workload-identity", }, + CredentialLifetime: CredentialLifetime{ + TTL: 1 * time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, { diff --git a/lib/tbot/config/service_workload_identity_x509_test.go b/lib/tbot/config/service_workload_identity_x509_test.go index 584aaacf2ca83..a1a9286833978 100644 --- a/lib/tbot/config/service_workload_identity_x509_test.go +++ b/lib/tbot/config/service_workload_identity_x509_test.go @@ -18,6 +18,7 @@ package config import ( "testing" + "time" "github.com/gravitational/teleport/lib/tbot/botfs" ) @@ -35,6 +36,10 @@ func TestWorkloadIdentityX509Service_YAML(t *testing.T) { Name: "my-workload-identity", }, IncludeFederatedTrustBundles: true, + CredentialLifetime: CredentialLifetime{ + TTL: 1 * time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, { diff --git a/lib/tbot/config/testdata/TestApplicationOutput_YAML/full.golden b/lib/tbot/config/testdata/TestApplicationOutput_YAML/full.golden index 031fdb542955c..13b1dc77af3b3 100644 --- a/lib/tbot/config/testdata/TestApplicationOutput_YAML/full.golden +++ b/lib/tbot/config/testdata/TestApplicationOutput_YAML/full.golden @@ -5,3 +5,5 @@ roles: - access app_name: my-app specific_tls_naming: false +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/config/testdata/TestApplicationTunnelService_YAML/full.golden b/lib/tbot/config/testdata/TestApplicationTunnelService_YAML/full.golden index b4580d4c3c539..a6bfec7e4092e 100644 --- a/lib/tbot/config/testdata/TestApplicationTunnelService_YAML/full.golden +++ b/lib/tbot/config/testdata/TestApplicationTunnelService_YAML/full.golden @@ -1,3 +1,5 @@ type: application-tunnel listen: tcp://0.0.0.0:3621 app_name: my-app +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/config/testdata/TestDatabaseOutput_YAML/full.golden b/lib/tbot/config/testdata/TestDatabaseOutput_YAML/full.golden index cda1ff705341a..a066caf2f818a 100644 --- a/lib/tbot/config/testdata/TestDatabaseOutput_YAML/full.golden +++ b/lib/tbot/config/testdata/TestDatabaseOutput_YAML/full.golden @@ -7,3 +7,5 @@ format: tls service: my-database-service database: my-database username: my-username +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/config/testdata/TestDatabaseTunnelService_YAML/full.golden b/lib/tbot/config/testdata/TestDatabaseTunnelService_YAML/full.golden index f56e8dfa7c3c5..2e2d610265421 100644 --- a/lib/tbot/config/testdata/TestDatabaseTunnelService_YAML/full.golden +++ b/lib/tbot/config/testdata/TestDatabaseTunnelService_YAML/full.golden @@ -6,3 +6,5 @@ roles: service: service database: database username: username +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/config/testdata/TestIdentityOutput_YAML/full.golden b/lib/tbot/config/testdata/TestIdentityOutput_YAML/full.golden index 667cddad25427..ddf3935656cc6 100644 --- a/lib/tbot/config/testdata/TestIdentityOutput_YAML/full.golden +++ b/lib/tbot/config/testdata/TestIdentityOutput_YAML/full.golden @@ -6,3 +6,5 @@ roles: cluster: leaf.example.com ssh_config: "off" allow_reissue: true +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/config/testdata/TestKubernetesOutput_YAML/full.golden b/lib/tbot/config/testdata/TestKubernetesOutput_YAML/full.golden index bacaf8176fc8a..2bbfbd14e0c8b 100644 --- a/lib/tbot/config/testdata/TestKubernetesOutput_YAML/full.golden +++ b/lib/tbot/config/testdata/TestKubernetesOutput_YAML/full.golden @@ -5,3 +5,5 @@ roles: - access kubernetes_cluster: k8s.example.com disable_exec_plugin: false +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/config/testdata/TestKubernetesV2Output_YAML/full.golden b/lib/tbot/config/testdata/TestKubernetesV2Output_YAML/full.golden index bb0c1f6c80273..6ff75ac6b8d50 100644 --- a/lib/tbot/config/testdata/TestKubernetesV2Output_YAML/full.golden +++ b/lib/tbot/config/testdata/TestKubernetesV2Output_YAML/full.golden @@ -6,3 +6,5 @@ selectors: - name: foo - labels: foo: bar +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/config/testdata/TestSPIFFESVIDOutput_YAML/full.golden b/lib/tbot/config/testdata/TestSPIFFESVIDOutput_YAML/full.golden index 9ec11ec05704d..ca3640c733fde 100644 --- a/lib/tbot/config/testdata/TestSPIFFESVIDOutput_YAML/full.golden +++ b/lib/tbot/config/testdata/TestSPIFFESVIDOutput_YAML/full.golden @@ -16,3 +16,5 @@ jwts: audience: example.com - file_name: bar audience: 2.example.com +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/config/testdata/TestSPIFFEWorkloadAPIService_YAML/full.golden b/lib/tbot/config/testdata/TestSPIFFEWorkloadAPIService_YAML/full.golden index 9c2e871c5840e..b1d13a1d033c6 100644 --- a/lib/tbot/config/testdata/TestSPIFFEWorkloadAPIService_YAML/full.golden +++ b/lib/tbot/config/testdata/TestSPIFFEWorkloadAPIService_YAML/full.golden @@ -31,3 +31,5 @@ attestors: skip_verify: true anonymous: true jwt_svid_ttl: 5m0s +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/config/testdata/TestSSHHostOutput_YAML/full.golden b/lib/tbot/config/testdata/TestSSHHostOutput_YAML/full.golden index feca5c898976c..8f5ffb3ac97a5 100644 --- a/lib/tbot/config/testdata/TestSSHHostOutput_YAML/full.golden +++ b/lib/tbot/config/testdata/TestSSHHostOutput_YAML/full.golden @@ -5,3 +5,5 @@ roles: - access principals: - host.example.com +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/config/testdata/TestSSHMultiplexerService_YAML/full.golden b/lib/tbot/config/testdata/TestSSHMultiplexerService_YAML/full.golden index cfb0f9947db1b..1df929ad3ddfa 100644 --- a/lib/tbot/config/testdata/TestSSHMultiplexerService_YAML/full.golden +++ b/lib/tbot/config/testdata/TestSSHMultiplexerService_YAML/full.golden @@ -6,3 +6,5 @@ enable_resumption: true proxy_templates_path: /etc/teleport/templates proxy_command: - rusty-boi +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/config/testdata/TestWorkloadIdentityAPIService_YAML/full.golden b/lib/tbot/config/testdata/TestWorkloadIdentityAPIService_YAML/full.golden index 3727e43be0576..3ca5f3b1b8838 100644 --- a/lib/tbot/config/testdata/TestWorkloadIdentityAPIService_YAML/full.golden +++ b/lib/tbot/config/testdata/TestWorkloadIdentityAPIService_YAML/full.golden @@ -11,3 +11,5 @@ attestors: anonymous: true selector: name: my-workload-identity +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/config/testdata/TestWorkloadIdentityX509Service_YAML/full.golden b/lib/tbot/config/testdata/TestWorkloadIdentityX509Service_YAML/full.golden index ecb401da9de18..e3a5cc2a9294f 100644 --- a/lib/tbot/config/testdata/TestWorkloadIdentityX509Service_YAML/full.golden +++ b/lib/tbot/config/testdata/TestWorkloadIdentityX509Service_YAML/full.golden @@ -4,3 +4,5 @@ selector: destination: type: memory include_federated_trust_bundles: true +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/testdata/TestSDS_FetchSecrets/all.golden b/lib/tbot/testdata/TestSDS_FetchSecrets/all.golden index 6b59847567477..ed319fb4b57b3 100644 --- a/lib/tbot/testdata/TestSDS_FetchSecrets/all.golden +++ b/lib/tbot/testdata/TestSDS_FetchSecrets/all.golden @@ -1,42 +1,42 @@ { - "resources": [ + "resources": [ { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", - "name": "spiffe://example.com/default", - "tlsCertificate": { - "certificateChain": { - "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tClEwVlNWQzF6Y0dsbVptVTZMeTlsZUdGdGNHeGxMbU52YlM5a1pXWmhkV3gwCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "name": "spiffe://example.com/default", + "tlsCertificate": { + "certificateChain": { + "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tClEwVlNWQzF6Y0dsbVptVTZMeTlsZUdGdGNHeGxMbU52YlM5a1pXWmhkV3gwCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" }, - "privateKey": { - "inlineBytes": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tClMwVlpMWE53YVdabVpUb3ZMMlY0WVcxd2JHVXVZMjl0TDJSbFptRjFiSFE9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K" + "privateKey": { + "inlineBytes": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tClMwVlpMWE53YVdabVpUb3ZMMlY0WVcxd2JHVXVZMjl0TDJSbFptRjFiSFE9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K" } } }, { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", - "name": "spiffe://example.com/second", - "tlsCertificate": { - "certificateChain": { - "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tClEwVlNWQzF6Y0dsbVptVTZMeTlsZUdGdGNHeGxMbU52YlM5elpXTnZibVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "name": "spiffe://example.com/second", + "tlsCertificate": { + "certificateChain": { + "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tClEwVlNWQzF6Y0dsbVptVTZMeTlsZUdGdGNHeGxMbU52YlM5elpXTnZibVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" }, - "privateKey": { - "inlineBytes": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tClMwVlpMWE53YVdabVpUb3ZMMlY0WVcxd2JHVXVZMjl0TDNObFkyOXVaQT09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K" + "privateKey": { + "inlineBytes": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tClMwVlpMWE53YVdabVpUb3ZMMlY0WVcxd2JHVXVZMjl0TDNObFkyOXVaQT09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K" } } }, { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", - "name": "spiffe://example.com", - "validationContext": { - "customValidatorConfig": { - "name": "envoy.tls.cert_validator.spiffe", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", - "trustDomains": [ + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "name": "spiffe://example.com", + "validationContext": { + "customValidatorConfig": { + "name": "envoy.tls.cert_validator.spiffe", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", + "trustDomains": [ { - "name": "example.com", - "trustBundle": { - "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" + "name": "example.com", + "trustBundle": { + "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" } } ] @@ -45,18 +45,18 @@ } }, { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", - "name": "spiffe://federated.example.com", - "validationContext": { - "customValidatorConfig": { - "name": "envoy.tls.cert_validator.spiffe", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", - "trustDomains": [ + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "name": "spiffe://federated.example.com", + "validationContext": { + "customValidatorConfig": { + "name": "envoy.tls.cert_validator.spiffe", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", + "trustDomains": [ { - "name": "federated.example.com", - "trustBundle": { - "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" + "name": "federated.example.com", + "trustBundle": { + "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" } } ] @@ -65,5 +65,5 @@ } } ], - "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" } \ No newline at end of file diff --git a/lib/tbot/testdata/TestSDS_FetchSecrets/special_ALL.golden b/lib/tbot/testdata/TestSDS_FetchSecrets/special_ALL.golden index 8e2f1dcdc5713..98e7ba3b234ea 100644 --- a/lib/tbot/testdata/TestSDS_FetchSecrets/special_ALL.golden +++ b/lib/tbot/testdata/TestSDS_FetchSecrets/special_ALL.golden @@ -1,24 +1,24 @@ { - "resources": [ + "resources": [ { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", - "name": "ALL", - "validationContext": { - "customValidatorConfig": { - "name": "envoy.tls.cert_validator.spiffe", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", - "trustDomains": [ + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "name": "ALL", + "validationContext": { + "customValidatorConfig": { + "name": "envoy.tls.cert_validator.spiffe", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", + "trustDomains": [ { - "name": "federated.example.com", - "trustBundle": { - "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" + "name": "federated.example.com", + "trustBundle": { + "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" } }, { - "name": "example.com", - "trustBundle": { - "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" + "name": "example.com", + "trustBundle": { + "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" } } ] @@ -27,5 +27,5 @@ } } ], - "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" } \ No newline at end of file diff --git a/lib/tbot/testdata/TestSDS_FetchSecrets/special_ROOTCA.golden b/lib/tbot/testdata/TestSDS_FetchSecrets/special_ROOTCA.golden index c6102d07131c4..c9c0222ba2780 100644 --- a/lib/tbot/testdata/TestSDS_FetchSecrets/special_ROOTCA.golden +++ b/lib/tbot/testdata/TestSDS_FetchSecrets/special_ROOTCA.golden @@ -1,18 +1,18 @@ { - "resources": [ + "resources": [ { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", - "name": "ROOTCA", - "validationContext": { - "customValidatorConfig": { - "name": "envoy.tls.cert_validator.spiffe", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", - "trustDomains": [ + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "name": "ROOTCA", + "validationContext": { + "customValidatorConfig": { + "name": "envoy.tls.cert_validator.spiffe", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", + "trustDomains": [ { - "name": "example.com", - "trustBundle": { - "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" + "name": "example.com", + "trustBundle": { + "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" } } ] @@ -21,5 +21,5 @@ } } ], - "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" } \ No newline at end of file diff --git a/lib/tbot/testdata/TestSDS_FetchSecrets/special_default.golden b/lib/tbot/testdata/TestSDS_FetchSecrets/special_default.golden index a718267bfe6d6..584d4843fad8c 100644 --- a/lib/tbot/testdata/TestSDS_FetchSecrets/special_default.golden +++ b/lib/tbot/testdata/TestSDS_FetchSecrets/special_default.golden @@ -1,17 +1,17 @@ { - "resources": [ + "resources": [ { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", - "name": "default", - "tlsCertificate": { - "certificateChain": { - "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tClEwVlNWQzF6Y0dsbVptVTZMeTlsZUdGdGNHeGxMbU52YlM5a1pXWmhkV3gwCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "name": "default", + "tlsCertificate": { + "certificateChain": { + "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tClEwVlNWQzF6Y0dsbVptVTZMeTlsZUdGdGNHeGxMbU52YlM5a1pXWmhkV3gwCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" }, - "privateKey": { - "inlineBytes": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tClMwVlpMWE53YVdabVpUb3ZMMlY0WVcxd2JHVXVZMjl0TDJSbFptRjFiSFE9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K" + "privateKey": { + "inlineBytes": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tClMwVlpMWE53YVdabVpUb3ZMMlY0WVcxd2JHVXVZMjl0TDJSbFptRjFiSFE9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K" } } } ], - "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" } \ No newline at end of file diff --git a/lib/tbot/testdata/TestSDS_FetchSecrets/specific_ca.golden b/lib/tbot/testdata/TestSDS_FetchSecrets/specific_ca.golden index 1ce4732281419..7f57ae3ef817d 100644 --- a/lib/tbot/testdata/TestSDS_FetchSecrets/specific_ca.golden +++ b/lib/tbot/testdata/TestSDS_FetchSecrets/specific_ca.golden @@ -1,18 +1,18 @@ { - "resources": [ + "resources": [ { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", - "name": "spiffe://example.com", - "validationContext": { - "customValidatorConfig": { - "name": "envoy.tls.cert_validator.spiffe", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", - "trustDomains": [ + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "name": "spiffe://example.com", + "validationContext": { + "customValidatorConfig": { + "name": "envoy.tls.cert_validator.spiffe", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", + "trustDomains": [ { - "name": "example.com", - "trustBundle": { - "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" + "name": "example.com", + "trustBundle": { + "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" } } ] @@ -21,5 +21,5 @@ } } ], - "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" } \ No newline at end of file diff --git a/lib/tbot/testdata/TestSDS_FetchSecrets/specific_ca_federated.golden b/lib/tbot/testdata/TestSDS_FetchSecrets/specific_ca_federated.golden index 625594d07e93a..ba09a7f975f58 100644 --- a/lib/tbot/testdata/TestSDS_FetchSecrets/specific_ca_federated.golden +++ b/lib/tbot/testdata/TestSDS_FetchSecrets/specific_ca_federated.golden @@ -1,18 +1,18 @@ { - "resources": [ + "resources": [ { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", - "name": "spiffe://federated.example.com", - "validationContext": { - "customValidatorConfig": { - "name": "envoy.tls.cert_validator.spiffe", - "typedConfig": { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", - "trustDomains": [ + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "name": "spiffe://federated.example.com", + "validationContext": { + "customValidatorConfig": { + "name": "envoy.tls.cert_validator.spiffe", + "typedConfig": { + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.SPIFFECertValidatorConfig", + "trustDomains": [ { - "name": "federated.example.com", - "trustBundle": { - "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" + "name": "federated.example.com", + "trustBundle": { + "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLakNDQWhLZ0F3SUJBZ0lRSnRKREpaWkJrZy9hZk04ZDJaSkNUakFOQmdrcWhraUc5dzBCQVFzRkFEQkEKTVJVd0V3WURWUVFLRXd4VVpXeGxjRzl5ZENCUFUxTXhKekFsQmdOVkJBTVRIblJsYkdWd2IzSjBMbXh2WTJGcwphRzl6ZEM1c2IyTmhiR1J2YldGcGJqQWVGdzB4TnpBMU1Ea3hPVFF3TXpaYUZ3MHlOekExTURjeE9UUXdNelphCk1FQXhGVEFUQmdOVkJBb1RERlJsYkdWd2IzSjBJRTlUVXpFbk1DVUdBMVVFQXhNZWRHVnNaWEJ2Y25RdWJHOWoKWVd4b2IzTjBMbXh2WTJGc1pHOXRZV2x1TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQwpBUUVBdUtGTGFmMmlJSS94RFIrbTJZajZQblVFYStxenF3eHNkTFVqbnVuRlphQVhHK2habTRNbDgwU0NpQmdJCmdUSFFsSnlMSWtUdHVSb0g1YWVNeXoxRVJVQ3RpaTRac1RxRHJqalV5YnhQNHIrNEhWWDZtMzRzNmh3RXI4RmkKZnRzOXBNcDRpUzN0UWd1UmMyOGdQZERvL1Q2VnJKVFZZVWZVVXNORFJ0SXJsQjVPOWlncXFMbnVhWTllcUdpNApQVXgwRzB3UllKcFJ5d29qOEcwSWtwZlFUaVgrQ0FDN2R0NXdzN1pybkdxQ05CTEdpNWJHc2FNbXB0VmJzU0VwCjFUZW5udEY1NFYxaVI0OUlWNUpxRGhtMVMwSG1rbGVvSnpLZGMrNnNQL3hOZXB6OVBKenVGOWQ5TnViVExXZ0IKc0syOFlJdGNtV0hkSFhEL09EeFZhZWhSandJREFRQUJveUF3SGpBT0JnTlZIUThCQWY4RUJBTUNCNEF3REFZRApWUjBUQVFIL0JBSXdBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQVZVNnNOQmRqNzZzYUh3T3hHU2RuRXFRCm8ydE11UjNtc1NNNEY2d0ZLMlVrS2Vwc0Q3Q1lJZi9Qek5TTlVxQTVKSUVVVmVNcUd5aUh1QWJVNEM2NTVuVDEKSXlKWDFELytyNzNzU3A1amJJcFFtMnhvUUdabmo2Zy9LbHR3OE9TT0F3K0RzTUYvUExWcW9XSnAwN3U2ZXcvbQpOeFdzSktjWjVrK3E0ZU14Y2k5bUtSSEhxc3F1V0tYelFsVVJNTkZJK21HYUZ3cktNNGRtemFSMEJFYytpbFN4ClFxVXZRNzRzbXNMSyt6aE5pa21namxHQzVvYjlnOFhraFZBa0pNQWgycmI5b25ETmlSbDY4aUFnY3pQODhtWHUKdk4vbzk4ZHlwenNQeFhtdzZ0a0RxSVJQVUFVYmg0NjVybFk1c0tNbVJnWGkyclVmbC9RVjVuYm96VW8vSFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" } } ] @@ -21,5 +21,5 @@ } } ], - "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" } \ No newline at end of file diff --git a/lib/tbot/testdata/TestSDS_FetchSecrets/specific_svid.golden b/lib/tbot/testdata/TestSDS_FetchSecrets/specific_svid.golden index 91b303484878a..817b3aa0c7eba 100644 --- a/lib/tbot/testdata/TestSDS_FetchSecrets/specific_svid.golden +++ b/lib/tbot/testdata/TestSDS_FetchSecrets/specific_svid.golden @@ -1,17 +1,17 @@ { - "resources": [ + "resources": [ { - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", - "name": "spiffe://example.com/second", - "tlsCertificate": { - "certificateChain": { - "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tClEwVlNWQzF6Y0dsbVptVTZMeTlsZUdGdGNHeGxMbU52YlM5elpXTnZibVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" + "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret", + "name": "spiffe://example.com/second", + "tlsCertificate": { + "certificateChain": { + "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tClEwVlNWQzF6Y0dsbVptVTZMeTlsZUdGdGNHeGxMbU52YlM5elpXTnZibVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" }, - "privateKey": { - "inlineBytes": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tClMwVlpMWE53YVdabVpUb3ZMMlY0WVcxd2JHVXVZMjl0TDNObFkyOXVaQT09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K" + "privateKey": { + "inlineBytes": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tClMwVlpMWE53YVdabVpUb3ZMMlY0WVcxd2JHVXVZMjl0TDNObFkyOXVaQT09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K" } } } ], - "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" + "typeUrl": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret" } \ No newline at end of file From 26284434387582097b2db63054536e405ca73def Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Tue, 11 Feb 2025 14:17:26 +0000 Subject: [PATCH 21/23] Support `credential_ttl` and `renewal_interval` in workload-identity-jwt service --- lib/tbot/config/service_workload_identity_jwt.go | 6 +++++- .../config/service_workload_identity_jwt_test.go | 5 +++++ .../TestWorkloadIdentityJWTService_YAML/full.golden | 2 ++ lib/tbot/service_workload_identity_jwt.go | 13 ++++++++++--- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/lib/tbot/config/service_workload_identity_jwt.go b/lib/tbot/config/service_workload_identity_jwt.go index fd206b219bc20..9311f5a36a356 100644 --- a/lib/tbot/config/service_workload_identity_jwt.go +++ b/lib/tbot/config/service_workload_identity_jwt.go @@ -41,6 +41,10 @@ type WorkloadIdentityJWTService struct { Destination bot.Destination `yaml:"destination"` // Audiences is the list of audiences that the JWT should be valid for. Audiences []string + + // CredentialLifetime contains configuration for how long credentials will + // last and the frequency at which they'll be renewed. + CredentialLifetime CredentialLifetime `yaml:",inline"` } // Init initializes the destination. @@ -106,5 +110,5 @@ func (o *WorkloadIdentityJWTService) GetDestination() bot.Destination { } func (o *WorkloadIdentityJWTService) GetCredentialLifetime() CredentialLifetime { - return CredentialLifetime{} + return o.CredentialLifetime } diff --git a/lib/tbot/config/service_workload_identity_jwt_test.go b/lib/tbot/config/service_workload_identity_jwt_test.go index 6f4f2571df084..0cb31e9030e77 100644 --- a/lib/tbot/config/service_workload_identity_jwt_test.go +++ b/lib/tbot/config/service_workload_identity_jwt_test.go @@ -18,6 +18,7 @@ package config import ( "testing" + "time" "github.com/gravitational/teleport/lib/tbot/botfs" ) @@ -35,6 +36,10 @@ func TestWorkloadIdentityJWTService_YAML(t *testing.T) { Name: "my-workload-identity", }, Audiences: []string{"audience1", "audience2"}, + CredentialLifetime: CredentialLifetime{ + TTL: time.Minute, + RenewalInterval: 30 * time.Second, + }, }, }, } diff --git a/lib/tbot/config/testdata/TestWorkloadIdentityJWTService_YAML/full.golden b/lib/tbot/config/testdata/TestWorkloadIdentityJWTService_YAML/full.golden index 09c561e4cde4a..d17c4a35eb88b 100644 --- a/lib/tbot/config/testdata/TestWorkloadIdentityJWTService_YAML/full.golden +++ b/lib/tbot/config/testdata/TestWorkloadIdentityJWTService_YAML/full.golden @@ -6,3 +6,5 @@ destination: audiences: - audience1 - audience2 +credential_ttl: 1m0s +renewal_interval: 30s diff --git a/lib/tbot/service_workload_identity_jwt.go b/lib/tbot/service_workload_identity_jwt.go index ea5669af1bcee..959b179e8c72d 100644 --- a/lib/tbot/service_workload_identity_jwt.go +++ b/lib/tbot/service_workload_identity_jwt.go @@ -111,7 +111,7 @@ func (s *WorkloadIdentityJWTService) Run(ctx context.Context) error { cred = nil } bundleSet = newBundleSet - case <-time.After(s.botCfg.CredentialLifetime.RenewalInterval): + case <-time.After(s.credentialLifetime().RenewalInterval): s.log.InfoContext(ctx, "Renewal interval reached, renewing SVIDs") cred = nil case <-firstRun: @@ -157,7 +157,7 @@ func (s *WorkloadIdentityJWTService) requestJWTSVID( s.botAuthClient, s.getBotIdentity(), roles, - s.botCfg.CredentialLifetime.TTL, + s.credentialLifetime().TTL, nil, ) if err != nil { @@ -178,7 +178,7 @@ func (s *WorkloadIdentityJWTService) requestJWTSVID( impersonatedClient, s.cfg.Selector, s.cfg.Audiences, - s.botCfg.CredentialLifetime.TTL, + s.credentialLifetime().TTL, nil, ) if err != nil { @@ -248,3 +248,10 @@ func (s *WorkloadIdentityJWTService) render( ) return nil } + +func (s *WorkloadIdentityJWTService) credentialLifetime() config.CredentialLifetime { + if !s.cfg.CredentialLifetime.IsEmpty() { + return s.cfg.CredentialLifetime + } + return s.botCfg.CredentialLifetime +} From 3380cef5a8ec586889f2021a9c158c1ee832dc7d Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Tue, 11 Feb 2025 14:37:04 +0000 Subject: [PATCH 22/23] Silence sloglint --- lib/tbot/config/config.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/tbot/config/config.go b/lib/tbot/config/config.go index 18c5380307440..7b50ae9519074 100644 --- a/lib/tbot/config/config.go +++ b/lib/tbot/config/config.go @@ -329,6 +329,8 @@ func (conf *BotConfig) CheckAndSetDefaults() error { case errors.As(err, &ttlErr): // Note: we log this as a warning for backward-compatibility, but should // just reject the configuration in a future release. + // + //nolint:sloglint // msg cannot be constant log.WarnContext(context.TODO(), ttlErr.msg, ttlErr.LogLabels()...) case err != nil: return err From 80f54e7431cd8e1d306da7afd7a62bd0165c6ed2 Mon Sep 17 00:00:00 2001 From: Dan Upton Date: Fri, 14 Feb 2025 13:56:00 +0000 Subject: [PATCH 23/23] Replace duplicated helper with `cmp.Or` --- lib/tbot/service_application_output.go | 14 ++++---------- lib/tbot/service_application_tunnel.go | 12 +++--------- lib/tbot/service_database_output.go | 14 ++++---------- lib/tbot/service_database_tunnel.go | 12 +++--------- lib/tbot/service_identity_output.go | 14 ++++---------- lib/tbot/service_kubernetes_output.go | 14 ++++---------- lib/tbot/service_kubernetes_v2_output.go | 12 +++--------- lib/tbot/service_spiffe_svid_output.go | 16 +++++----------- lib/tbot/service_spiffe_workload_api.go | 11 ++--------- lib/tbot/service_ssh_host_output.go | 14 ++++---------- lib/tbot/service_ssh_multiplexer.go | 12 +++--------- lib/tbot/service_workload_identity_api.go | 14 ++++---------- lib/tbot/service_workload_identity_jwt.go | 14 ++++---------- lib/tbot/service_workload_identity_x509.go | 14 ++++---------- 14 files changed, 51 insertions(+), 136 deletions(-) diff --git a/lib/tbot/service_application_output.go b/lib/tbot/service_application_output.go index 197bb38f796bb..c07758549d6dc 100644 --- a/lib/tbot/service_application_output.go +++ b/lib/tbot/service_application_output.go @@ -19,6 +19,7 @@ package tbot import ( + "cmp" "context" "fmt" "log/slog" @@ -62,7 +63,7 @@ func (s *ApplicationOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.credentialLifetime().RenewalInterval, + interval: cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -104,7 +105,7 @@ func (s *ApplicationOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { @@ -134,7 +135,7 @@ func (s *ApplicationOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, func(req *proto.UserCertsRequest) { req.RouteToApp = routeToApp }, @@ -254,10 +255,3 @@ func getApp(ctx context.Context, clt *authclient.Client, appName string) (types. return apps[0], nil } - -func (s *ApplicationOutputService) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -} diff --git a/lib/tbot/service_application_tunnel.go b/lib/tbot/service_application_tunnel.go index f80b33cad3f78..2450e6d1103ee 100644 --- a/lib/tbot/service_application_tunnel.go +++ b/lib/tbot/service_application_tunnel.go @@ -19,6 +19,7 @@ package tbot import ( + "cmp" "context" "crypto/tls" "fmt" @@ -201,7 +202,7 @@ func (s *ApplicationTunnelService) issueCert( s.botClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { @@ -233,7 +234,7 @@ func (s *ApplicationTunnelService) issueCert( s.botClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, func(req *proto.UserCertsRequest) { req.RouteToApp = route }) @@ -250,10 +251,3 @@ func (s *ApplicationTunnelService) issueCert( func (s *ApplicationTunnelService) String() string { return fmt.Sprintf("%s:%s:%s", config.ApplicationTunnelServiceType, s.cfg.Listen, s.cfg.AppName) } - -func (s *ApplicationTunnelService) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -} diff --git a/lib/tbot/service_database_output.go b/lib/tbot/service_database_output.go index e76b9bddbf982..b5f4af3e03125 100644 --- a/lib/tbot/service_database_output.go +++ b/lib/tbot/service_database_output.go @@ -19,6 +19,7 @@ package tbot import ( + "cmp" "context" "fmt" "log/slog" @@ -62,7 +63,7 @@ func (s *DatabaseOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.credentialLifetime().RenewalInterval, + interval: cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -104,7 +105,7 @@ func (s *DatabaseOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { @@ -136,7 +137,7 @@ func (s *DatabaseOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, func(req *proto.UserCertsRequest) { req.RouteToDatabase = route }, @@ -303,10 +304,3 @@ func writeMongoDatabaseFiles( func chooseOneDatabase(databases []types.Database, name string) (types.Database, error) { return chooseOneResource(databases, name, "database") } - -func (s *DatabaseOutputService) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -} diff --git a/lib/tbot/service_database_tunnel.go b/lib/tbot/service_database_tunnel.go index fb629295f74fb..6329ce9dd3132 100644 --- a/lib/tbot/service_database_tunnel.go +++ b/lib/tbot/service_database_tunnel.go @@ -19,6 +19,7 @@ package tbot import ( + "cmp" "context" "crypto/tls" "fmt" @@ -240,7 +241,7 @@ func (s *DatabaseTunnelService) getRouteToDatabaseWithImpersonation(ctx context. s.botClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { @@ -280,7 +281,7 @@ func (s *DatabaseTunnelService) issueCert( s.botClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, func(req *proto.UserCertsRequest) { req.RouteToDatabase = route }) @@ -297,10 +298,3 @@ func (s *DatabaseTunnelService) issueCert( func (s *DatabaseTunnelService) String() string { return fmt.Sprintf("%s:%s:%s", config.DatabaseTunnelServiceType, s.cfg.Listen, s.cfg.Service) } - -func (s *DatabaseTunnelService) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -} diff --git a/lib/tbot/service_identity_output.go b/lib/tbot/service_identity_output.go index 3d7389ad285ec..7fcf1c8f6f0bb 100644 --- a/lib/tbot/service_identity_output.go +++ b/lib/tbot/service_identity_output.go @@ -19,6 +19,7 @@ package tbot import ( + "cmp" "context" "fmt" "log/slog" @@ -74,7 +75,7 @@ func (s *IdentityOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.credentialLifetime().RenewalInterval, + interval: cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -116,7 +117,7 @@ func (s *IdentityOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, func(req *proto.UserCertsRequest) { req.ReissuableRoleImpersonation = s.cfg.AllowReissue }, @@ -139,7 +140,7 @@ func (s *IdentityOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, func(req *proto.UserCertsRequest) { req.RouteToCluster = s.cfg.Cluster req.ReissuableRoleImpersonation = s.cfg.AllowReissue @@ -226,13 +227,6 @@ func (s *IdentityOutputService) render( return nil } -func (s *IdentityOutputService) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -} - type certAuthGetter interface { GetCertAuthority( ctx context.Context, diff --git a/lib/tbot/service_kubernetes_output.go b/lib/tbot/service_kubernetes_output.go index 6a769af49a324..10dee53cac269 100644 --- a/lib/tbot/service_kubernetes_output.go +++ b/lib/tbot/service_kubernetes_output.go @@ -20,6 +20,7 @@ package tbot import ( "bytes" + "cmp" "context" "fmt" "log/slog" @@ -79,7 +80,7 @@ func (s *KubernetesOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.credentialLifetime().RenewalInterval, + interval: cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -121,7 +122,7 @@ func (s *KubernetesOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { @@ -152,7 +153,7 @@ func (s *KubernetesOutputService) generate(ctx context.Context) error { s.botAuthClient, id, roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, func(req *proto.UserCertsRequest) { req.KubernetesCluster = kubeClusterName }, @@ -461,10 +462,3 @@ func selectKubeConnectionMethod(proxyPong *proxyPingResponse) ( return "", "", trace.BadParameter("unable to determine kubernetes address") } - -func (s *KubernetesOutputService) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -} diff --git a/lib/tbot/service_kubernetes_v2_output.go b/lib/tbot/service_kubernetes_v2_output.go index d8ccde4a621d4..54563e459529c 100644 --- a/lib/tbot/service_kubernetes_v2_output.go +++ b/lib/tbot/service_kubernetes_v2_output.go @@ -20,6 +20,7 @@ package tbot import ( "bytes" + "cmp" "context" "encoding/base64" "fmt" @@ -78,7 +79,7 @@ func (s *KubernetesV2OutputService) Run(ctx context.Context) error { return trace.Wrap(runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.credentialLifetime().RenewalInterval, + interval: cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -115,7 +116,7 @@ func (s *KubernetesV2OutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { @@ -448,10 +449,3 @@ func generateKubeConfigV2WithoutPlugin(ks *kubernetesStatusV2) (*clientcmdapi.Co return config, nil } - -func (s *KubernetesV2OutputService) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -} diff --git a/lib/tbot/service_spiffe_svid_output.go b/lib/tbot/service_spiffe_svid_output.go index 15ec632e0f829..59a2b53f9452e 100644 --- a/lib/tbot/service_spiffe_svid_output.go +++ b/lib/tbot/service_spiffe_svid_output.go @@ -19,6 +19,7 @@ package tbot import ( + "cmp" "context" "crypto" "crypto/x509" @@ -134,7 +135,7 @@ func (s *SPIFFESVIDOutputService) Run(ctx context.Context) error { privateKey = nil } bundleSet = newBundleSet - case <-time.After(s.credentialLifetime().RenewalInterval): + case <-time.After(cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval): s.log.InfoContext(ctx, "Renewal interval reached, renewing SVIDs") res = nil privateKey = nil @@ -183,7 +184,7 @@ func (s *SPIFFESVIDOutputService) requestSVID( s.botAuthClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { @@ -202,7 +203,7 @@ func (s *SPIFFESVIDOutputService) requestSVID( ctx, impersonatedClient, []config.SVIDRequest{s.cfg.SVID}, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, ) if err != nil { return nil, nil, nil, trace.Wrap(err, "generating X509 SVID") @@ -213,7 +214,7 @@ func (s *SPIFFESVIDOutputService) requestSVID( impersonatedClient, s.cfg.SVID, s.cfg.JWTs, - s.credentialLifetime().TTL) + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL) if err != nil { return nil, nil, nil, trace.Wrap(err, "generating JWT SVIDs") } @@ -401,10 +402,3 @@ func generateSVID( return res, privateKey, nil } - -func (s *SPIFFESVIDOutputService) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -} diff --git a/lib/tbot/service_spiffe_workload_api.go b/lib/tbot/service_spiffe_workload_api.go index ba2379f121f4a..09075eddb2892 100644 --- a/lib/tbot/service_spiffe_workload_api.go +++ b/lib/tbot/service_spiffe_workload_api.go @@ -322,7 +322,7 @@ func (s *SPIFFEWorkloadAPIService) fetchX509SVIDs( ctx, s.client, svidRequests, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, ) if err != nil { return nil, trace.Wrap(err) @@ -645,7 +645,7 @@ func (s *SPIFFEWorkloadAPIService) FetchX509SVID( } bundleSet = newBundleSet continue - case <-time.After(s.credentialLifetime().RenewalInterval): + case <-time.After(cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval): log.DebugContext(ctx, "Renewal interval reached, renewing SVIDs") svids = nil continue @@ -895,10 +895,3 @@ func (s *SPIFFEWorkloadAPIService) ValidateJWTSVID( func (s *SPIFFEWorkloadAPIService) String() string { return fmt.Sprintf("%s:%s", config.SPIFFEWorkloadAPIServiceType, s.cfg.Listen) } - -func (s *SPIFFEWorkloadAPIService) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -} diff --git a/lib/tbot/service_ssh_host_output.go b/lib/tbot/service_ssh_host_output.go index 5369b7f2c9778..5dc0139d3cf58 100644 --- a/lib/tbot/service_ssh_host_output.go +++ b/lib/tbot/service_ssh_host_output.go @@ -19,6 +19,7 @@ package tbot import ( + "cmp" "context" "fmt" "log/slog" @@ -65,7 +66,7 @@ func (s *SSHHostOutputService) Run(ctx context.Context) error { err := runOnInterval(ctx, runOnIntervalConfig{ name: "output-renewal", f: s.generate, - interval: s.credentialLifetime().RenewalInterval, + interval: cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -107,7 +108,7 @@ func (s *SSHHostOutputService) generate(ctx context.Context) error { s.botAuthClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { @@ -143,7 +144,7 @@ func (s *SSHHostOutputService) generate(ctx context.Context) error { Principals: s.cfg.Principals, ClusterName: clusterName, Role: string(types.RoleNode), - Ttl: durationpb.New(s.credentialLifetime().TTL), + Ttl: durationpb.New(cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL), }, ) if err != nil { @@ -226,10 +227,3 @@ func exportSSHUserCAs(cas []types.CertAuthority, localAuthName string) (string, return exported, nil } - -func (s *SSHHostOutputService) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -} diff --git a/lib/tbot/service_ssh_multiplexer.go b/lib/tbot/service_ssh_multiplexer.go index fe5df448c5a40..f5b589026c178 100644 --- a/lib/tbot/service_ssh_multiplexer.go +++ b/lib/tbot/service_ssh_multiplexer.go @@ -21,6 +21,7 @@ package tbot import ( "bufio" "bytes" + "cmp" "context" "crypto/tls" "errors" @@ -345,7 +346,7 @@ func (s *SSHMultiplexerService) generateIdentity(ctx context.Context) (*identity s.botAuthClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { @@ -396,7 +397,7 @@ func (s *SSHMultiplexerService) identityRenewalLoop( s.identity.Set(id) return s.writeArtifacts(ctx, proxyHost, authClient) }, - interval: s.credentialLifetime().RenewalInterval, + interval: cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval, retryLimit: renewalRetryLimit, log: s.log, reloadCh: reloadCh, @@ -865,10 +866,3 @@ func (s *cyclingHostDialClient) DialHost(ctx context.Context, target string, clu wrappedConn.parent.Store(currentClt) return wrappedConn, details, nil } - -func (s *SSHMultiplexerService) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -} diff --git a/lib/tbot/service_workload_identity_api.go b/lib/tbot/service_workload_identity_api.go index 2aec39efc2670..7987abcf1dc35 100644 --- a/lib/tbot/service_workload_identity_api.go +++ b/lib/tbot/service_workload_identity_api.go @@ -17,6 +17,7 @@ package tbot import ( + "cmp" "context" "crypto/x509" "fmt" @@ -350,7 +351,7 @@ func (s *WorkloadIdentityAPIService) FetchX509SVID( } bundleSet = newBundleSet continue - case <-time.After(s.credentialLifetime().RenewalInterval): + case <-time.After(cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval): log.DebugContext(ctx, "Renewal interval reached, renewing SVIDs") svids = nil continue @@ -408,7 +409,7 @@ func (s *WorkloadIdentityAPIService) fetchX509SVIDs( log, s.client, s.cfg.Selector, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, attest, ) if err != nil { @@ -490,7 +491,7 @@ func (s *WorkloadIdentityAPIService) FetchJWTSVID( s.client, s.cfg.Selector, req.Audience, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, attr, ) if err != nil { @@ -660,10 +661,3 @@ func (s *WorkloadIdentityAPIService) ValidateJWTSVID( func (s *WorkloadIdentityAPIService) String() string { return fmt.Sprintf("%s:%s", config.WorkloadIdentityAPIServiceType, s.cfg.Listen) } - -func (s *WorkloadIdentityAPIService) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -} diff --git a/lib/tbot/service_workload_identity_jwt.go b/lib/tbot/service_workload_identity_jwt.go index 959b179e8c72d..22088f8a82c53 100644 --- a/lib/tbot/service_workload_identity_jwt.go +++ b/lib/tbot/service_workload_identity_jwt.go @@ -17,6 +17,7 @@ package tbot import ( + "cmp" "context" "fmt" "log/slog" @@ -111,7 +112,7 @@ func (s *WorkloadIdentityJWTService) Run(ctx context.Context) error { cred = nil } bundleSet = newBundleSet - case <-time.After(s.credentialLifetime().RenewalInterval): + case <-time.After(cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval): s.log.InfoContext(ctx, "Renewal interval reached, renewing SVIDs") cred = nil case <-firstRun: @@ -157,7 +158,7 @@ func (s *WorkloadIdentityJWTService) requestJWTSVID( s.botAuthClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { @@ -178,7 +179,7 @@ func (s *WorkloadIdentityJWTService) requestJWTSVID( impersonatedClient, s.cfg.Selector, s.cfg.Audiences, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { @@ -248,10 +249,3 @@ func (s *WorkloadIdentityJWTService) render( ) return nil } - -func (s *WorkloadIdentityJWTService) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -} diff --git a/lib/tbot/service_workload_identity_x509.go b/lib/tbot/service_workload_identity_x509.go index 76e0e4dcb9f28..667d8208baeba 100644 --- a/lib/tbot/service_workload_identity_x509.go +++ b/lib/tbot/service_workload_identity_x509.go @@ -17,6 +17,7 @@ package tbot import ( + "cmp" "context" "crypto" "crypto/x509" @@ -126,7 +127,7 @@ func (s *WorkloadIdentityX509Service) Run(ctx context.Context) error { privateKey = nil } bundleSet = newBundleSet - case <-time.After(s.credentialLifetime().RenewalInterval): + case <-time.After(cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).RenewalInterval): s.log.InfoContext(ctx, "Renewal interval reached, renewing SVIDs") x509Cred = nil privateKey = nil @@ -174,7 +175,7 @@ func (s *WorkloadIdentityX509Service) requestSVID( s.botAuthClient, s.getBotIdentity(), roles, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { @@ -194,7 +195,7 @@ func (s *WorkloadIdentityX509Service) requestSVID( s.log, impersonatedClient, s.cfg.Selector, - s.credentialLifetime().TTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { @@ -303,10 +304,3 @@ func (s *WorkloadIdentityX509Service) render( ) return nil } - -func (s *WorkloadIdentityX509Service) credentialLifetime() config.CredentialLifetime { - if !s.cfg.CredentialLifetime.IsEmpty() { - return s.cfg.CredentialLifetime - } - return s.botCfg.CredentialLifetime -}