Skip to content

Commit

Permalink
Hide secretes on the /config endpoint. (grafana#2176)
Browse files Browse the repository at this point in the history
* Hide passwords in URLs from flags.
* Add secret flag handler that hides the value of the secret when marshalled to YAML.
* Use flagext.Secret for Azure, GCP, Redis, Cassandra secrets and block storage config.
* Teach doc generator how to handle flagext.Secret.

Signed-off-by: Tom Wilkie <tom@grafana.com>
  • Loading branch information
tomwilkie authored Feb 25, 2020
1 parent 5dc7611 commit 547efd2
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 30 deletions.
25 changes: 13 additions & 12 deletions azure/blob_storage_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,31 @@ import (
"github.com/Azure/azure-storage-blob-go/azblob"

"github.com/cortexproject/cortex/pkg/chunk"
"github.com/cortexproject/cortex/pkg/util/flagext"
)

const blobURLFmt = "https://%s.blob.core.windows.net/%s/%s"
const containerURLFmt = "https://%s.blob.core.windows.net/%s"

// BlobStorageConfig defines the configurable flags that can be defined when using azure blob storage.
type BlobStorageConfig struct {
ContainerName string `yaml:"container_name"`
AccountName string `yaml:"account_name"`
AccountKey string `yaml:"account_key"`
DownloadBufferSize int `yaml:"download_buffer_size"`
UploadBufferSize int `yaml:"upload_buffer_size"`
UploadBufferCount int `yaml:"upload_buffer_count"`
RequestTimeout time.Duration `yaml:"request_timeout"`
MaxRetries int `yaml:"max_retries"`
MinRetryDelay time.Duration `yaml:"min_retry_delay"`
MaxRetryDelay time.Duration `yaml:"max_retry_delay"`
ContainerName string `yaml:"container_name"`
AccountName string `yaml:"account_name"`
AccountKey flagext.Secret `yaml:"account_key"`
DownloadBufferSize int `yaml:"download_buffer_size"`
UploadBufferSize int `yaml:"upload_buffer_size"`
UploadBufferCount int `yaml:"upload_buffer_count"`
RequestTimeout time.Duration `yaml:"request_timeout"`
MaxRetries int `yaml:"max_retries"`
MinRetryDelay time.Duration `yaml:"min_retry_delay"`
MaxRetryDelay time.Duration `yaml:"max_retry_delay"`
}

// RegisterFlags adds the flags required to config this to the given FlagSet
func (c *BlobStorageConfig) RegisterFlags(f *flag.FlagSet) {
f.StringVar(&c.ContainerName, "azure.container-name", "cortex", "Name of the blob container used to store chunks. Defaults to `cortex`. This container must be created before running cortex.")
f.StringVar(&c.AccountName, "azure.account-name", "", "The Microsoft Azure account name to be used")
f.StringVar(&c.AccountKey, "azure.account-key", "", "The Microsoft Azure account key to use.")
f.Var(&c.AccountKey, "azure.account-key", "The Microsoft Azure account key to use.")
f.DurationVar(&c.RequestTimeout, "azure.request-timeout", 30*time.Second, "Timeout for requests made against azure blob storage. Defaults to 30 seconds.")
f.IntVar(&c.DownloadBufferSize, "azure.download-buffer-size", 512000, "Preallocated buffer size for downloads (default is 512KB)")
f.IntVar(&c.UploadBufferSize, "azure.upload-buffer-size", 256000, "Preallocated buffer size for up;oads (default is 256KB)")
Expand Down Expand Up @@ -139,7 +140,7 @@ func (b *BlobStorage) buildContainerURL() (azblob.ContainerURL, error) {
}

func (b *BlobStorage) newPipeline() (pipeline.Pipeline, error) {
credential, err := azblob.NewSharedKeyCredential(b.cfg.AccountName, b.cfg.AccountKey)
credential, err := azblob.NewSharedKeyCredential(b.cfg.AccountName, b.cfg.AccountKey.Value)
if err != nil {
return nil, err
}
Expand Down
21 changes: 11 additions & 10 deletions cache/redis_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/gomodule/redigo/redis"

"github.com/cortexproject/cortex/pkg/util"
"github.com/cortexproject/cortex/pkg/util/flagext"
)

// RedisCache type caches chunks in redis
Expand All @@ -21,13 +22,13 @@ type RedisCache struct {

// RedisConfig defines how a RedisCache should be constructed.
type RedisConfig struct {
Endpoint string `yaml:"endpoint,omitempty"`
Timeout time.Duration `yaml:"timeout,omitempty"`
Expiration time.Duration `yaml:"expiration,omitempty"`
MaxIdleConns int `yaml:"max_idle_conns,omitempty"`
MaxActiveConns int `yaml:"max_active_conns,omitempty"`
Password string `yaml:"password"`
EnableTLS bool `yaml:"enable_tls"`
Endpoint string `yaml:"endpoint,omitempty"`
Timeout time.Duration `yaml:"timeout,omitempty"`
Expiration time.Duration `yaml:"expiration,omitempty"`
MaxIdleConns int `yaml:"max_idle_conns,omitempty"`
MaxActiveConns int `yaml:"max_active_conns,omitempty"`
Password flagext.Secret `yaml:"password"`
EnableTLS bool `yaml:"enable_tls"`
}

// RegisterFlagsWithPrefix adds the flags required to config this to the given FlagSet
Expand All @@ -37,7 +38,7 @@ func (cfg *RedisConfig) RegisterFlagsWithPrefix(prefix, description string, f *f
f.DurationVar(&cfg.Expiration, prefix+"redis.expiration", 0, description+"How long keys stay in the redis.")
f.IntVar(&cfg.MaxIdleConns, prefix+"redis.max-idle-conns", 80, description+"Maximum number of idle connections in pool.")
f.IntVar(&cfg.MaxActiveConns, prefix+"redis.max-active-conns", 0, description+"Maximum number of active connections in pool.")
f.StringVar(&cfg.Password, prefix+"redis.password", "", description+"Password to use when connecting to redis.")
f.Var(&cfg.Password, prefix+"redis.password", description+"Password to use when connecting to redis.")
f.BoolVar(&cfg.EnableTLS, prefix+"redis.enable-tls", false, description+"Enables connecting to redis with TLS.")
}

Expand All @@ -53,8 +54,8 @@ func NewRedisCache(cfg RedisConfig, name string, pool *redis.Pool) *RedisCache {
if cfg.EnableTLS {
options = append(options, redis.DialUseTLS(true))
}
if cfg.Password != "" {
options = append(options, redis.DialPassword(cfg.Password))
if cfg.Password.Value != "" {
options = append(options, redis.DialPassword(cfg.Password.Value))
}

c, err := redis.Dial("tcp", cfg.Endpoint, options...)
Expand Down
8 changes: 4 additions & 4 deletions cassandra/storage_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type Config struct {
CAPath string `yaml:"CA_path,omitempty"`
Auth bool `yaml:"auth,omitempty"`
Username string `yaml:"username,omitempty"`
Password string `yaml:"password,omitempty"`
Password flagext.Secret `yaml:"password,omitempty"`
PasswordFile string `yaml:"password_file,omitempty"`
CustomAuthenticators flagext.StringSlice `yaml:"custom_authenticators"`
Timeout time.Duration `yaml:"timeout,omitempty"`
Expand All @@ -53,7 +53,7 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) {
f.StringVar(&cfg.CAPath, "cassandra.ca-path", "", "Path to certificate file to verify the peer.")
f.BoolVar(&cfg.Auth, "cassandra.auth", false, "Enable password authentication when connecting to cassandra.")
f.StringVar(&cfg.Username, "cassandra.username", "", "Username to use when connecting to cassandra.")
f.StringVar(&cfg.Password, "cassandra.password", "", "Password to use when connecting to cassandra.")
f.Var(&cfg.Password, "cassandra.password", "Password to use when connecting to cassandra.")
f.StringVar(&cfg.PasswordFile, "cassandra.password-file", "", "File containing password to use when connecting to cassandra.")
f.Var(&cfg.CustomAuthenticators, "cassandra.custom-authenticator", "If set, when authenticating with cassandra a custom authenticator will be expected during the handshake. This flag can be set multiple times.")
f.DurationVar(&cfg.Timeout, "cassandra.timeout", 2*time.Second, "Timeout when connecting to cassandra.")
Expand All @@ -64,7 +64,7 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) {
}

func (cfg *Config) Validate() error {
if cfg.Password != "" && cfg.PasswordFile != "" {
if cfg.Password.Value != "" && cfg.PasswordFile != "" {
return errors.Errorf("The password and password_file config options are mutually exclusive.")
}
return nil
Expand Down Expand Up @@ -123,7 +123,7 @@ func (cfg *Config) setClusterConfig(cluster *gocql.ClusterConfig) error {
}
}
if cfg.Auth {
password := cfg.Password
password := cfg.Password.Value
if cfg.PasswordFile != "" {
passwordBytes, err := ioutil.ReadFile(cfg.PasswordFile)
if err != nil {
Expand Down
9 changes: 5 additions & 4 deletions cassandra/storage_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package cassandra
import (
"testing"

"github.com/stretchr/testify/require"

"github.com/gocql/gocql"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/cortexproject/cortex/pkg/util/flagext"
)

func TestConfig_setClusterConfig_noAuth(t *testing.T) {
Expand All @@ -26,7 +27,7 @@ func TestConfig_setClusterConfig_authWithPassword(t *testing.T) {
cfg := Config{
Auth: true,
Username: "user",
Password: "pass",
Password: flagext.Secret{Value: "pass"},
}
require.NoError(t, cfg.Validate())

Expand Down Expand Up @@ -73,7 +74,7 @@ func TestConfig_setClusterConfig_authWithPasswordAndPasswordFile(t *testing.T) {
cfg := Config{
Auth: true,
Username: "user",
Password: "pass",
Password: flagext.Secret{Value: "pass"},
PasswordFile: "testdata/password-with-trailing-newline.txt",
}
assert.Error(t, cfg.Validate())
Expand Down

0 comments on commit 547efd2

Please sign in to comment.