diff --git a/agent/app/agent_capability.go b/agent/app/agent_capability.go index 141cd40a343..601879cdf24 100644 --- a/agent/app/agent_capability.go +++ b/agent/app/agent_capability.go @@ -304,6 +304,14 @@ func (agent *ecsAgent) appendDockerDependentCapabilities(capabilities []*ecs.Att return capabilities } +func (agent *ecsAgent) appendGMSACapabilities(capabilities []*ecs.Attribute) []*ecs.Attribute { + if agent.cfg.GMSACapable { + return appendNameOnlyAttribute(capabilities, attributePrefix+capabilityGMSA) + } + + return capabilities +} + func (agent *ecsAgent) appendLoggingDriverCapabilities(capabilities []*ecs.Attribute) []*ecs.Attribute { knownVersions := make(map[dockerclient.DockerVersion]struct{}) // Determine known API versions. Known versions are used exclusively for logging-driver enablement, since none of diff --git a/agent/app/agent_capability_test.go b/agent/app/agent_capability_test.go index 700053c49eb..657ab3ccec5 100644 --- a/agent/app/agent_capability_test.go +++ b/agent/app/agent_capability_test.go @@ -1416,3 +1416,29 @@ func TestAppendAndRemoveAttributes(t *testing.T) { Name: aws.String("cap-2"), }) } + +func TestAppendGMSACapabilities(t *testing.T) { + var inputCapabilities []*ecs.Attribute + var expectedCapabilities []*ecs.Attribute + + expectedCapabilities = append(expectedCapabilities, + []*ecs.Attribute{ + { + Name: aws.String(attributePrefix + capabilityGMSA), + }, + }...) + + agent := &ecsAgent{ + cfg: &config.Config{ + GMSACapable: true, + }, + } + + capabilities := agent.appendGMSACapabilities(inputCapabilities) + + assert.Equal(t, len(expectedCapabilities), len(capabilities)) + for i, expected := range expectedCapabilities { + assert.Equal(t, aws.StringValue(expected.Name), aws.StringValue(capabilities[i].Name)) + assert.Equal(t, aws.StringValue(expected.Value), aws.StringValue(capabilities[i].Value)) + } +} diff --git a/agent/app/agent_capability_unix.go b/agent/app/agent_capability_unix.go index f7c2b318f5c..51b43935dba 100644 --- a/agent/app/agent_capability_unix.go +++ b/agent/app/agent_capability_unix.go @@ -200,10 +200,6 @@ func (agent *ecsAgent) appendFirelensConfigCapabilities(capabilities []*ecs.Attr return appendNameOnlyAttribute(capabilities, attributePrefix+capabilityFirelensConfigS3) } -func (agent *ecsAgent) appendGMSACapabilities(capabilities []*ecs.Attribute) []*ecs.Attribute { - return capabilities -} - func (agent *ecsAgent) appendIPv6Capability(capabilities []*ecs.Attribute) []*ecs.Attribute { return appendNameOnlyAttribute(capabilities, attributePrefix+taskENIIPv6AttributeSuffix) } diff --git a/agent/app/agent_capability_unix_test.go b/agent/app/agent_capability_unix_test.go index 956d386e160..0faf8905f42 100644 --- a/agent/app/agent_capability_unix_test.go +++ b/agent/app/agent_capability_unix_test.go @@ -913,16 +913,6 @@ func TestFirelensConfigCapabilitiesUnix(t *testing.T) { assert.Contains(t, capabilities, &ecs.Attribute{Name: aws.String(attributePrefix + capabilityFirelensConfigS3)}) } -func TestAppendGMSACapabilities(t *testing.T) { - var inputCapabilities []*ecs.Attribute - - agent := &ecsAgent{} - - capabilities := agent.appendGMSACapabilities(inputCapabilities) - assert.Equal(t, len(inputCapabilities), len(capabilities)) - assert.EqualValues(t, capabilities, inputCapabilities) -} - func TestAppendFSxWindowsFileServerCapabilities(t *testing.T) { var inputCapabilities []*ecs.Attribute diff --git a/agent/app/agent_capability_windows.go b/agent/app/agent_capability_windows.go index 749b0c3a6a5..77f34138e4b 100644 --- a/agent/app/agent_capability_windows.go +++ b/agent/app/agent_capability_windows.go @@ -100,14 +100,6 @@ func (agent *ecsAgent) appendFirelensConfigCapabilities(capabilities []*ecs.Attr return capabilities } -func (agent *ecsAgent) appendGMSACapabilities(capabilities []*ecs.Attribute) []*ecs.Attribute { - if agent.cfg.GMSACapable { - return appendNameOnlyAttribute(capabilities, attributePrefix+capabilityGMSA) - } - - return capabilities -} - func (agent *ecsAgent) appendEFSVolumePluginCapabilities(capabilities []*ecs.Attribute, pluginCapability string) []*ecs.Attribute { return capabilities } diff --git a/agent/app/agent_capability_windows_test.go b/agent/app/agent_capability_windows_test.go index 46c98cd592d..63925124929 100644 --- a/agent/app/agent_capability_windows_test.go +++ b/agent/app/agent_capability_windows_test.go @@ -225,32 +225,6 @@ func TestSupportedCapabilitiesWindows(t *testing.T) { } } -func TestAppendGMSACapabilities(t *testing.T) { - var inputCapabilities []*ecs.Attribute - var expectedCapabilities []*ecs.Attribute - - expectedCapabilities = append(expectedCapabilities, - []*ecs.Attribute{ - { - Name: aws.String(attributePrefix + capabilityGMSA), - }, - }...) - - agent := &ecsAgent{ - cfg: &config.Config{ - GMSACapable: true, - }, - } - - capabilities := agent.appendGMSACapabilities(inputCapabilities) - - assert.Equal(t, len(expectedCapabilities), len(capabilities)) - for i, expected := range expectedCapabilities { - assert.Equal(t, aws.StringValue(expected.Name), aws.StringValue(capabilities[i].Name)) - assert.Equal(t, aws.StringValue(expected.Value), aws.StringValue(capabilities[i].Value)) - } -} - func TestAppendGMSACapabilitiesFalse(t *testing.T) { var inputCapabilities []*ecs.Attribute var expectedCapabilities []*ecs.Attribute diff --git a/agent/config/config_unix.go b/agent/config/config_unix.go index 8f6b8019609..3b95d84ac56 100644 --- a/agent/config/config_unix.go +++ b/agent/config/config_unix.go @@ -100,7 +100,7 @@ func DefaultConfig() Config { PollingMetricsWaitDuration: DefaultPollingMetricsWaitDuration, NvidiaRuntime: DefaultNvidiaRuntime, CgroupCPUPeriod: defaultCgroupCPUPeriod, - GMSACapable: false, + GMSACapable: isGMSACapable(), FSxWindowsFileServerCapable: false, RuntimeStatsLogFile: defaultRuntimeStatsLogFile, EnableRuntimeStats: BooleanDefaultFalse{Value: NotSet}, @@ -135,3 +135,7 @@ func (cfg *Config) platformString() string { func getConfigFileName() (string, error) { return utils.DefaultIfBlank(os.Getenv("ECS_AGENT_CONFIG_FILE_PATH"), defaultConfigFileName), nil } + +func isGMSACapable() bool { + return utils.ParseBool(os.Getenv("ECS_GMSA_SUPPORTED"), true) +} diff --git a/agent/config/parse.go b/agent/config/parse.go index ba37b28a926..f8f018f3d41 100644 --- a/agent/config/parse.go +++ b/agent/config/parse.go @@ -27,6 +27,13 @@ import ( cnitypes "github.com/containernetworking/cni/pkg/types" ) +const ( + // envSkipDomainJoinCheck is an environment setting that can be used to skip + // domain join check validation. This is useful for integration and + // functional-tests but should not be set for any non-test use-case. + envSkipDomainJoinCheck = "ZZZ_SKIP_DOMAIN_JOIN_CHECK_NOT_SUPPORTED_IN_PRODUCTION" +) + func parseCheckpoint(dataDir string) BooleanDefaultFalse { checkPoint := parseBooleanDefaultFalseConfig("ECS_CHECKPOINT") if dataDir != "" { diff --git a/agent/config/parse_linux.go b/agent/config/parse_linux.go index 5ab45d3cf1e..6df94dc6e6f 100644 --- a/agent/config/parse_linux.go +++ b/agent/config/parse_linux.go @@ -7,7 +7,7 @@ // not use this file except in compliance with the License. A copy of the // License is located at // -// httpaws.amazon.com/apache2.0/ +// http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either @@ -18,10 +18,43 @@ package config import ( "errors" + "os" "strings" + + "github.com/aws/amazon-ecs-agent/agent/utils" + "github.com/cihub/seelog" ) func parseGMSACapability() bool { + envStatus := utils.ParseBool(os.Getenv("ECS_GMSA_SUPPORTED"), true) + if envStatus { + // Check if domain join check override is present + skipDomainJoinCheck := utils.ParseBool(os.Getenv(envSkipDomainJoinCheck), false) + if skipDomainJoinCheck { + seelog.Errorf("Skipping domain join validation based on environment override") + return true + } + + // check if the credentials fetcher socket is created and exists + // this env variable is set in ecs-init module + if credentialsfetcherHostDir := os.Getenv("CREDENTIALS_FETCHER_HOST_DIR"); credentialsfetcherHostDir != "" { + _, err := os.Stat(credentialsfetcherHostDir) + if err != nil { + if os.IsNotExist(err) { + seelog.Errorf("credentials fetcher socket doesn't exist to support linux gmsa") + return false + } + } + // returns true if the container instance is domain joined + // this env variable is set in ecs-init module + isDomainJoined := utils.ParseBool(os.Getenv("ECS_DOMAIN_JOINED_LINUX_INSTANCE"), false) + + if !isDomainJoined { + seelog.Errorf("Unable to determine valid domain join") + } + return isDomainJoined + } + } return false } diff --git a/agent/config/parse_linux_test.go b/agent/config/parse_linux_test.go new file mode 100644 index 00000000000..d609bab116d --- /dev/null +++ b/agent/config/parse_linux_test.go @@ -0,0 +1,63 @@ +//go:build linux && unit +// +build linux,unit + +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +package config + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParseGMSACapabilitySupported(t *testing.T) { + os.Setenv("ECS_GMSA_SUPPORTED", "True") + defer os.Unsetenv("ECS_GMSA_SUPPORTED") + + os.Setenv("ECS_DOMAIN_JOINED_LINUX_INSTANCE", "True") + defer os.Unsetenv("ECS_DOMAIN_JOINED_LINUX_INSTANCE") + + os.Setenv("CREDENTIALS_FETCHER_HOST_DIR", "/var/run") + defer os.Unsetenv("CREDENTIALS_FETCHER_HOST_DIR") + + assert.True(t, parseGMSACapability()) +} + +func TestParseGMSACapabilityNonDomainJoined(t *testing.T) { + os.Setenv("ECS_GMSA_SUPPORTED", "True") + defer os.Unsetenv("ECS_GMSA_SUPPORTED") + + os.Setenv("ECS_DOMAIN_JOINED_LINUX_INSTANCE", "False") + defer os.Unsetenv("ECS_DOMAIN_JOINED_LINUX_INSTANCE") + + assert.False(t, parseGMSACapability()) +} + +func TestParseGMSACapabilityUnsupported(t *testing.T) { + os.Setenv("ECS_GMSA_SUPPORTED", "False") + defer os.Unsetenv("ECS_GMSA_SUPPORTED") + + assert.False(t, parseGMSACapability()) +} + +func TestSkipDomainJoinCheckParseGMSACapability(t *testing.T) { + os.Setenv("ECS_GMSA_SUPPORTED", "True") + defer os.Unsetenv("ECS_GMSA_SUPPORTED") + os.Setenv("ZZZ_SKIP_DOMAIN_JOIN_CHECK_NOT_SUPPORTED_IN_PRODUCTION", "True") + defer os.Unsetenv("ZZZ_SKIP_DOMAIN_JOIN_CHECK_NOT_SUPPORTED_IN_PRODUCTION") + + assert.True(t, parseGMSACapability()) +} diff --git a/agent/config/parse_windows.go b/agent/config/parse_windows.go index 6040cb5d27c..c9c6dec403b 100644 --- a/agent/config/parse_windows.go +++ b/agent/config/parse_windows.go @@ -28,11 +28,6 @@ import ( ) const ( - // envSkipDomainJoinCheck is an environment setting that can be used to skip - // domain join check validation. This is useful for integration and - // functional-tests but should not be set for any non-test use-case. - envSkipDomainJoinCheck = "ZZZ_SKIP_DOMAIN_JOIN_CHECK_NOT_SUPPORTED_IN_PRODUCTION" - // envSkipWindowsServerVersionCheck is an environment setting that can be used // to skip the windows server version check. This is useful for testing and // should not be set for any non-test use-case. diff --git a/ecs-init/config/common.go b/ecs-init/config/common.go index d0acc580be2..f27e78cee66 100644 --- a/ecs-init/config/common.go +++ b/ecs-init/config/common.go @@ -93,6 +93,12 @@ const ( // DefaultRegionEnvVar is the environment variable for specifying the default AWS region to use. DefaultRegionEnvVar = "AWS_DEFAULT_REGION" + + // ECSGMSASupportEnvVar indicates that the gMSA is supported + ECSGMSASupportEnvVar = "ECS_GMSA_SUPPORTED" + + // CredentialsFetcherHostEnvVar is the environment variable that specifies the location of the credentials-fetcher daemon socket. + CredentialsFetcherHostEnvVar = "CREDENTIALS_FETCHER_HOST" ) // partitionBucketRegion provides the "partitional" bucket region @@ -212,6 +218,23 @@ func DockerUnixSocket() (string, bool) { return "/var/run", false } +// CredentialsFetcherUnixSocket returns the credentials fetcher daemon socket endpoint and whether it reads from CredentialsFetcherEnvVar +func CredentialsFetcherUnixSocket() (string, bool) { + if credentialsFetcherHost := os.Getenv(CredentialsFetcherHostEnvVar); strings.HasPrefix(credentialsFetcherHost, UnixSocketPrefix) { + return strings.TrimPrefix(credentialsFetcherHost, UnixSocketPrefix), true + } + + return "/var/credentials-fetcher/socket/credentials_fetcher.sock", false +} + +// HostCredentialsFetcherPath() returns the daemon socket location if it is available +func HostCredentialsFetcherPath() string { + if credentialsFetcherHost, _ := CredentialsFetcherUnixSocket(); len(credentialsFetcherHost) > 0 { + return credentialsFetcherHost + } + return "" +} + // CgroupMountpoint returns the cgroup mountpoint for the system func CgroupMountpoint() string { return cgroupMountpoint diff --git a/ecs-init/config/common_test.go b/ecs-init/config/common_test.go index a86ae325d8d..94ea0bc3aa7 100644 --- a/ecs-init/config/common_test.go +++ b/ecs-init/config/common_test.go @@ -253,3 +253,30 @@ func TestAgentRunningInExternal(t *testing.T) { defer os.Unsetenv(ExternalEnvVar) assert.True(t, RunningInExternal()) } + +func TestCredentialsFetcherUnixSocketWithoutCredentialsFetcherHost(t *testing.T) { + // Make sure that the env variable is not set + os.Unsetenv("CREDENTIALS_FETCHER_HOST") + + credentialsFetcherUnixSocketSourcePath, fromEnv := CredentialsFetcherUnixSocket() + + if credentialsFetcherUnixSocketSourcePath != "/var/credentials-fetcher/socket/credentials_fetcher.sock" { + t.Error("CredentialsFetcherUnixSocket() should be \"/var/credentials-fetcher/socket\"") + } + if fromEnv { + t.Error("CredentialsFetcherUnixSocket() should return the default instead of reading from CREDENTIALS_FETCHER_HOST when CREDENTIALS_FETCHER_HOST isn't set") + } +} + +func TestCredentialsFetcherUnixSocketWithCredentialsFetcherHost(t *testing.T) { + os.Setenv("CREDENTIALS_FETCHER_HOST", "unix:///foo/bar") + defer os.Unsetenv("CREDENTIALS_FETCHER_HOST") + + credentialsFetcherUnixSocketSourcePath, fromEnv := CredentialsFetcherUnixSocket() + if credentialsFetcherUnixSocketSourcePath != "/foo/bar" { + t.Error("CredentialsFetcherUnixSocket() should be \"/foo/bar\"") + } + if !fromEnv { + t.Error("CredentialsFetcherUnixSocket() should read from environment variable CREDENTIALS_FETCHER_HOST, when CREDENTIALS_FETCHER_HOST is set") + } +} diff --git a/ecs-init/docker/docker.go b/ecs-init/docker/docker.go index f43e54bfcb1..3fa2a925cdd 100644 --- a/ecs-init/docker/docker.go +++ b/ecs-init/docker/docker.go @@ -18,6 +18,7 @@ import ( "encoding/json" "io" "os" + "os/exec" "path/filepath" "strings" "sync" @@ -49,6 +50,10 @@ const ( // in case /var/run/docker.sock is deleted and recreated outside the container defaultDockerEndpoint = "/var/run" defaultDockerSocketPath = "/var/run/docker.sock" + // this socket is exposed by credentials-fetcher (daemon for gMSA support on Linux) + // defaultCredentialsFetcherSocketPath is set to /var/credentials-fetcher/socket/credentials_fetcher.sock + // in case path is not passed in the env variable + defaultCredentialsFetcherSocketPath = "/var/credentials-fetcher/socket/credentials_fetcher.sock" // networkMode specifies the networkmode to create the agent container networkMode = "host" @@ -298,11 +303,21 @@ func (c *client) getContainerConfig(envVarsFromFiles map[string]string) *godocke envVariables["SSL_CERT_DIR"] = certDir } + // env variable is only available if the gmsa is enabled on linux + if credentialsFetcherHost := config.HostCredentialsFetcherPath(); credentialsFetcherHost != "" { + envVariables["CREDENTIALS_FETCHER_HOST_DIR"] = credentialsFetcherHost + } + // merge in platform-specific environment variables for envKey, envValue := range getPlatformSpecificEnvVariables() { envVariables[envKey] = envValue } + if isDomainJoined() { + // set the environment variable to true if the container instance is domain joined + envVariables["ECS_DOMAIN_JOINED_LINUX_INSTANCE"] = "true" + } + for key, val := range envVarsFromFiles { envVariables[key] = val } @@ -430,6 +445,14 @@ func (c *client) getHostConfig(envVarsFromFiles map[string]string) *godocker.Hos binds = append(binds, gpu.GPUInfoDirPath+":"+gpu.GPUInfoDirPath) } } + + if key == config.ECSGMSASupportEnvVar && val == "true" { + // only bind if the env variable gmsa support is set to true and the path to bind exists + credentialsfetcherSocketBind, volumeExists := getCredentialsFetcherSocketBind(envVarsFromFiles) + if volumeExists { + binds = append(binds, credentialsfetcherSocketBind) + } + } } binds = append(binds, getDockerPluginDirBinds()...) @@ -440,6 +463,33 @@ func (c *client) getHostConfig(envVarsFromFiles map[string]string) *godocker.Hos return createHostConfig(binds) } +// getCredentialsFetcherSocketBind returns the bind for CredentialsFetcher socket and also whether the bind exists. +// Value for the bind is as follow: +// CREDENTIALS_FETCHER_HOST (as in os.Getenv) set: source CREDENTIALS_FETCHER_HOST (as in os.Getenv, trim unix:// prefix), +// dest CREDENTIALS_FETCHER_HOST (as in /etc/ecs/ecs.config, trim unix:// prefix) +func getCredentialsFetcherSocketBind(envVarsFromFiles map[string]string) (string, bool) { + CredentialsFetcherEndpointAgent := defaultCredentialsFetcherSocketPath + CredentialsFetcherUnixSocketSourcePath, fromEnv := config.CredentialsFetcherUnixSocket() + if fromEnv { + credentialsFetcherEndpointConfig, ok := envVarsFromFiles[config.CredentialsFetcherHostEnvVar] + if ok && strings.HasPrefix(credentialsFetcherEndpointConfig, config.UnixSocketPrefix) { + CredentialsFetcherEndpointAgent = strings.TrimPrefix(credentialsFetcherEndpointConfig, config.UnixSocketPrefix) + } else { + CredentialsFetcherEndpointAgent = defaultCredentialsFetcherSocketPath + } + } + + // check whether the path to the mount exists + _, err := os.Stat(CredentialsFetcherUnixSocketSourcePath) + if err != nil { + if os.IsNotExist(err) { + return CredentialsFetcherUnixSocketSourcePath + ":" + CredentialsFetcherEndpointAgent, false + } + } + + return CredentialsFetcherUnixSocketSourcePath + ":" + CredentialsFetcherEndpointAgent, true +} + // getDockerSocketBind returns the bind for Docker socket. // Value for the bind is as follow: // 1. DOCKER_HOST (as in os.Getenv) not set: source /var/run, dest /var/run @@ -541,3 +591,32 @@ func (c *client) StopAgent() error { } return err } + +// isDomainJoined is used to validate if container instance is part of a valid active directory. +func isDomainJoined() bool { + realmPath, err := exec.LookPath("realm") + if err != nil { + log.Errorf("realmd is not installed on the instance") + return false + } + + if len(realmPath) == 0 { + log.Errorf("could not path of realm on the instance") + return false + } + + realmCommmand := realmPath + " list" + realmCmdOutput, err := exec.Command("bash", "-c", realmCommmand).Output() + if err != nil { + log.Errorf("failed to read realm info") + return false + } + + realmOutputStr := strings.TrimSpace(string(realmCmdOutput)) + if !strings.Contains(realmOutputStr, "realm-name") { + log.Errorf("couldn't not find realm name") + return false + } + + return true +} diff --git a/ecs-init/docker/docker_test.go b/ecs-init/docker/docker_test.go index 73ecb1b0ea2..f37d11079a4 100644 --- a/ecs-init/docker/docker_test.go +++ b/ecs-init/docker/docker_test.go @@ -985,3 +985,53 @@ func TestDefaultIsPathValid(t *testing.T) { }) } } + +func TestGetCredentialsFetcherSocketBind(t *testing.T) { + testCases := []struct { + name string + credentialsFetcherHostFromEnv string + credentialsFetcherHostFromConfigFile string + expectedBind string + }{ + { + name: "No Credentials Fetcher host from env", + credentialsFetcherHostFromEnv: "", + credentialsFetcherHostFromConfigFile: "dummy", + expectedBind: "/var/credentials-fetcher/socket/credentials_fetcher.sock:/var/credentials-fetcher/socket/credentials_fetcher.sock", + }, + { + name: "Invalid Credentials Fetcher host from env", + credentialsFetcherHostFromEnv: "invalid", + credentialsFetcherHostFromConfigFile: "dummy", + expectedBind: "/var/credentials-fetcher/socket/credentials_fetcher.sock:/var/credentials-fetcher/socket/credentials_fetcher.sock", + }, + { + name: "Credentials Fetcher from env, no Credentials Fetcher from config file", + credentialsFetcherHostFromEnv: "unix:///var/credentials-fetcher/socket/credentials_fetcher.sock", + credentialsFetcherHostFromConfigFile: "", + expectedBind: "/var/credentials-fetcher/socket/credentials_fetcher.sock:/var/credentials-fetcher/socket/credentials_fetcher.sock", + }, + { + name: "Credentials Fetcher from env, invalid Credentials Fetcher from config file", + credentialsFetcherHostFromEnv: "unix:///var/credentials-fetcher/socket/credentials_fetcher.sock", + credentialsFetcherHostFromConfigFile: "invalid", + expectedBind: "/var/credentials-fetcher/socket/credentials_fetcher.sock:/var/credentials-fetcher/socket/credentials_fetcher.sock", + }, + { + name: "Credentials Fetcher host from env, Credentials Fetcher from config file", + credentialsFetcherHostFromEnv: "unix:///var/credentials-fetcher/socket/credentials_fetcher.sock.1", + credentialsFetcherHostFromConfigFile: "unix:///var/credentials-fetcher/socket/credentials_fetcher.sock.1", + expectedBind: "/var/credentials-fetcher/socket/credentials_fetcher.sock.1:/var/credentials-fetcher/socket/credentials_fetcher.sock.1", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + os.Setenv("CREDENTIALS_FETCHER_HOST", tc.credentialsFetcherHostFromEnv) + defer os.Unsetenv("CREDENTIALS_FETCHER_HOST") + + bind, _ := getCredentialsFetcherSocketBind(map[string]string{"CREDENTIALS_FETCHER_HOST": tc.credentialsFetcherHostFromConfigFile}) + assert.Equal(t, tc.expectedBind, bind) + }) + } +}