2021-06-08 23:11:18 +03:00
|
|
|
package config
|
2019-06-20 16:36:40 -07:00
|
|
|
|
|
|
|
import (
|
2022-08-10 22:28:52 +00:00
|
|
|
"os"
|
2022-02-10 00:51:35 +00:00
|
|
|
"time"
|
2021-05-13 21:59:12 +03:00
|
|
|
|
2019-08-15 09:34:54 -07:00
|
|
|
"github.com/getlantern/deepcopy"
|
2021-05-21 20:47:28 +00:00
|
|
|
distspec "github.com/opencontainers/distribution-spec/specs-go"
|
2022-10-20 19:39:20 +03:00
|
|
|
|
2021-12-04 03:50:58 +00:00
|
|
|
extconf "zotregistry.io/zot/pkg/extensions/config"
|
2023-05-26 21:08:19 +03:00
|
|
|
storageConstants "zotregistry.io/zot/pkg/storage/constants"
|
2019-06-20 16:36:40 -07:00
|
|
|
)
|
|
|
|
|
2021-02-12 16:52:02 -08:00
|
|
|
var (
|
2022-10-05 13:21:14 +03:00
|
|
|
Commit string //nolint: gochecknoglobals
|
2022-10-11 19:01:59 +03:00
|
|
|
ReleaseTag string //nolint: gochecknoglobals
|
2022-10-05 13:21:14 +03:00
|
|
|
BinaryType string //nolint: gochecknoglobals
|
|
|
|
GoVersion string //nolint: gochecknoglobals
|
2023-07-19 19:27:04 +03:00
|
|
|
|
|
|
|
openIDSupportedProviders = [...]string{"google", "gitlab", "dex"} //nolint: gochecknoglobals
|
|
|
|
oauth2SupportedProviders = [...]string{"github"} //nolint: gochecknoglobals
|
|
|
|
|
2021-02-12 16:52:02 -08:00
|
|
|
)
|
2019-09-16 11:01:59 -07:00
|
|
|
|
2019-06-20 16:36:40 -07:00
|
|
|
type StorageConfig struct {
|
|
|
|
RootDirectory string
|
2020-04-15 16:24:05 -07:00
|
|
|
Dedupe bool
|
2022-11-03 00:53:08 +02:00
|
|
|
RemoteCache bool
|
|
|
|
GC bool
|
2022-01-21 04:11:44 +00:00
|
|
|
Commit bool
|
2022-02-10 00:51:35 +00:00
|
|
|
GCDelay time.Duration
|
2022-03-21 20:40:37 +02:00
|
|
|
GCInterval time.Duration
|
2021-07-17 06:53:05 +03:00
|
|
|
StorageDriver map[string]interface{} `mapstructure:",omitempty"`
|
2022-11-22 20:29:57 +02:00
|
|
|
CacheDriver map[string]interface{} `mapstructure:",omitempty"`
|
2019-06-20 16:36:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
type TLSConfig struct {
|
|
|
|
Cert string
|
|
|
|
Key string
|
|
|
|
CACert string
|
|
|
|
}
|
|
|
|
|
|
|
|
type AuthHTPasswd struct {
|
|
|
|
Path string
|
|
|
|
}
|
|
|
|
|
|
|
|
type AuthConfig struct {
|
|
|
|
FailDelay int
|
|
|
|
HTPasswd AuthHTPasswd
|
2019-08-15 09:34:54 -07:00
|
|
|
LDAP *LDAPConfig
|
2020-01-24 15:32:38 -06:00
|
|
|
Bearer *BearerConfig
|
2023-07-07 19:27:10 +03:00
|
|
|
OpenID *OpenIDConfig
|
2023-08-02 21:58:34 +03:00
|
|
|
APIKey bool
|
2020-01-24 15:32:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
type BearerConfig struct {
|
|
|
|
Realm string
|
|
|
|
Service string
|
|
|
|
Cert string
|
2019-06-20 16:36:40 -07:00
|
|
|
}
|
|
|
|
|
2023-07-07 19:27:10 +03:00
|
|
|
type OpenIDConfig struct {
|
|
|
|
Providers map[string]OpenIDProviderConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
type OpenIDProviderConfig struct {
|
|
|
|
ClientID string
|
|
|
|
ClientSecret string
|
|
|
|
KeyPath string
|
|
|
|
Issuer string
|
|
|
|
Scopes []string
|
|
|
|
}
|
|
|
|
|
2022-01-21 20:30:09 +00:00
|
|
|
type MethodRatelimitConfig struct {
|
|
|
|
Method string
|
|
|
|
Rate int
|
|
|
|
}
|
|
|
|
|
|
|
|
type RatelimitConfig struct {
|
|
|
|
Rate *int // requests per second
|
|
|
|
Methods []MethodRatelimitConfig `mapstructure:",omitempty"`
|
|
|
|
}
|
|
|
|
|
2023-07-07 19:27:10 +03:00
|
|
|
//nolint:maligned
|
2019-06-20 16:36:40 -07:00
|
|
|
type HTTPConfig struct {
|
2023-03-08 21:47:15 +02:00
|
|
|
Address string
|
|
|
|
Port string
|
|
|
|
AllowOrigin string // comma separated
|
|
|
|
TLS *TLSConfig
|
|
|
|
Auth *AuthConfig
|
2023-03-09 20:43:26 +02:00
|
|
|
AccessControl *AccessControlConfig `mapstructure:"accessControl,omitempty"`
|
2023-03-08 21:47:15 +02:00
|
|
|
Realm string
|
|
|
|
Ratelimit *RatelimitConfig `mapstructure:",omitempty"`
|
2019-06-20 16:36:40 -07:00
|
|
|
}
|
|
|
|
|
2023-07-04 11:03:29 +03:00
|
|
|
type SchedulerConfig struct {
|
|
|
|
NumWorkers int
|
|
|
|
}
|
|
|
|
|
2019-08-15 09:34:54 -07:00
|
|
|
type LDAPConfig struct {
|
2023-03-08 21:47:15 +02:00
|
|
|
Port int
|
|
|
|
Insecure bool
|
|
|
|
StartTLS bool // if !Insecure, then StartTLS or LDAPs
|
|
|
|
SkipVerify bool
|
|
|
|
SubtreeSearch bool
|
|
|
|
Address string
|
|
|
|
BindDN string
|
|
|
|
UserGroupAttribute string
|
|
|
|
BindPassword string
|
|
|
|
BaseDN string
|
|
|
|
UserAttribute string
|
|
|
|
CACert string
|
2019-08-15 09:34:54 -07:00
|
|
|
}
|
|
|
|
|
2019-06-20 16:36:40 -07:00
|
|
|
type LogConfig struct {
|
|
|
|
Level string
|
|
|
|
Output string
|
2021-05-25 11:38:21 +03:00
|
|
|
Audit string
|
2019-06-20 16:36:40 -07:00
|
|
|
}
|
|
|
|
|
2021-04-05 17:40:33 -07:00
|
|
|
type GlobalStorageConfig struct {
|
2022-11-03 00:53:08 +02:00
|
|
|
StorageConfig `mapstructure:",squash"`
|
2021-04-05 17:40:33 -07:00
|
|
|
SubPaths map[string]StorageConfig
|
|
|
|
}
|
|
|
|
|
2021-06-08 23:11:18 +03:00
|
|
|
type AccessControlConfig struct {
|
2023-03-08 21:47:15 +02:00
|
|
|
Repositories Repositories `json:"repositories" mapstructure:"repositories"`
|
2021-06-08 23:11:18 +03:00
|
|
|
AdminPolicy Policy
|
2023-03-08 21:47:15 +02:00
|
|
|
Groups Groups
|
2021-06-08 23:11:18 +03:00
|
|
|
}
|
|
|
|
|
2023-06-22 14:29:45 +03:00
|
|
|
func (config *AccessControlConfig) AnonymousPolicyExists() bool {
|
|
|
|
if config == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, repository := range config.Repositories {
|
|
|
|
if len(repository.AnonymousPolicy) > 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-03-08 21:47:15 +02:00
|
|
|
type (
|
|
|
|
Repositories map[string]PolicyGroup
|
|
|
|
Groups map[string]Group
|
|
|
|
)
|
|
|
|
|
|
|
|
type Group struct {
|
|
|
|
Users []string
|
|
|
|
}
|
2021-06-08 23:11:18 +03:00
|
|
|
|
|
|
|
type PolicyGroup struct {
|
2022-07-14 18:13:46 +03:00
|
|
|
Policies []Policy
|
|
|
|
DefaultPolicy []string
|
|
|
|
AnonymousPolicy []string
|
2021-06-08 23:11:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type Policy struct {
|
|
|
|
Users []string
|
|
|
|
Actions []string
|
2023-03-08 21:47:15 +02:00
|
|
|
Groups []string
|
2021-06-08 23:11:18 +03:00
|
|
|
}
|
|
|
|
|
2019-06-20 16:36:40 -07:00
|
|
|
type Config struct {
|
2022-03-07 14:50:15 +02:00
|
|
|
DistSpecVersion string `json:"distSpecVersion" mapstructure:"distSpecVersion"`
|
|
|
|
GoVersion string
|
|
|
|
Commit string
|
2022-10-11 19:01:59 +03:00
|
|
|
ReleaseTag string
|
2022-03-07 14:50:15 +02:00
|
|
|
BinaryType string
|
|
|
|
Storage GlobalStorageConfig
|
|
|
|
HTTP HTTPConfig
|
|
|
|
Log *LogConfig
|
|
|
|
Extensions *extconf.ExtensionConfig
|
2023-07-04 11:03:29 +03:00
|
|
|
Scheduler *SchedulerConfig `json:"scheduler" mapstructure:",omitempty"`
|
2019-06-20 16:36:40 -07:00
|
|
|
}
|
|
|
|
|
2021-06-08 23:11:18 +03:00
|
|
|
func New() *Config {
|
2019-06-20 16:36:40 -07:00
|
|
|
return &Config{
|
2022-03-07 14:50:15 +02:00
|
|
|
DistSpecVersion: distspec.Version,
|
|
|
|
GoVersion: GoVersion,
|
|
|
|
Commit: Commit,
|
2022-10-11 19:01:59 +03:00
|
|
|
ReleaseTag: ReleaseTag,
|
2022-03-07 14:50:15 +02:00
|
|
|
BinaryType: BinaryType,
|
2022-11-03 00:53:08 +02:00
|
|
|
Storage: GlobalStorageConfig{
|
2023-05-26 21:08:19 +03:00
|
|
|
StorageConfig: StorageConfig{GC: true, GCDelay: storageConstants.DefaultGCDelay, Dedupe: true},
|
2022-11-03 00:53:08 +02:00
|
|
|
},
|
|
|
|
HTTP: HTTPConfig{Address: "127.0.0.1", Port: "8080", Auth: &AuthConfig{FailDelay: 0}},
|
|
|
|
Log: &LogConfig{Level: "debug"},
|
2019-08-15 09:34:54 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-10 22:28:52 +00:00
|
|
|
func (expConfig StorageConfig) ParamsEqual(actConfig StorageConfig) bool {
|
|
|
|
return expConfig.GC == actConfig.GC && expConfig.Dedupe == actConfig.Dedupe &&
|
|
|
|
expConfig.GCDelay == actConfig.GCDelay && expConfig.GCInterval == actConfig.GCInterval
|
|
|
|
}
|
|
|
|
|
|
|
|
// SameFile compare two files.
|
|
|
|
// This method will first do the stat of two file and compare using os.SameFile method.
|
|
|
|
func SameFile(str1, str2 string) (bool, error) {
|
|
|
|
sFile, err := os.Stat(str1)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
tFile, err := os.Stat(str2)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return os.SameFile(sFile, tFile), nil
|
|
|
|
}
|
|
|
|
|
2020-05-11 15:13:24 -07:00
|
|
|
// Sanitize makes a sanitized copy of the config removing any secrets.
|
2019-08-15 09:34:54 -07:00
|
|
|
func (c *Config) Sanitize() *Config {
|
2021-12-13 19:23:31 +00:00
|
|
|
sanitizedConfig := &Config{}
|
|
|
|
if err := deepcopy.Copy(sanitizedConfig, c); err != nil {
|
2021-06-08 23:11:18 +03:00
|
|
|
panic(err)
|
|
|
|
}
|
2019-12-13 00:53:18 -05:00
|
|
|
|
2021-06-08 23:11:18 +03:00
|
|
|
if c.HTTP.Auth != nil && c.HTTP.Auth.LDAP != nil && c.HTTP.Auth.LDAP.BindPassword != "" {
|
2021-12-13 19:23:31 +00:00
|
|
|
sanitizedConfig.HTTP.Auth.LDAP = &LDAPConfig{}
|
2019-12-13 00:53:18 -05:00
|
|
|
|
2021-12-13 19:23:31 +00:00
|
|
|
if err := deepcopy.Copy(sanitizedConfig.HTTP.Auth.LDAP, c.HTTP.Auth.LDAP); err != nil {
|
2019-08-15 09:34:54 -07:00
|
|
|
panic(err)
|
|
|
|
}
|
2019-12-13 00:53:18 -05:00
|
|
|
|
2021-12-13 19:23:31 +00:00
|
|
|
sanitizedConfig.HTTP.Auth.LDAP.BindPassword = "******"
|
2019-08-15 09:34:54 -07:00
|
|
|
}
|
2019-12-13 00:53:18 -05:00
|
|
|
|
2021-12-13 19:23:31 +00:00
|
|
|
return sanitizedConfig
|
2019-08-15 09:34:54 -07:00
|
|
|
}
|
2023-07-19 19:27:04 +03:00
|
|
|
|
|
|
|
func (c *Config) IsLdapAuthEnabled() bool {
|
|
|
|
if c.HTTP.Auth != nil && c.HTTP.Auth.LDAP != nil {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) IsHtpasswdAuthEnabled() bool {
|
|
|
|
if c.HTTP.Auth != nil && c.HTTP.Auth.HTPasswd.Path != "" {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) IsBearerAuthEnabled() bool {
|
|
|
|
if c.HTTP.Auth != nil &&
|
|
|
|
c.HTTP.Auth.Bearer != nil &&
|
|
|
|
c.HTTP.Auth.Bearer.Cert != "" &&
|
|
|
|
c.HTTP.Auth.Bearer.Realm != "" &&
|
|
|
|
c.HTTP.Auth.Bearer.Service != "" {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) IsOpenIDAuthEnabled() bool {
|
|
|
|
if c.HTTP.Auth != nil &&
|
|
|
|
c.HTTP.Auth.OpenID != nil {
|
|
|
|
for provider := range c.HTTP.Auth.OpenID.Providers {
|
|
|
|
if isOpenIDAuthProviderEnabled(c, provider) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) IsAPIKeyEnabled() bool {
|
2023-08-02 21:58:34 +03:00
|
|
|
if c.HTTP.Auth != nil && c.HTTP.Auth.APIKey {
|
2023-07-19 19:27:04 +03:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) IsBasicAuthnEnabled() bool {
|
|
|
|
if c.IsHtpasswdAuthEnabled() || c.IsLdapAuthEnabled() ||
|
|
|
|
c.IsOpenIDAuthEnabled() || c.IsAPIKeyEnabled() {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func isOpenIDAuthProviderEnabled(config *Config, provider string) bool {
|
|
|
|
if providerConfig, ok := config.HTTP.Auth.OpenID.Providers[provider]; ok {
|
|
|
|
if IsOpenIDSupported(provider) {
|
|
|
|
if providerConfig.ClientID != "" || providerConfig.Issuer != "" ||
|
|
|
|
len(providerConfig.Scopes) > 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
} else if IsOauth2Supported(provider) {
|
|
|
|
if providerConfig.ClientID != "" || len(providerConfig.Scopes) > 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-08-02 21:58:34 +03:00
|
|
|
func (c *Config) IsSearchEnabled() bool {
|
|
|
|
return c.Extensions != nil && c.Extensions.Search != nil && *c.Extensions.Search.Enable
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) IsUIEnabled() bool {
|
|
|
|
return c.Extensions != nil && c.Extensions.UI != nil && *c.Extensions.UI.Enable
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) AreUserPrefsEnabled() bool {
|
|
|
|
return c.IsSearchEnabled() && c.IsUIEnabled()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) IsMgmtEnabled() bool {
|
|
|
|
return c.IsSearchEnabled() && c.IsUIEnabled()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) IsImageTrustEnabled() bool {
|
|
|
|
return c.Extensions != nil && c.Extensions.Trust != nil && *c.Extensions.Trust.Enable
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) IsCosignEnabled() bool {
|
|
|
|
return c.IsImageTrustEnabled() && c.Extensions.Trust.Cosign
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) IsNotationEnabled() bool {
|
|
|
|
return c.IsImageTrustEnabled() && c.Extensions.Trust.Notation
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) IsSyncEnabled() bool {
|
|
|
|
return c.Extensions != nil && c.Extensions.Sync != nil && *c.Extensions.Sync.Enable
|
|
|
|
}
|
|
|
|
|
2023-07-19 19:27:04 +03:00
|
|
|
func IsOpenIDSupported(provider string) bool {
|
|
|
|
for _, supportedProvider := range openIDSupportedProviders {
|
|
|
|
if supportedProvider == provider {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func IsOauth2Supported(provider string) bool {
|
|
|
|
for _, supportedProvider := range oauth2SupportedProviders {
|
|
|
|
if supportedProvider == provider {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|