feat: added support for redis username configuration

Redis introduced an Access Control List (ACL) mechanism since version 6.0. This commit implements the necessary changes to support configuring the username for Redis. Users can now define a specific username to authenticate with Redis and enhance security through the ACL feature.

Signed-off-by: chlins <chenyuzh@vmware.com>
This commit is contained in:
chlins 2023-08-04 15:04:43 +08:00
parent 807a836852
commit 32a476b840
3 changed files with 94 additions and 1 deletions

View file

@ -174,6 +174,9 @@ type Configuration struct {
// Addr specifies the the redis instance available to the application. // Addr specifies the the redis instance available to the application.
Addr string `yaml:"addr,omitempty"` Addr string `yaml:"addr,omitempty"`
// Usernames can be used as a finer-grained permission control since the introduction of the redis 6.0.
Username string `yaml:"username,omitempty"`
// Password string to use when making a connection. // Password string to use when making a connection.
Password string `yaml:"password,omitempty"` Password string `yaml:"password,omitempty"`

View file

@ -131,6 +131,40 @@ var configStruct = Configuration{
Disabled: false, Disabled: false,
}, },
}, },
Redis: struct {
Addr string `yaml:"addr,omitempty"`
Username string `yaml:"username,omitempty"`
Password string `yaml:"password,omitempty"`
DB int `yaml:"db,omitempty"`
TLS struct {
Enabled bool `yaml:"enabled,omitempty"`
} `yaml:"tls,omitempty"`
DialTimeout time.Duration `yaml:"dialtimeout,omitempty"`
ReadTimeout time.Duration `yaml:"readtimeout,omitempty"`
WriteTimeout time.Duration `yaml:"writetimeout,omitempty"`
Pool struct {
MaxIdle int `yaml:"maxidle,omitempty"`
MaxActive int `yaml:"maxactive,omitempty"`
IdleTimeout time.Duration `yaml:"idletimeout,omitempty"`
} `yaml:"pool,omitempty"`
}{
Addr: "localhost:6379",
Username: "alice",
Password: "123456",
DB: 1,
Pool: struct {
MaxIdle int `yaml:"maxidle,omitempty"`
MaxActive int `yaml:"maxactive,omitempty"`
IdleTimeout time.Duration `yaml:"idletimeout,omitempty"`
}{
MaxIdle: 16,
MaxActive: 64,
IdleTimeout: time.Second * 300,
},
DialTimeout: time.Millisecond * 10,
ReadTimeout: time.Millisecond * 10,
WriteTimeout: time.Millisecond * 10,
},
} }
// configYamlV0_1 is a Version 0.1 yaml document representing configStruct // configYamlV0_1 is a Version 0.1 yaml document representing configStruct
@ -175,6 +209,18 @@ http:
- /path/to/ca.pem - /path/to/ca.pem
headers: headers:
X-Content-Type-Options: [nosniff] X-Content-Type-Options: [nosniff]
redis:
addr: localhost:6379
username: alice
password: 123456
db: 1
pool:
maxidle: 16
maxactive: 64
idletimeout: 300s
dialtimeout: 10ms
readtimeout: 10ms
writetimeout: 10ms
` `
// inmemoryConfigYamlV0_1 is a Version 0.1 yaml document specifying an inmemory // inmemoryConfigYamlV0_1 is a Version 0.1 yaml document specifying an inmemory
@ -242,6 +288,23 @@ func (suite *ConfigSuite) TestParseInmemory(c *check.C) {
suite.expectedConfig.Storage = Storage{"inmemory": Parameters{}} suite.expectedConfig.Storage = Storage{"inmemory": Parameters{}}
suite.expectedConfig.Reporting = Reporting{} suite.expectedConfig.Reporting = Reporting{}
suite.expectedConfig.Log.Fields = nil suite.expectedConfig.Log.Fields = nil
suite.expectedConfig.Redis = struct {
Addr string `yaml:"addr,omitempty"`
Username string `yaml:"username,omitempty"`
Password string `yaml:"password,omitempty"`
DB int `yaml:"db,omitempty"`
TLS struct {
Enabled bool `yaml:"enabled,omitempty"`
} `yaml:"tls,omitempty"`
DialTimeout time.Duration `yaml:"dialtimeout,omitempty"`
ReadTimeout time.Duration `yaml:"readtimeout,omitempty"`
WriteTimeout time.Duration `yaml:"writetimeout,omitempty"`
Pool struct {
MaxIdle int `yaml:"maxidle,omitempty"`
MaxActive int `yaml:"maxactive,omitempty"`
IdleTimeout time.Duration `yaml:"idletimeout,omitempty"`
} `yaml:"pool,omitempty"`
}{}
config, err := Parse(bytes.NewReader([]byte(inmemoryConfigYamlV0_1))) config, err := Parse(bytes.NewReader([]byte(inmemoryConfigYamlV0_1)))
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
@ -262,6 +325,23 @@ func (suite *ConfigSuite) TestParseIncomplete(c *check.C) {
suite.expectedConfig.Reporting = Reporting{} suite.expectedConfig.Reporting = Reporting{}
suite.expectedConfig.Notifications = Notifications{} suite.expectedConfig.Notifications = Notifications{}
suite.expectedConfig.HTTP.Headers = nil suite.expectedConfig.HTTP.Headers = nil
suite.expectedConfig.Redis = struct {
Addr string `yaml:"addr,omitempty"`
Username string `yaml:"username,omitempty"`
Password string `yaml:"password,omitempty"`
DB int `yaml:"db,omitempty"`
TLS struct {
Enabled bool `yaml:"enabled,omitempty"`
} `yaml:"tls,omitempty"`
DialTimeout time.Duration `yaml:"dialtimeout,omitempty"`
ReadTimeout time.Duration `yaml:"readtimeout,omitempty"`
WriteTimeout time.Duration `yaml:"writetimeout,omitempty"`
Pool struct {
MaxIdle int `yaml:"maxidle,omitempty"`
MaxActive int `yaml:"maxactive,omitempty"`
IdleTimeout time.Duration `yaml:"idletimeout,omitempty"`
} `yaml:"pool,omitempty"`
}{}
// Note: this also tests that REGISTRY_STORAGE and // Note: this also tests that REGISTRY_STORAGE and
// REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY can be used together // REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY can be used together
@ -555,5 +635,7 @@ func copyConfig(config Configuration) *Configuration {
configCopy.HTTP.Headers[k] = v configCopy.HTTP.Headers[k] = v
} }
configCopy.Redis = config.Redis
return configCopy return configCopy
} }

View file

@ -546,8 +546,16 @@ func (app *App) configureRedis(configuration *configuration.Configuration) {
} }
// authorize the connection // authorize the connection
authArgs := make([]interface{}, 0, 2)
if configuration.Redis.Username != "" {
authArgs = append(authArgs, configuration.Redis.Username)
}
if configuration.Redis.Password != "" { if configuration.Redis.Password != "" {
if _, err = conn.Do("AUTH", configuration.Redis.Password); err != nil { authArgs = append(authArgs, configuration.Redis.Password)
}
if len(authArgs) > 0 {
if _, err = conn.Do("AUTH", authArgs...); err != nil {
defer conn.Close() defer conn.Close()
done(err) done(err)
return nil, err return nil, err