diff --git a/pkg/config/setup/config.go b/pkg/config/setup/config.go index 9ed374b26e64b..1cc1f63d2cc9e 100644 --- a/pkg/config/setup/config.go +++ b/pkg/config/setup/config.go @@ -975,6 +975,8 @@ func InitConfig(config pkgconfigmodel.Config) { config.BindEnvAndSetDefault("remote_policies", false) config.BindEnvAndSetDefault("installer.registry.url", "") config.BindEnvAndSetDefault("installer.registry.auth", "") + config.BindEnvAndSetDefault("installer.registry.username", "") + config.BindEnvAndSetDefault("installer.registry.password", "") config.BindEnv("fleet_policies_dir") config.SetDefault("fleet_layers", []string{}) diff --git a/pkg/fleet/env/env.go b/pkg/fleet/env/env.go index 4db44ce681b1d..b11a38048e489 100644 --- a/pkg/fleet/env/env.go +++ b/pkg/fleet/env/env.go @@ -23,6 +23,8 @@ const ( envRemotePolicies = "DD_REMOTE_POLICIES" envRegistryURL = "DD_INSTALLER_REGISTRY_URL" envRegistryAuth = "DD_INSTALLER_REGISTRY_AUTH" + envRegistryUsername = "DD_INSTALLER_REGISTRY_USERNAME" + envRegistryPassword = "DD_INSTALLER_REGISTRY_PASSWORD" envDefaultPackageVersion = "DD_INSTALLER_DEFAULT_PKG_VERSION" envDefaultPackageInstall = "DD_INSTALLER_DEFAULT_PKG_INSTALL" envApmLibraries = "DD_APM_INSTRUMENTATION_LIBRARIES" @@ -38,8 +40,12 @@ var defaultEnv = Env{ RegistryOverride: "", RegistryAuthOverride: "", + RegistryUsername: "", + RegistryPassword: "", RegistryOverrideByImage: map[string]string{}, RegistryAuthOverrideByImage: map[string]string{}, + RegistryUsernameByImage: map[string]string{}, + RegistryPasswordByImage: map[string]string{}, DefaultPackagesInstallOverride: map[string]bool{}, DefaultPackagesVersionOverride: map[string]string{}, @@ -64,8 +70,12 @@ type Env struct { RegistryOverride string RegistryAuthOverride string + RegistryUsername string + RegistryPassword string RegistryOverrideByImage map[string]string RegistryAuthOverrideByImage map[string]string + RegistryUsernameByImage map[string]string + RegistryPasswordByImage map[string]string DefaultPackagesInstallOverride map[string]bool DefaultPackagesVersionOverride map[string]string @@ -88,8 +98,12 @@ func FromEnv() *Env { RegistryOverride: getEnvOrDefault(envRegistryURL, defaultEnv.RegistryOverride), RegistryAuthOverride: getEnvOrDefault(envRegistryAuth, defaultEnv.RegistryAuthOverride), + RegistryUsername: getEnvOrDefault(envRegistryUsername, defaultEnv.RegistryUsername), + RegistryPassword: getEnvOrDefault(envRegistryPassword, defaultEnv.RegistryPassword), RegistryOverrideByImage: overridesByNameFromEnv(envRegistryURL, func(s string) string { return s }), RegistryAuthOverrideByImage: overridesByNameFromEnv(envRegistryAuth, func(s string) string { return s }), + RegistryUsernameByImage: overridesByNameFromEnv(envRegistryUsername, func(s string) string { return s }), + RegistryPasswordByImage: overridesByNameFromEnv(envRegistryPassword, func(s string) string { return s }), DefaultPackagesInstallOverride: overridesByNameFromEnv(envDefaultPackageInstall, func(s string) bool { return strings.ToLower(s) == "true" }), DefaultPackagesVersionOverride: overridesByNameFromEnv(envDefaultPackageVersion, func(s string) string { return s }), @@ -112,6 +126,8 @@ func FromConfig(config model.Reader) *Env { RemotePolicies: config.GetBool("remote_policies"), RegistryOverride: config.GetString("installer.registry.url"), RegistryAuthOverride: config.GetString("installer.registry.auth"), + RegistryUsername: config.GetString("installer.registry.username"), + RegistryPassword: config.GetString("installer.registry.password"), } } @@ -136,6 +152,12 @@ func (e *Env) ToEnv() []string { if e.RegistryAuthOverride != "" { env = append(env, envRegistryAuth+"="+e.RegistryAuthOverride) } + if e.RegistryUsername != "" { + env = append(env, envRegistryUsername+"="+e.RegistryUsername) + } + if e.RegistryPassword != "" { + env = append(env, envRegistryPassword+"="+e.RegistryPassword) + } if len(e.ApmLibraries) > 0 { libraries := []string{} for l, v := range e.ApmLibraries { @@ -150,6 +172,8 @@ func (e *Env) ToEnv() []string { } env = append(env, overridesByNameToEnv(envRegistryURL, e.RegistryOverrideByImage)...) env = append(env, overridesByNameToEnv(envRegistryAuth, e.RegistryAuthOverrideByImage)...) + env = append(env, overridesByNameToEnv(envRegistryUsername, e.RegistryUsernameByImage)...) + env = append(env, overridesByNameToEnv(envRegistryPassword, e.RegistryPasswordByImage)...) env = append(env, overridesByNameToEnv(envDefaultPackageInstall, e.DefaultPackagesInstallOverride)...) env = append(env, overridesByNameToEnv(envDefaultPackageVersion, e.DefaultPackagesVersionOverride)...) return env diff --git a/pkg/fleet/env/env_test.go b/pkg/fleet/env/env_test.go index b4e86c46e3f93..9c42a96f99983 100644 --- a/pkg/fleet/env/env_test.go +++ b/pkg/fleet/env/env_test.go @@ -25,8 +25,12 @@ func TestFromEnv(t *testing.T) { Site: "datadoghq.com", RegistryOverride: "", RegistryAuthOverride: "", + RegistryUsername: "", + RegistryPassword: "", RegistryOverrideByImage: map[string]string{}, RegistryAuthOverrideByImage: map[string]string{}, + RegistryUsernameByImage: map[string]string{}, + RegistryPasswordByImage: map[string]string{}, DefaultPackagesInstallOverride: map[string]bool{}, DefaultPackagesVersionOverride: map[string]string{}, ApmLibraries: map[ApmLibLanguage]ApmLibVersion{}, @@ -44,10 +48,16 @@ func TestFromEnv(t *testing.T) { envRemotePolicies: "true", envRegistryURL: "registry.example.com", envRegistryAuth: "auth", + envRegistryUsername: "username", + envRegistryPassword: "password", envRegistryURL + "_IMAGE": "another.registry.example.com", envRegistryURL + "_ANOTHER_IMAGE": "yet.another.registry.example.com", envRegistryAuth + "_IMAGE": "another.auth", envRegistryAuth + "_ANOTHER_IMAGE": "yet.another.auth", + envRegistryUsername + "_IMAGE": "another.username", + envRegistryUsername + "_ANOTHER_IMAGE": "yet.another.username", + envRegistryPassword + "_IMAGE": "another.password", + envRegistryPassword + "_ANOTHER_IMAGE": "yet.another.password", envDefaultPackageInstall + "_PACKAGE": "true", envDefaultPackageInstall + "_ANOTHER_PACKAGE": "false", envDefaultPackageVersion + "_PACKAGE": "1.2.3", @@ -62,6 +72,8 @@ func TestFromEnv(t *testing.T) { RemotePolicies: true, RegistryOverride: "registry.example.com", RegistryAuthOverride: "auth", + RegistryUsername: "username", + RegistryPassword: "password", RegistryOverrideByImage: map[string]string{ "image": "another.registry.example.com", "another-image": "yet.another.registry.example.com", @@ -70,6 +82,14 @@ func TestFromEnv(t *testing.T) { "image": "another.auth", "another-image": "yet.another.auth", }, + RegistryUsernameByImage: map[string]string{ + "image": "another.username", + "another-image": "yet.another.username", + }, + RegistryPasswordByImage: map[string]string{ + "image": "another.password", + "another-image": "yet.another.password", + }, DefaultPackagesInstallOverride: map[string]bool{ "package": true, "another-package": false, @@ -100,6 +120,8 @@ func TestFromEnv(t *testing.T) { RegistryAuthOverride: "", RegistryOverrideByImage: map[string]string{}, RegistryAuthOverrideByImage: map[string]string{}, + RegistryUsernameByImage: map[string]string{}, + RegistryPasswordByImage: map[string]string{}, DefaultPackagesInstallOverride: map[string]bool{}, DefaultPackagesVersionOverride: map[string]string{}, ApmLibraries: map[ApmLibLanguage]ApmLibVersion{ @@ -133,6 +155,8 @@ func TestFromEnv(t *testing.T) { }, RegistryOverrideByImage: map[string]string{}, RegistryAuthOverrideByImage: map[string]string{}, + RegistryUsernameByImage: map[string]string{}, + RegistryPasswordByImage: map[string]string{}, DefaultPackagesInstallOverride: map[string]bool{}, DefaultPackagesVersionOverride: map[string]string{}, }, @@ -171,6 +195,8 @@ func TestToEnv(t *testing.T) { RemotePolicies: true, RegistryOverride: "registry.example.com", RegistryAuthOverride: "auth", + RegistryUsername: "username", + RegistryPassword: "password", RegistryOverrideByImage: map[string]string{ "image": "another.registry.example.com", "another-image": "yet.another.registry.example.com", @@ -179,6 +205,14 @@ func TestToEnv(t *testing.T) { "image": "another.auth", "another-image": "yet.another.auth", }, + RegistryUsernameByImage: map[string]string{ + "image": "another.username", + "another-image": "yet.another.username", + }, + RegistryPasswordByImage: map[string]string{ + "image": "another.password", + "another-image": "yet.another.password", + }, DefaultPackagesInstallOverride: map[string]bool{ "package": true, "another-package": false, @@ -200,11 +234,17 @@ func TestToEnv(t *testing.T) { "DD_REMOTE_POLICIES=true", "DD_INSTALLER_REGISTRY_URL=registry.example.com", "DD_INSTALLER_REGISTRY_AUTH=auth", + "DD_INSTALLER_REGISTRY_USERNAME=username", + "DD_INSTALLER_REGISTRY_PASSWORD=password", "DD_APM_INSTRUMENTATION_LIBRARIES=dotnet:latest,java,ruby:1.2", "DD_INSTALLER_REGISTRY_URL_IMAGE=another.registry.example.com", "DD_INSTALLER_REGISTRY_URL_ANOTHER_IMAGE=yet.another.registry.example.com", "DD_INSTALLER_REGISTRY_AUTH_IMAGE=another.auth", "DD_INSTALLER_REGISTRY_AUTH_ANOTHER_IMAGE=yet.another.auth", + "DD_INSTALLER_REGISTRY_USERNAME_IMAGE=another.username", + "DD_INSTALLER_REGISTRY_USERNAME_ANOTHER_IMAGE=yet.another.username", + "DD_INSTALLER_REGISTRY_PASSWORD_IMAGE=another.password", + "DD_INSTALLER_REGISTRY_PASSWORD_ANOTHER_IMAGE=yet.another.password", "DD_INSTALLER_DEFAULT_PKG_INSTALL_PACKAGE=true", "DD_INSTALLER_DEFAULT_PKG_INSTALL_ANOTHER_PACKAGE=false", "DD_INSTALLER_DEFAULT_PKG_VERSION_PACKAGE=1.2.3", diff --git a/pkg/fleet/internal/oci/download.go b/pkg/fleet/internal/oci/download.go index 95593831dc901..6900c771dc942 100644 --- a/pkg/fleet/internal/oci/download.go +++ b/pkg/fleet/internal/oci/download.go @@ -41,6 +41,8 @@ const ( RegistryAuthGCR string = "gcr" // RegistryAuthECR is the Amazon Elastic Container Registry authentication method. RegistryAuthECR string = "ecr" + // RegistryAuthPassword is the password registry authentication method. + RegistryAuthPassword string = "password" ) const ( @@ -132,12 +134,17 @@ func (d *Downloader) Download(ctx context.Context, packageURL string) (*Download }, nil } -func getKeychain(auth string) authn.Keychain { +func getKeychain(auth string, username string, password string) authn.Keychain { switch auth { case RegistryAuthGCR: return google.Keychain case RegistryAuthECR: return authn.NewKeychainFromHelper(ecr.NewECRHelper()) + case RegistryAuthPassword: + return usernamePasswordKeychain{ + username: username, + password: password, + } case RegistryAuthDefault, "": return authn.DefaultKeychain default: @@ -169,10 +176,10 @@ func getRefAndKeychain(env *env.Env, url string) urlWithKeychain { } ref = registryOverride + imageWithIdentifier } - keychain := getKeychain(env.RegistryAuthOverride) + keychain := getKeychain(env.RegistryAuthOverride, env.RegistryUsername, env.RegistryPassword) for image, override := range env.RegistryAuthOverrideByImage { if strings.HasPrefix(imageWithIdentifier, image+":") || strings.HasPrefix(imageWithIdentifier, image+"@") { - keychain = getKeychain(override) + keychain = getKeychain(override, env.RegistryUsername, env.RegistryPassword) break } } @@ -313,3 +320,15 @@ func isStreamResetError(err error) bool { } return false } + +type usernamePasswordKeychain struct { + username string + password string +} + +func (k usernamePasswordKeychain) Resolve(_ authn.Resource) (authn.Authenticator, error) { + return authn.FromConfig(authn.AuthConfig{ + Username: k.username, + Password: k.password, + }), nil +}