Skip to content

Commit 7e2225c

Browse files
authored
Do not wrap Kubernetes Address in brackets (#4363)
Signed-off-by: maksim.nabokikh <max.nabokih@gmail.com>
1 parent 9207486 commit 7e2225c

File tree

2 files changed

+87
-16
lines changed

2 files changed

+87
-16
lines changed

storage/kubernetes/client.go

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ import (
3232
"github.com/dexidp/dex/storage/kubernetes/k8sapi"
3333
)
3434

35+
const (
36+
serviceAccountPath = "/var/run/secrets/kubernetes.io/serviceaccount/"
37+
serviceAccountTokenPath = serviceAccountPath + "token"
38+
serviceAccountCAPath = serviceAccountPath + "ca.crt"
39+
serviceAccountNamespacePath = serviceAccountPath + "namespace"
40+
41+
kubernetesServiceHostENV = "KUBERNETES_SERVICE_HOST"
42+
kubernetesServicePortENV = "KUBERNETES_SERVICE_PORT"
43+
kubernetesPodNamespaceENV = "KUBERNETES_POD_NAMESPACE"
44+
)
45+
3546
type client struct {
3647
client *http.Client
3748
baseURL string
@@ -508,33 +519,35 @@ func getInClusterConfigNamespace(token, namespaceENV, namespacePath string) (str
508519
return "", fmt.Errorf("%v: trying to get namespace from file: %v", err, fileErr)
509520
}
510521

511-
func inClusterConfig() (k8sapi.Cluster, k8sapi.AuthInfo, string, error) {
512-
const (
513-
serviceAccountPath = "/var/run/secrets/kubernetes.io/serviceaccount/"
514-
serviceAccountTokenPath = serviceAccountPath + "token"
515-
serviceAccountCAPath = serviceAccountPath + "ca.crt"
516-
serviceAccountNamespacePath = serviceAccountPath + "namespace"
517-
518-
kubernetesServiceHostENV = "KUBERNETES_SERVICE_HOST"
519-
kubernetesServicePortENV = "KUBERNETES_SERVICE_PORT"
520-
kubernetesPodNamespaceENV = "KUBERNETES_POD_NAMESPACE"
521-
)
522-
523-
host, port := os.Getenv(kubernetesServiceHostENV), os.Getenv(kubernetesServicePortENV)
522+
func getInClusterConnectOptions(host, port string) (k8sapi.Cluster, error) {
524523
if len(host) == 0 || len(port) == 0 {
525-
return k8sapi.Cluster{}, k8sapi.AuthInfo{}, "", fmt.Errorf(
524+
return k8sapi.Cluster{}, fmt.Errorf(
526525
"unable to load in-cluster configuration, %s and %s must be defined",
527526
kubernetesServiceHostENV,
528527
kubernetesServicePortENV,
529528
)
530529
}
530+
531531
// we need to wrap IPv6 addresses in square brackets
532-
// IPv4 also works with square brackets
533-
host = "[" + host + "]"
532+
// IPv4 used to work with square brackets, but it was fixed in the latest Go versions
533+
// https://github.com/golang/go/issues/75712
534+
ipAddr := net.ParseIP(host)
535+
if ipAddr != nil && ipAddr.To4() == nil {
536+
host = "[" + host + "]"
537+
}
538+
534539
cluster := k8sapi.Cluster{
535540
Server: "https://" + host + ":" + port,
536541
CertificateAuthority: serviceAccountCAPath,
537542
}
543+
return cluster, nil
544+
}
545+
546+
func inClusterConfig() (k8sapi.Cluster, k8sapi.AuthInfo, string, error) {
547+
cluster, err := getInClusterConnectOptions(os.Getenv(kubernetesServiceHostENV), os.Getenv(kubernetesServicePortENV))
548+
if err != nil {
549+
return cluster, k8sapi.AuthInfo{}, "", err
550+
}
538551

539552
token, err := os.ReadFile(serviceAccountTokenPath)
540553
if err != nil {

storage/kubernetes/client_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"testing"
1212
"time"
1313

14+
"github.com/stretchr/testify/assert"
1415
"github.com/stretchr/testify/require"
1516

1617
"github.com/dexidp/dex/storage/kubernetes/k8sapi"
@@ -216,6 +217,63 @@ func TestGetClusterConfigNamespace(t *testing.T) {
216217
}
217218
}
218219

220+
func TestGetInClusterConnectOptions(t *testing.T) {
221+
type testCase struct {
222+
name string
223+
host string
224+
port string
225+
expectedURL string
226+
expectError bool
227+
}
228+
229+
testCases := []testCase{
230+
{
231+
name: "valid IPv4",
232+
host: "10.1.1.1",
233+
port: "443",
234+
expectedURL: "https://10.1.1.1:443",
235+
},
236+
{
237+
name: "valid IPv6",
238+
host: "fd00::1",
239+
port: "8443",
240+
expectedURL: "https://[fd00::1]:8443",
241+
},
242+
{
243+
name: "valid DNS name",
244+
host: "kubernetes.default.svc",
245+
port: "443",
246+
expectedURL: "https://kubernetes.default.svc:443",
247+
},
248+
{
249+
name: "empty host",
250+
host: "",
251+
port: "443",
252+
expectError: true,
253+
},
254+
{
255+
name: "empty port",
256+
host: "127.0.0.1",
257+
port: "",
258+
expectError: true,
259+
},
260+
}
261+
262+
for _, tc := range testCases {
263+
t.Run(tc.name, func(t *testing.T) {
264+
cluster, err := getInClusterConnectOptions(tc.host, tc.port)
265+
266+
if tc.expectError {
267+
assert.Error(t, err)
268+
return
269+
}
270+
require.NoError(t, err)
271+
assert.Equal(t, tc.expectedURL, cluster.Server)
272+
assert.Equal(t, "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt", cluster.CertificateAuthority)
273+
})
274+
}
275+
}
276+
219277
const serviceAccountToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZXgtdGVzdC1uYW1lc3BhY2UiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlY3JldC5uYW1lIjoiZG90aGVyb2JvdC1zZWNyZXQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZG90aGVyb2JvdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjQyYjJhOTRmLTk4MjAtMTFlNi1iZDc0LTJlZmQzOGYxMjYxYyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZXgtdGVzdC1uYW1lc3BhY2U6ZG90aGVyb2JvdCJ9.KViBpPwCiBwxDvAjYUUXoVvLVwqV011aLlYQpNtX12Bh8M-QAFch-3RWlo_SR00bcdFg_nZo9JKACYlF_jHMEsf__PaYms9r7vEaSg0jPfkqnL2WXZktzQRyLBr0n-bxeUrbwIWsKOAC0DfFB5nM8XoXljRmq8yAx8BAdmQp7MIFb4EOV9nYthhua6pjzYyaFSiDiYTjw7HtXOvoL8oepodJ3-37pUKS8vdBvnvUoqC4M1YAhkO5L36JF6KV_RfmG8GPEdNQfXotHcsR-3jKi1n8S5l7Xd-rhrGOhSGQizH3dORzo9GvBAhYeqbq1O-NLzm2EQUiMQayIUx7o4g3Kw"
220278

221279
// The following program was used to generate the example token. Since we don't want to

0 commit comments

Comments
 (0)