[Identity-based Authorization] Add an option to specify a global policy for all repositories

using regex.

Signed-off-by: Petu Eusebiu <peusebiu@cisco.com>
This commit is contained in:
Petu Eusebiu
2021-09-10 18:23:26 +03:00
committed by Ramkumar Chinchani
parent 3177f87403
commit 4f825a5e2f
8 changed files with 332 additions and 101 deletions
+54 -34
View File
@@ -186,25 +186,7 @@ func NewRootCmd() *cobra.Command {
return rootCmd
}
func LoadConfiguration(config *config.Config, configPath string) {
viper.SetConfigFile(configPath)
if err := viper.ReadInConfig(); err != nil {
log.Error().Err(err).Msg("error while reading configuration")
panic(err)
}
metaData := &mapstructure.Metadata{}
if err := viper.Unmarshal(&config, metadataConfig(metaData)); err != nil {
log.Error().Err(err).Msg("error while unmarshalling new config")
panic(err)
}
if len(metaData.Keys) == 0 || len(metaData.Unused) > 0 {
log.Error().Err(errors.ErrBadConfig).Msg("bad configuration, retry writing it")
panic(errors.ErrBadConfig)
}
func validateConfiguration(config *config.Config) {
// check authorization config, it should have basic auth enabled or ldap
if config.HTTP.RawAccessControl != nil {
if config.HTTP.Auth == nil || (config.HTTP.Auth.HTPasswd.Path == "" && config.HTTP.Auth.LDAP == nil) {
@@ -228,14 +210,14 @@ func LoadConfiguration(config *config.Config, configPath string) {
}
}
// check glob patterns in sync are compilable
// check glob patterns in sync config are compilable
if config.Extensions != nil && config.Extensions.Sync != nil {
for _, regCfg := range config.Extensions.Sync.Registries {
if regCfg.Content != nil {
for _, content := range regCfg.Content {
ok := glob.ValidatePattern(content.Prefix)
if !ok {
log.Error().Err(glob.ErrBadPattern).Str("pattern", content.Prefix).Msg("pattern could not be compiled")
log.Error().Err(glob.ErrBadPattern).Str("pattern", content.Prefix).Msg("sync pattern could not be compiled")
panic(errors.ErrBadConfig)
}
}
@@ -260,19 +242,57 @@ func LoadConfiguration(config *config.Config, configPath string) {
}
}
err := config.LoadAccessControlConfig()
if err != nil {
log.Error().Err(errors.ErrBadConfig).Msg("unable to unmarshal http.accessControl.key.policies")
panic(err)
}
// defaults
defualtTLSVerify := true
if config.Extensions != nil && config.Extensions.Sync != nil {
for id, regCfg := range config.Extensions.Sync.Registries {
if regCfg.TLSVerify == nil {
config.Extensions.Sync.Registries[id].TLSVerify = &defualtTLSVerify
// check glob patterns in authz config are compilable
if config.AccessControl != nil {
for pattern := range config.AccessControl.Repositories {
ok := glob.ValidatePattern(pattern)
if !ok {
log.Error().Err(glob.ErrBadPattern).Str("pattern", pattern).Msg("authorization pattern could not be compiled")
panic(errors.ErrBadConfig)
}
}
}
}
func LoadConfiguration(config *config.Config, configPath string) {
// Default is dot (.) but because we allow glob patterns in authz
// we need another key delimiter.
viperInstance := viper.NewWithOptions(viper.KeyDelimiter("::"))
viperInstance.SetConfigFile(configPath)
if err := viperInstance.ReadInConfig(); err != nil {
log.Error().Err(err).Msg("error while reading configuration")
panic(err)
}
metaData := &mapstructure.Metadata{}
if err := viperInstance.Unmarshal(&config, metadataConfig(metaData)); err != nil {
log.Error().Err(err).Msg("error while unmarshalling new config")
panic(err)
}
if len(metaData.Keys) == 0 || len(metaData.Unused) > 0 {
log.Error().Err(errors.ErrBadConfig).Msg("bad configuration, retry writing it")
panic(errors.ErrBadConfig)
}
err := config.LoadAccessControlConfig(viperInstance)
if err != nil {
log.Error().Err(err).Msg("unable to unmarshal config's accessControl")
panic(err)
}
// various config checks
validateConfiguration(config)
// defaults
defaultTLSVerify := true
if config.Extensions != nil && config.Extensions.Sync != nil {
for id, regCfg := range config.Extensions.Sync.Registries {
if regCfg.TLSVerify == nil {
config.Extensions.Sync.Registries[id].TLSVerify = &defaultTLSVerify
}
}
}
+34 -4
View File
@@ -10,7 +10,6 @@ import (
"time"
. "github.com/smartystreets/goconvey/convey"
"github.com/spf13/viper"
"gopkg.in/resty.v1"
"zotregistry.io/zot/pkg/api"
"zotregistry.io/zot/pkg/api/config"
@@ -188,6 +187,40 @@ func TestVerify(t *testing.T) {
So(func() { _ = cli.NewRootCmd().Execute() }, ShouldPanic)
})
Convey("Test verify with bad authorization repo patterns", t, func(c C) {
tmpfile, err := ioutil.TempFile("", "zot-test*.json")
So(err, ShouldBeNil)
defer os.Remove(tmpfile.Name()) // clean up
content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"},
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1},
"accessControl":{"\|":{"policies":[],"defaultPolicy":[]}}}}`)
_, err = tmpfile.Write(content)
So(err, ShouldBeNil)
err = tmpfile.Close()
So(err, ShouldBeNil)
os.Args = []string{"cli_test", "verify", tmpfile.Name()}
So(func() { _ = cli.NewRootCmd().Execute() }, ShouldPanic)
})
Convey("Test verify sync config default tls value", t, func(c C) {
tmpfile, err := ioutil.TempFile("", "zot-test*.json")
So(err, ShouldBeNil)
defer os.Remove(tmpfile.Name()) // clean up
content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"},
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}},
"extensions":{"sync": {"registries": [{"url":"localhost:9999",
"content": [{"prefix":"repo**"}]}]}}}`)
_, err = tmpfile.Write(content)
So(err, ShouldBeNil)
err = tmpfile.Close()
So(err, ShouldBeNil)
os.Args = []string{"cli_test", "verify", tmpfile.Name()}
err = cli.NewRootCmd().Execute()
So(err, ShouldBeNil)
})
Convey("Test verify good config", t, func(c C) {
tmpfile, err := ioutil.TempFile("", "zot-test*.json")
So(err, ShouldBeNil)
@@ -209,9 +242,6 @@ func TestLoadConfig(t *testing.T) {
Convey("Test viper load config", t, func(c C) {
config := config.New()
So(func() { cli.LoadConfiguration(config, "../../examples/config-policy.json") }, ShouldNotPanic)
adminPolicy := viper.GetStringMapStringSlice("http.accessControl.adminPolicy")
So(config.AccessControl.AdminPolicy.Actions, ShouldResemble, adminPolicy["actions"])
So(config.AccessControl.AdminPolicy.Users, ShouldResemble, adminPolicy["users"])
})
}