mirror of
https://github.com/siderolabs/talos.git
synced 2025-11-04 18:31:49 +01:00
feat: add RedactSecrets method to v1alpha1.Config
Add a way to strip away the secrets from a config. Signed-off-by: Utku Ozdemir <utku.ozdemir@siderolabs.com>
This commit is contained in:
parent
4c31b9b1a3
commit
cf7adc51c9
@ -19,6 +19,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Provider defines the configuration consumption interface.
|
// Provider defines the configuration consumption interface.
|
||||||
|
//
|
||||||
|
//nolint:interfacebloat
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
// Config parts accessor.
|
// Config parts accessor.
|
||||||
Version() string
|
Version() string
|
||||||
@ -33,6 +35,9 @@ type Provider interface {
|
|||||||
// Bytes returns source YAML representation (if available) or does default encoding.
|
// Bytes returns source YAML representation (if available) or does default encoding.
|
||||||
Bytes() ([]byte, error)
|
Bytes() ([]byte, error)
|
||||||
|
|
||||||
|
// RedactSecrets returns a copy of the Provider with all secrets replaced with the given string.
|
||||||
|
RedactSecrets(string) Provider
|
||||||
|
|
||||||
// Encode configuration to YAML using the provided options.
|
// Encode configuration to YAML using the provided options.
|
||||||
EncodeString(encoderOptions ...encoder.Option) (string, error)
|
EncodeString(encoderOptions ...encoder.Option) (string, error)
|
||||||
EncodeBytes(encoderOptions ...encoder.Option) ([]byte, error)
|
EncodeBytes(encoderOptions ...encoder.Option) ([]byte, error)
|
||||||
|
|||||||
@ -102,6 +102,55 @@ func (c *Config) Bytes() ([]byte, error) {
|
|||||||
return c.EncodeBytes()
|
return c.EncodeBytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RedactSecrets implements the config.Provider interface.
|
||||||
|
func (c *Config) RedactSecrets(replacement string) config.Provider {
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
redactBytes := func(b []byte) []byte {
|
||||||
|
if len(b) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(replacement)
|
||||||
|
}
|
||||||
|
|
||||||
|
redactStr := func(s string) string {
|
||||||
|
return string(redactBytes([]byte(s)))
|
||||||
|
}
|
||||||
|
|
||||||
|
clone := c.DeepCopy()
|
||||||
|
|
||||||
|
if clone.MachineConfig != nil {
|
||||||
|
clone.MachineConfig.MachineToken = redactStr(clone.MachineConfig.MachineToken)
|
||||||
|
if clone.MachineConfig.MachineCA != nil {
|
||||||
|
clone.MachineConfig.MachineCA.Key = redactBytes(clone.MachineConfig.MachineCA.Key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if clone.ClusterConfig != nil {
|
||||||
|
clone.ClusterConfig.ClusterSecret = redactStr(clone.ClusterConfig.ClusterSecret)
|
||||||
|
clone.ClusterConfig.BootstrapToken = redactStr(clone.ClusterConfig.BootstrapToken)
|
||||||
|
clone.ClusterConfig.ClusterAESCBCEncryptionSecret = redactStr(clone.ClusterConfig.ClusterAESCBCEncryptionSecret)
|
||||||
|
clone.ClusterConfig.ClusterSecretboxEncryptionSecret = redactStr(clone.ClusterConfig.ClusterSecretboxEncryptionSecret)
|
||||||
|
|
||||||
|
if clone.ClusterConfig.ClusterCA != nil {
|
||||||
|
clone.ClusterConfig.ClusterCA.Key = redactBytes(clone.ClusterConfig.ClusterCA.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if clone.ClusterConfig.ClusterAggregatorCA != nil {
|
||||||
|
clone.ClusterConfig.ClusterAggregatorCA.Key = redactBytes(clone.ClusterConfig.ClusterAggregatorCA.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if clone.ClusterConfig.EtcdConfig != nil && clone.ClusterConfig.EtcdConfig.RootCA != nil {
|
||||||
|
clone.ClusterConfig.EtcdConfig.RootCA.Key = redactBytes(clone.ClusterConfig.EtcdConfig.RootCA.Key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
// Raw implements the config.Provider interface.
|
// Raw implements the config.Provider interface.
|
||||||
func (c *Config) Raw() interface{} {
|
func (c *Config) Raw() interface{} {
|
||||||
return c
|
return c
|
||||||
|
|||||||
@ -66,6 +66,11 @@ func (r *ReadonlyProvider) Bytes() ([]byte, error) {
|
|||||||
return r.bytes, nil
|
return r.bytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RedactSecrets implements the config.Provider interface.
|
||||||
|
func (r *ReadonlyProvider) RedactSecrets(replacement string) config.Provider {
|
||||||
|
return r.cfg.RedactSecrets(replacement)
|
||||||
|
}
|
||||||
|
|
||||||
// EncodeString implements the config.Provider interface.
|
// EncodeString implements the config.Provider interface.
|
||||||
func (r *ReadonlyProvider) EncodeString(encoderOptions ...encoder.Option) (string, error) {
|
func (r *ReadonlyProvider) EncodeString(encoderOptions ...encoder.Option) (string, error) {
|
||||||
return r.cfg.EncodeString(encoderOptions...)
|
return r.cfg.EncodeString(encoderOptions...)
|
||||||
|
|||||||
58
pkg/machinery/config/types/v1alpha1/v1alpha1_redact_test.go
Normal file
58
pkg/machinery/config/types/v1alpha1/v1alpha1_redact_test.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
package v1alpha1_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/generate"
|
||||||
|
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine"
|
||||||
|
"github.com/siderolabs/talos/pkg/machinery/constants"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRedactSecrets(t *testing.T) {
|
||||||
|
bundle, err := generate.NewSecretsBundle(generate.NewClock())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
input, err := generate.NewInput("test", "https://doesntmatter:6443", constants.DefaultKubernetesVersion, bundle)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
config, err := generate.Config(machine.TypeControlPlane, input)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NotEmpty(t, config.MachineConfig.MachineToken)
|
||||||
|
require.NotEmpty(t, config.MachineConfig.MachineCA.Key)
|
||||||
|
require.NotEmpty(t, config.ClusterConfig.ClusterSecret)
|
||||||
|
require.NotEmpty(t, config.ClusterConfig.BootstrapToken)
|
||||||
|
require.Empty(t, config.ClusterConfig.ClusterAESCBCEncryptionSecret)
|
||||||
|
require.NotEmpty(t, config.ClusterConfig.ClusterSecretboxEncryptionSecret)
|
||||||
|
require.NotEmpty(t, config.ClusterConfig.ClusterCA.Key)
|
||||||
|
require.NotEmpty(t, config.ClusterConfig.EtcdConfig.RootCA.Key)
|
||||||
|
|
||||||
|
replacement := "**.***"
|
||||||
|
|
||||||
|
configBytesBefore, err := config.Bytes()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
redacted := config.RedactSecrets(replacement)
|
||||||
|
|
||||||
|
configBytesAfter, err := config.Bytes()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, string(configBytesBefore), string(configBytesAfter), "original config is modified")
|
||||||
|
|
||||||
|
require.Equal(t, replacement, redacted.Machine().Security().Token())
|
||||||
|
require.Equal(t, replacement, string(redacted.Machine().Security().CA().Key))
|
||||||
|
require.Equal(t, replacement, redacted.Cluster().Secret())
|
||||||
|
require.Equal(t, "***", redacted.Cluster().Token().Secret())
|
||||||
|
require.Equal(t, "", redacted.Cluster().AESCBCEncryptionSecret())
|
||||||
|
require.Equal(t, replacement, redacted.Cluster().SecretboxEncryptionSecret())
|
||||||
|
require.Equal(t, replacement, string(redacted.Cluster().CA().Key))
|
||||||
|
require.Equal(t, replacement, string(redacted.Cluster().Etcd().CA().Key))
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user