diff --git a/docs/tutorials/coredns.md b/docs/tutorials/coredns.md index 13d7877576..bc673494c5 100644 --- a/docs/tutorials/coredns.md +++ b/docs/tutorials/coredns.md @@ -86,6 +86,7 @@ helm install --name my-coredns --values values.yaml stable/coredns ## Installing ExternalDNS ### Install external ExternalDNS ETCD_URLS is configured to etcd client service address. +Optionnally, you can configure ETCD_USERNAME and ETCD_PASSWORD for authenticating to etcd. #### Manifest (for clusters without RBAC enabled) diff --git a/provider/coredns/coredns.go b/provider/coredns/coredns.go index a514ca8659..eeb545aea5 100644 --- a/provider/coredns/coredns.go +++ b/provider/coredns/coredns.go @@ -205,8 +205,10 @@ func getETCDConfig() (*etcdcv3.Config, error) { } etcdURLs := strings.Split(etcdURLsStr, ",") firstURL := strings.ToLower(etcdURLs[0]) + etcdUsername := os.Getenv("ETCD_USERNAME") + etcdPassword := os.Getenv("ETCD_PASSWORD") if strings.HasPrefix(firstURL, "http://") { - return &etcdcv3.Config{Endpoints: etcdURLs}, nil + return &etcdcv3.Config{Endpoints: etcdURLs, Username: etcdUsername, Password: etcdPassword}, nil } else if strings.HasPrefix(firstURL, "https://") { caFile := os.Getenv("ETCD_CA_FILE") certFile := os.Getenv("ETCD_CERT_FILE") @@ -221,6 +223,8 @@ func getETCDConfig() (*etcdcv3.Config, error) { return &etcdcv3.Config{ Endpoints: etcdURLs, TLS: tlsConfig, + Username: etcdUsername, + Password: etcdPassword, }, nil } else { return nil, errors.New("etcd URLs must start with either http:// or https://") diff --git a/provider/coredns/coredns_test.go b/provider/coredns/coredns_test.go index 8c9aa8f9d6..baf5652f8e 100644 --- a/provider/coredns/coredns_test.go +++ b/provider/coredns/coredns_test.go @@ -18,9 +18,12 @@ package coredns import ( "context" + "os" + "reflect" "strings" "testing" + etcdcv3 "go.etcd.io/etcd/client/v3" "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/plan" @@ -55,6 +58,68 @@ func (c fakeETCDClient) DeleteService(key string) error { return nil } +func TestETCDConfig(t *testing.T) { + var tests = []struct { + name string + input map[string]string + want *etcdcv3.Config + }{ + { + "default config", + map[string]string{}, + &etcdcv3.Config{Endpoints: []string{"http://localhost:2379"}}, + }, + { + "config with ETCD_URLS", + map[string]string{"ETCD_URLS": "http://example.com:2379"}, + &etcdcv3.Config{Endpoints: []string{"http://example.com:2379"}}, + }, + { + "config with ETCD_USERNAME and ETCD_PASSWORD", + map[string]string{"ETCD_USERNAME": "root", "ETCD_PASSWORD": "test"}, + &etcdcv3.Config{ + Endpoints: []string{"http://localhost:2379"}, + Username: "root", + Password: "test", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + closer := envSetter(tt.input) + cfg, _ := getETCDConfig() + if !reflect.DeepEqual(cfg, tt.want) { + t.Errorf("unexpected config. Got %v, want %v", cfg, tt.want) + } + t.Cleanup(closer) + }) + } + +} + +func envSetter(envs map[string]string) (closer func()) { + originalEnvs := map[string]string{} + + for name, value := range envs { + if originalValue, ok := os.LookupEnv(name); ok { + originalEnvs[name] = originalValue + } + _ = os.Setenv(name, value) + } + + return func() { + for name := range envs { + origValue, has := originalEnvs[name] + if has { + _ = os.Setenv(name, origValue) + } else { + _ = os.Unsetenv(name) + } + } + } +} + func TestAServiceTranslation(t *testing.T) { expectedTarget := "1.2.3.4" expectedDNSName := "example.com"