diff --git a/configuration/configuration.go b/configuration/configuration.go index 6a0af0af9..beec7f89b 100644 --- a/configuration/configuration.go +++ b/configuration/configuration.go @@ -174,6 +174,9 @@ type Configuration struct { // Addr specifies the the redis instance available to the application. 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 `yaml:"password,omitempty"` diff --git a/configuration/configuration_test.go b/configuration/configuration_test.go index 24cd680d8..064bae4ac 100644 --- a/configuration/configuration_test.go +++ b/configuration/configuration_test.go @@ -131,6 +131,40 @@ var configStruct = Configuration{ 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 @@ -175,6 +209,18 @@ http: - /path/to/ca.pem headers: 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 @@ -242,6 +288,23 @@ func (suite *ConfigSuite) TestParseInmemory(c *check.C) { suite.expectedConfig.Storage = Storage{"inmemory": Parameters{}} suite.expectedConfig.Reporting = Reporting{} 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))) c.Assert(err, check.IsNil) @@ -262,6 +325,23 @@ func (suite *ConfigSuite) TestParseIncomplete(c *check.C) { suite.expectedConfig.Reporting = Reporting{} suite.expectedConfig.Notifications = Notifications{} 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 // REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY can be used together @@ -555,5 +635,7 @@ func copyConfig(config Configuration) *Configuration { configCopy.HTTP.Headers[k] = v } + configCopy.Redis = config.Redis + return configCopy } diff --git a/registry/handlers/app.go b/registry/handlers/app.go index cdcb326fc..4567f27c0 100644 --- a/registry/handlers/app.go +++ b/registry/handlers/app.go @@ -546,8 +546,16 @@ func (app *App) configureRedis(configuration *configuration.Configuration) { } // authorize the connection + authArgs := make([]interface{}, 0, 2) + if configuration.Redis.Username != "" { + authArgs = append(authArgs, configuration.Redis.Username) + } 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() done(err) return nil, err