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 98f0bb4972d99..37a2f0ec37b8e 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 + +# 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. +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 8d97964dd1ec2..68ac72706eb7a 100644 --- a/docs/pages/reference/machine-id/configuration.mdx +++ b/docs/pages/reference/machine-id/configuration.mdx @@ -43,17 +43,23 @@ 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`. -certificate_ttl: "1h" +# +# It can be overridden for most outputs and services to give them a shorter TTL +# than `tbot`'s internal certificates. +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 +# renewal interval than `tbot`'s internal certificates. renewal_interval: "20m" # oneshot configures `tbot` to exit immediately after generating the outputs. diff --git a/integrations/lib/embeddedtbot/bot_test.go b/integrations/lib/embeddedtbot/bot_test.go index ca4bc9480af43..512c220580cc7 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, + CredentialLifetime: config.CredentialLifetime{ + 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..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.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.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 2aa463cb04f44..5f4b2c15d3d12 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, + CredentialLifetime: tbotconfig.CredentialLifetime{ + 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..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.CertificateTTL) - require.Equal(t, time.Minute*5, cfg.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 0d406a2062fa4..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.CertificateTTL != 0 { + if cfg.CredentialLifetime.TTL != 0 { log.WarnContext( context.TODO(), "CLI parameters are overriding configuration", "flag", "certificate-ttl", - "config_value", cfg.CertificateTTL, + "config_value", cfg.CredentialLifetime.TTL, "cli_value", c.CertificateTTL, ) } - cfg.CertificateTTL = c.CertificateTTL + cfg.CredentialLifetime.TTL = c.CertificateTTL } if c.RenewalInterval != 0 { - if cfg.RenewalInterval != 0 { + if cfg.CredentialLifetime.RenewalInterval != 0 { log.WarnContext( context.TODO(), "CLI parameters are overriding configuration", "flag", "renewal-interval", - "config_value", cfg.RenewalInterval, + "config_value", cfg.CredentialLifetime.RenewalInterval, "cli_value", c.RenewalInterval, ) } - cfg.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 93a40a75b3da1..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.CertificateTTL) - require.Equal(t, time.Minute*5, cfg.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 2e2a07a94020c..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.CertificateTTL != 0 { + if cfg.CredentialLifetime.TTL != 0 { l.WarnContext( context.TODO(), "CLI parameters are overriding configuration", "flag", "certificate-ttl", - "config_value", cfg.CertificateTTL, + "config_value", cfg.CredentialLifetime.TTL, "cli_value", s.CertificateTTL, ) } - cfg.CertificateTTL = s.CertificateTTL + cfg.CredentialLifetime.TTL = s.CertificateTTL } if s.RenewalInterval != 0 { - if cfg.RenewalInterval != 0 { + if cfg.CredentialLifetime.RenewalInterval != 0 { l.WarnContext( context.TODO(), "CLI parameters are overriding configuration", "flag", "renewal-interval", - "config_value", cfg.RenewalInterval, + "config_value", cfg.CredentialLifetime.RenewalInterval, "cli_value", s.RenewalInterval, ) } - cfg.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 549f04497e806..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.CertificateTTL) - require.Equal(t, time.Minute*5, cfg.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 c7f0631fa273d..7b50ae9519074 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" @@ -152,10 +153,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"` + 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 @@ -207,6 +207,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 @@ -226,6 +254,9 @@ func (conf *BotConfig) CheckAndSetDefaults() error { if err := service.CheckAndSetDefaults(); err != nil { return trace.Wrap(err, "validating service[%d]", i) } + if err := service.GetCredentialLifetime().Validate(conf.Oneshot); err != nil { + return trace.Wrap(err, "validating service[%d]", i) + } } destinationPaths := map[string]int{} @@ -259,12 +290,12 @@ func (conf *BotConfig) CheckAndSetDefaults() error { } } - if conf.CertificateTTL == 0 { - conf.CertificateTTL = DefaultCertificateTTL + if conf.CredentialLifetime.TTL == 0 { + conf.CredentialLifetime.TTL = DefaultCertificateTTL } - if conf.RenewalInterval == 0 { - conf.RenewalInterval = DefaultRenewInterval + if conf.CredentialLifetime.RenewalInterval == 0 { + conf.CredentialLifetime.RenewalInterval = DefaultRenewInterval } // We require the join method for `configure` and `start` but not for `init` @@ -291,23 +322,18 @@ 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 + 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. + // + //nolint:sloglint // msg cannot be constant + log.WarnContext(context.TODO(), ttlErr.msg, ttlErr.LogLabels()...) + case err != nil: + return err } return nil @@ -317,6 +343,11 @@ func (conf *BotConfig) CheckAndSetDefaults() error { type ServiceConfig interface { Type() string CheckAndSetDefaults() error + + // 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. + GetCredentialLifetime() CredentialLifetime } // ServiceConfigs assists polymorphic unmarshaling of a slice of ServiceConfigs. @@ -616,3 +647,94 @@ func ReadConfig(reader io.ReadSeeker, manualMigration bool) (*BotConfig, error) return nil, trace.BadParameter("unrecognized config version %q", version.Version) } } + +// 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 CredentialLifetime struct { + TTL time.Duration `yaml:"credential_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 CredentialLifetime) IsEmpty() bool { + return l == CredentialLifetime{} +} + +// Validate checks whether the combination of the fields is valid. +func (l CredentialLifetime) Validate(oneShot bool) error { + if l.IsEmpty() { + return nil + } + + if l.TTL == 0 || l.RenewalInterval == 0 { + return trace.BadParameter("credential_ttl and renewal_interval must both be specified if either is") + } + + if l.TTL < 0 { + return trace.BadParameter("credential_ttl must be positive") + } + + if l.RenewalInterval < 0 { + return trace.BadParameter("renewal_interval must be positive") + } + + if l.TTL < l.RenewalInterval && !oneShot { + 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 { + 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 8bc3138d2ef1c..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" @@ -42,7 +43,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.CredentialLifetime.RenewalInterval) require.NotNil(t, cfg.Onboarding) @@ -197,13 +198,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", + CredentialLifetime: CredentialLifetime{ + TTL: time.Minute, + RenewalInterval: time.Second * 30, + }, Outputs: ServiceConfigs{ &IdentityOutput{ Destination: &DestinationDirectory{ @@ -219,6 +222,10 @@ func TestBotConfig_YAML(t *testing.T) { Destination: &DestinationKubernetesSecret{ Name: "my-secret", }, + CredentialLifetime: CredentialLifetime{ + TTL: 30 * time.Second, + RenewalInterval: 15 * time.Second, + }, }, }, Services: []ServiceConfig{ @@ -250,6 +257,10 @@ func TestBotConfig_YAML(t *testing.T) { }, }, }, + CredentialLifetime: CredentialLifetime{ + TTL: 30 * time.Second, + RenewalInterval: 15 * time.Second, + }, }, &ExampleService{ Message: "llama", @@ -258,11 +269,19 @@ func TestBotConfig_YAML(t *testing.T) { Destination: &DestinationDirectory{ Path: "/bot/output", }, + CredentialLifetime: CredentialLifetime{ + TTL: 30 * time.Second, + RenewalInterval: 15 * time.Second, + }, }, &ApplicationTunnelService{ Listen: "tcp://127.0.0.1:123", Roles: []string{"access"}, AppName: "my-app", + CredentialLifetime: CredentialLifetime{ + TTL: 30 * time.Second, + RenewalInterval: 15 * time.Second, + }, }, &WorkloadIdentityX509Service{ Destination: &DestinationDirectory{ @@ -271,12 +290,20 @@ func TestBotConfig_YAML(t *testing.T) { Selector: WorkloadIdentitySelector{ Name: "my-workload-identity", }, + CredentialLifetime: CredentialLifetime{ + TTL: 30 * time.Second, + RenewalInterval: 15 * time.Second, + }, }, &WorkloadIdentityAPIService{ Listen: "tcp://127.0.0.1:123", Selector: WorkloadIdentitySelector{ Name: "my-workload-identity", }, + CredentialLifetime: CredentialLifetime{ + TTL: 30 * time.Second, + RenewalInterval: 15 * time.Second, + }, }, &WorkloadIdentityJWTService{ Destination: &DestinationDirectory{ @@ -293,10 +320,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", + CredentialLifetime: CredentialLifetime{ + TTL: time.Minute, + RenewalInterval: time.Second * 30, + }, Outputs: ServiceConfigs{ &IdentityOutput{ Destination: &DestinationMemory{}, @@ -307,10 +336,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", + CredentialLifetime: CredentialLifetime{ + TTL: time.Minute, + RenewalInterval: time.Second * 30, + }, Outputs: ServiceConfigs{ &IdentityOutput{ Destination: &DestinationMemory{}, @@ -388,3 +419,101 @@ func TestBotConfig_WithCAPathAndCAPins(t *testing.T) { require.ErrorContains(t, cfg.CheckAndSetDefaults(), "mutually exclusive") } + +func TestBotConfig_ServicePartialCredentialLifetime(t *testing.T) { + cfg := &BotConfig{ + Version: V2, + AuthServer: "example.teleport.sh:443", + Services: []ServiceConfig{ + &IdentityOutput{ + CredentialLifetime: CredentialLifetime{TTL: 5 * time.Minute}, + Destination: &DestinationMemory{}, + }, + }, + } + require.ErrorContains(t, cfg.CheckAndSetDefaults(), "credential_ttl and renewal_interval") +} + +func TestBotConfig_ServiceInvalidCredentialLifetime(t *testing.T) { + cfg := &BotConfig{ + Version: V2, + AuthServer: "example.teleport.sh:443", + Services: []ServiceConfig{ + &IdentityOutput{ + CredentialLifetime: CredentialLifetime{TTL: 5 * time.Minute}, + Destination: &DestinationMemory{}, + }, + }, + } + 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) { + testCases := map[string]struct { + cfg CredentialLifetime + oneShot bool + error string + }{ + "partial config": { + cfg: CredentialLifetime{TTL: 1 * time.Minute}, + error: "credential_ttl and renewal_interval must both be specified if either is", + }, + "negative TTL": { + cfg: CredentialLifetime{TTL: -time.Minute, RenewalInterval: time.Minute}, + error: "credential_ttl must be positive", + }, + "negative renewal interval": { + 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) { + 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/migrate.go b/lib/tbot/config/migrate.go index dcf2c3170e215..2db890bd8d712 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, + CredentialLifetime: CredentialLifetime{ + 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..db87a895b2e38 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, + CredentialLifetime: CredentialLifetime{ + 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, + CredentialLifetime: CredentialLifetime{ + 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/config/service_application.go b/lib/tbot/config/service_application.go index b5d65892b4a46..cd4148d702910 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"` + + // CredentialLifetime contains configuration for how long credentials will + // last and the frequency at which they'll be renewed. + CredentialLifetime CredentialLifetime `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) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime +} 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.go b/lib/tbot/config/service_application_tunnel.go index 1f6e649ebd14a..ede5b1a4ac44f 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"` + // CredentialLifetime contains configuration for how long credentials will + // last and the frequency at which they'll be renewed. + CredentialLifetime CredentialLifetime `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) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime +} 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_client_credential.go b/lib/tbot/config/service_client_credential.go index e5c58adb63980..f685aa7100c99 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) GetCredentialLifetime() CredentialLifetime { + return CredentialLifetime{} +} diff --git a/lib/tbot/config/service_database.go b/lib/tbot/config/service_database.go index 764f5364c07cd..205e5df49f3c7 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"` + + // CredentialLifetime contains configuration for how long credentials will + // last and the frequency at which they'll be renewed. + CredentialLifetime CredentialLifetime `yaml:",inline"` } func (o *DatabaseOutput) Init(ctx context.Context) error { @@ -197,6 +201,10 @@ func (o *DatabaseOutput) Type() string { return DatabaseOutputType } +func (o *DatabaseOutput) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime +} + // SupportedDatabaseFormatStrings returns a constant list of all valid // DatabaseFormat values as strings. func SupportedDatabaseFormatStrings() (ret []string) { 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.go b/lib/tbot/config/service_database_tunnel.go index be035a5091ff4..0e68563980a8e 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"` + // CredentialLifetime contains configuration for how long credentials will + // last and the frequency at which they'll be renewed. + CredentialLifetime CredentialLifetime `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) GetCredentialLifetime() CredentialLifetime { + return s.CredentialLifetime +} 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_example.go b/lib/tbot/config/service_example.go index 471b53bf5c1cd..7a09dd38b9cbd 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) GetCredentialLifetime() CredentialLifetime { + return CredentialLifetime{} +} diff --git a/lib/tbot/config/service_identity.go b/lib/tbot/config/service_identity.go index 686b5e7c66c6f..8d51fd43564db 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"` + + // CredentialLifetime contains configuration for how long credentials will + // last and the frequency at which they'll be renewed. + CredentialLifetime CredentialLifetime `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) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime +} 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.go b/lib/tbot/config/service_kubernetes.go index 27b3431681b72..09a7572bba49a 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"` + + // CredentialLifetime contains configuration for how long credentials will + // last and the frequency at which they'll be renewed. + CredentialLifetime CredentialLifetime `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) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime +} 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.go b/lib/tbot/config/service_kubernetes_v2.go index f5e4915e9dd84..eb0b651dd6ce2 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"` + + // CredentialLifetime contains configuration for how long credentials will + // last and the frequency at which they'll be renewed. + CredentialLifetime CredentialLifetime `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) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime +} 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.go b/lib/tbot/config/service_spiffe_svid.go index c72928608804d..b2c145f1e478b 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"` + + // 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. @@ -194,3 +198,7 @@ func (o *SPIFFESVIDOutput) UnmarshalYAML(node *yaml.Node) error { o.Destination = dest return nil } + +func (o *SPIFFESVIDOutput) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime +} 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.go b/lib/tbot/config/service_spiffe_workload_api.go index 799da41ebb9ef..c5e0917bf0666 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"` + + // CredentialLifetime contains configuration for how long X.509 SVIDs will + // last and the frequency at which they'll be renewed. + CredentialLifetime CredentialLifetime `yaml:",inline"` } func (s *SPIFFEWorkloadAPIService) Type() string { @@ -163,3 +167,7 @@ func (s *SPIFFEWorkloadAPIService) CheckAndSetDefaults() error { } return nil } + +func (o *SPIFFEWorkloadAPIService) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime +} 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.go b/lib/tbot/config/service_ssh_host.go index 813046d971e49..7729cfc0a8c06 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"` + + // CredentialLifetime contains configuration for how long credentials will + // last and the frequency at which they'll be renewed. + CredentialLifetime CredentialLifetime `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) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime +} 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.go b/lib/tbot/config/service_ssh_multiplexer.go index 11b7093f1f25c..3d538647518cc 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"` + + // CredentialLifetime contains configuration for how long credentials will + // last and the frequency at which they'll be renewed. + CredentialLifetime CredentialLifetime `yaml:",inline"` } func (s *SSHMultiplexerService) SessionResumptionEnabled() bool { @@ -93,3 +97,7 @@ func (s *SSHMultiplexerService) CheckAndSetDefaults() error { } return nil } + +func (o *SSHMultiplexerService) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime +} 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.go b/lib/tbot/config/service_workload_identity_api.go index 2c9d056868d25..11ed061a04349 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"` + + // CredentialLifetime contains configuration for how long X.509 SVIDs will + // last and the frequency at which they'll be renewed. + CredentialLifetime CredentialLifetime `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) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime +} 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_jwt.go b/lib/tbot/config/service_workload_identity_jwt.go index 4c71dace4bcee..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. @@ -104,3 +108,7 @@ func (o *WorkloadIdentityJWTService) UnmarshalYAML(node *yaml.Node) error { func (o *WorkloadIdentityJWTService) GetDestination() bot.Destination { return o.Destination } + +func (o *WorkloadIdentityJWTService) GetCredentialLifetime() 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/service_workload_identity_x509.go b/lib/tbot/config/service_workload_identity_x509.go index adff17f991eee..d5055585e9fc8 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"` + + // 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. @@ -134,3 +138,7 @@ func (o *WorkloadIdentityX509Service) UnmarshalYAML(node *yaml.Node) error { o.Destination = dest return nil } + +func (o *WorkloadIdentityX509Service) GetCredentialLifetime() CredentialLifetime { + return o.CredentialLifetime +} 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/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 79bfdb3b4223f..958e2ccaf8ce1 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 + credential_ttl: 30s + renewal_interval: 15s services: - type: spiffe-workload-api listen: unix:///var/run/spiffe.sock @@ -42,6 +44,8 @@ services: attestors: kubernetes: enabled: false + credential_ttl: 30s + renewal_interval: 15s - type: example message: llama - type: ssh-multiplexer @@ -50,17 +54,23 @@ services: path: /bot/output enable_resumption: null proxy_templates_path: "" + credential_ttl: 30s + renewal_interval: 15s - type: application-tunnel listen: tcp://127.0.0.1:123 roles: - access app_name: my-app + credential_ttl: 30s + renewal_interval: 15s - type: workload-identity-x509 selector: name: my-workload-identity destination: type: directory path: /an/output/path + credential_ttl: 30s + renewal_interval: 15s - type: workload-identity-api listen: tcp://127.0.0.1:123 attestors: @@ -68,6 +78,8 @@ services: enabled: false selector: name: my-workload-identity + credential_ttl: 30s + renewal_interval: 15s - type: workload-identity-jwt selector: name: my-workload-identity @@ -79,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/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/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/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/service_application_output.go b/lib/tbot/service_application_output.go index 75b01bc646672..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.botCfg.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.botCfg.CertificateTTL, + 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.botCfg.CertificateTTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).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..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.botCfg.CertificateTTL, + 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.botCfg.CertificateTTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).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..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.CertificateTTL, - "interval", s.cfg.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.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.CertificateTTL, + 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.CertificateTTL) + 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 03583874bb4cf..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.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.CertificateTTL, + 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 12bcf1b8ef4de..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.botCfg.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.botCfg.CertificateTTL, + 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.botCfg.CertificateTTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).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..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.botCfg.CertificateTTL, + 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.botCfg.CertificateTTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).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..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.botCfg.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.botCfg.CertificateTTL, + 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.botCfg.CertificateTTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).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..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.botCfg.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.botCfg.CertificateTTL, + 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.botCfg.CertificateTTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).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..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.botCfg.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.botCfg.CertificateTTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).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..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.botCfg.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.botCfg.CertificateTTL, + 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.botCfg.CertificateTTL, + 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.botCfg.CertificateTTL) + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).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..09075eddb2892 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.CertificateTTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).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.RenewalInterval): + case <-time.After(cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).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..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.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.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 da52f683140b9..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,9 @@ func TestSDS_FetchSecrets(t *testing.T) { }, } botConfig := &config.BotConfig{ - RenewalInterval: time.Minute, + CredentialLifetime: config.CredentialLifetime{ + 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..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.botCfg.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.botCfg.CertificateTTL, + 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.botCfg.CertificateTTL), + Ttl: durationpb.New(cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL), }, ) if err != nil { diff --git a/lib/tbot/service_ssh_multiplexer.go b/lib/tbot/service_ssh_multiplexer.go index 490633f7ca4d2..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.botCfg.CertificateTTL, + 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.botCfg.RenewalInterval, + interval: cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).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..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.botCfg.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.botCfg.CertificateTTL, + 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.botCfg.CertificateTTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).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..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.botCfg.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.botCfg.CertificateTTL, + 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.botCfg.CertificateTTL, + cmp.Or(s.cfg.CredentialLifetime, 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 0ca146dc0b3d4..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.botCfg.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.botCfg.CertificateTTL, + 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.botCfg.CertificateTTL, + cmp.Or(s.cfg.CredentialLifetime, s.botCfg.CredentialLifetime).TTL, nil, ) if err != nil { 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 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 diff --git a/tool/tctl/common/terraform_command.go b/tool/tctl/common/terraform_command.go index 90b2a2241f941..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}, - CertificateTTL: 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,