Skip to content
This repository has been archived by the owner on Oct 24, 2023. It is now read-only.

fix: prepend https:// in service-account-issuer flag #4262

Merged
merged 2 commits into from
Mar 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/topics/clusterdefinitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ Below is a list of apiserver options that AKS Engine will configure by default:
| "--oidc-groups-claim" | "groups" (_if has AADProfile_) |
| "--oidc-client-id" | _calculated value that represents OID client ID_ (_if has AADProfile_) |
| "--oidc-issuer-url" | _calculated value that represents OID issuer URL_ (_if has AADProfile_) |
| "--service-account-issuer" | "kubernetes.default.svc" (Kubernetes v1.20.0 and greater only) |
| "--service-account-issuer" | "https://kubernetes.default.svc.cluster.local" (Kubernetes v1.20.0 and greater only) |
| "--service-account-signing-key-file" | "/etc/kubernetes/certs/apiserver.key" (Kubernetes v1.20.0 and greater only) |

`*` In Kubernetes versions 1.10.0 and later the `--admission-control` flag is deprecated and `--enable-admission-plugins` is used instead.
Expand Down
7 changes: 6 additions & 1 deletion pkg/api/defaults-apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func (cs *ContainerService) setAPIServerConfig() {
}

if common.IsKubernetesVersionGe(o.OrchestratorVersion, "1.20.0-alpha.1") {
defaultAPIServerConfig["--service-account-issuer"] = "kubernetes.default.svc"
defaultAPIServerConfig["--service-account-issuer"] = "https://kubernetes.default.svc.cluster.local"
defaultAPIServerConfig["--service-account-signing-key-file"] = "/etc/kubernetes/certs/apiserver.key"
}

Expand Down Expand Up @@ -156,6 +156,11 @@ func (cs *ContainerService) setAPIServerConfig() {
delete(o.KubernetesConfig.APIServerConfig, key)
}
}

// Manual override of "--service-account-issuer" starting with 1.20
if common.IsKubernetesVersionGe(o.OrchestratorVersion, "1.20.0-alpha.1") && o.KubernetesConfig.APIServerConfig["--service-account-issuer"] == "kubernetes.default.svc" {
o.KubernetesConfig.APIServerConfig["--service-account-issuer"] = "https://kubernetes.default.svc.cluster.local"
}
}

func getDefaultAdmissionControls(cs *ContainerService) (string, string) {
Expand Down
13 changes: 12 additions & 1 deletion pkg/api/defaults-apiserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ func TestAPIServerServiceAccountFlags(t *testing.T) {
cs := CreateMockContainerService("testcluster", common.RationalizeReleaseAndVersion(Kubernetes, "1.20", "", false, false, false), 3, 2, false)
cs.setAPIServerConfig()
a := cs.Properties.OrchestratorProfile.KubernetesConfig.APIServerConfig
if a["--service-account-issuer"] != "kubernetes.default.svc" {
if a["--service-account-issuer"] != "https://kubernetes.default.svc.cluster.local" {
t.Fatalf("got unexpected '--service-account-issuer' API server config value for Kubernetes v1.20: %s",
a["--service-account-issuer"])
}
Expand All @@ -308,6 +308,17 @@ func TestAPIServerServiceAccountFlags(t *testing.T) {
t.Fatalf("got unexpected '--service-account-signing-key-file' API server config value for Kubernetes v1.20: %s",
a["--service-account-signing-key-file"])
}

cs = CreateMockContainerService("testcluster", common.RationalizeReleaseAndVersion(Kubernetes, "1.20", "", false, false, false), 3, 2, false)
cs.Properties.OrchestratorProfile.KubernetesConfig.APIServerConfig = map[string]string{
"--service-account-issuer": "kubernetes.default.svc",
}
cs.setAPIServerConfig()
a = cs.Properties.OrchestratorProfile.KubernetesConfig.APIServerConfig
if a["--service-account-issuer"] != "https://kubernetes.default.svc.cluster.local" {
t.Fatalf("got unexpected '--service-account-issuer' API server config value for Kubernetes v1.20: %s",
a["--service-account-issuer"])
}
}

func TestAPIServerConfigEnableSecureKubelet(t *testing.T) {
Expand Down
54 changes: 54 additions & 0 deletions test/e2e/kubernetes/kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ package kubernetes
import (
"bufio"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"log"
"math"
"math/rand"
"net/url"
"os"
"os/exec"
"path/filepath"
Expand Down Expand Up @@ -1512,6 +1515,57 @@ var _ = Describe("Azure Container Cluster using the Kubernetes Orchestrator", fu
}
}
})

It("should have the correct service account issuer when consuming a projected service account token", func() {
if !common.IsKubernetesVersionGe(eng.ExpandedDefinition.Properties.OrchestratorProfile.OrchestratorVersion, "1.20.0") {
Skip("Service account token volume projection is not available prior to Kubernetes 1.20")
}

By("Launching a pod with a projected service account token")
p, err := pod.CreatePodFromFileWithRetry(filepath.Join(WorkloadDir, "pod-projected-svc-token.yaml"), "nginx", "default", 1*time.Second, cfg.Timeout)
Expect(err).NotTo(HaveOccurred())

ready, err := p.WaitOnReady(true, sleepBetweenRetriesWhenWaitingForPodReady, cfg.Timeout)
Expect(err).NotTo(HaveOccurred())
Expect(ready).To(Equal(true))

By("Obtaining the projected service account token")
tokenPath := "/var/run/secrets/tokens/token"
nodeList, err := node.Get()
for _, n := range nodeList.Nodes {
if n.Metadata.Name == p.Spec.NodeName && n.IsWindows() {
tokenPath = "C:\\var\\run\\secrets\\tokens\\token"
break
}
}
out, err := p.Exec("--", "cat", tokenPath)
Expect(err).NotTo(HaveOccurred())

By("Decoding the service account token")
// out is a JWT token, which has 3 parts joined by "."
s := strings.Split(string(out), ".")
Expect(s).To(HaveLen(3))
// the payload is the second element
data, err := base64.StdEncoding.WithPadding(base64.NoPadding).DecodeString(s[1])
Expect(err).NotTo(HaveOccurred())

var payload struct {
Issuer string `json:"iss"`
}
err = json.Unmarshal(data, &payload)
Expect(err).NotTo(HaveOccurred())

svcIssuer := eng.ExpandedDefinition.Properties.OrchestratorProfile.KubernetesConfig.APIServerConfig["--service-account-issuer"]
By("Ensuring that the service account issuer matches the token issuer")
Expect(payload.Issuer).To(Equal(svcIssuer))

By("Ensuring that the service account issuer has a https scheme")
u, err := url.Parse(svcIssuer)
Expect(err).NotTo(HaveOccurred())
// Service account issuer for OIDC requires https scheme to work.
// See https://github.com/Azure/aks-engine/pull/4262 for more detail.
Expect(u.Scheme).To(Equal("https"))
})
})

Describe("with a windows agent pool", func() {
Expand Down
18 changes: 18 additions & 0 deletions test/e2e/kubernetes/workloads/pod-projected-svc-token.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: k8s.gcr.io/e2e-test-images/nginx:1.14-1
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nginx test image we use upstream, which supports both Linux and Windows.

name: nginx
volumeMounts:
- mountPath: /var/run/secrets/tokens
name: token
volumes:
- name: token
projected:
sources:
- serviceAccountToken:
path: token
expirationSeconds: 7200