Merge pull request #93258 from zshihang/token

mv TokenRequest and TokenRequestProjection to GA
This commit is contained in:
Kubernetes Prow Robot 2020-10-30 16:36:51 -07:00 committed by GitHub
commit bf67247124
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 254 additions and 327 deletions

View File

@ -18905,6 +18905,32 @@
"version": "unversioned"
},
"paths": {
"/.well-known/openid-configuration/": {
"get": {
"description": "get service account issuer OpenID configuration, also known as the 'OIDC discovery doc'",
"operationId": "getServiceAccountIssuerOpenIDConfiguration",
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"401": {
"description": "Unauthorized"
}
},
"schemes": [
"https"
],
"tags": [
"WellKnown"
]
}
},
"/api/": {
"get": {
"consumes": [
@ -105104,6 +105130,32 @@
}
]
},
"/openid/v1/jwks/": {
"get": {
"description": "get service account issuer OpenID JSON Web Key Set (contains public token verification keys)",
"operationId": "getServiceAccountIssuerOpenIDKeyset",
"produces": [
"application/jwk-set+json"
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"401": {
"description": "Unauthorized"
}
},
"schemes": [
"https"
],
"tags": [
"openid"
]
}
},
"/version/": {
"get": {
"consumes": [

View File

@ -270,7 +270,7 @@ func (s *ServerRunOptions) Flags() (fss cliflag.NamedFlagSets) {
"Turns on aggregator routing requests to endpoints IP rather than cluster IP.")
fs.StringVar(&s.ServiceAccountSigningKeyFile, "service-account-signing-key-file", s.ServiceAccountSigningKeyFile, ""+
"Path to the file that contains the current private key of the service account token issuer. The issuer will sign issued ID tokens with this private key. (Requires the 'TokenRequest' feature gate.)")
"Path to the file that contains the current private key of the service account token issuer. The issuer will sign issued ID tokens with this private key.")
return fss
}

View File

@ -120,14 +120,6 @@ func validateTokenRequest(options *ServerRunOptions) []error {
enableSucceeded := options.ServiceAccountIssuer != nil
if enableAttempted && !utilfeature.DefaultFeatureGate.Enabled(features.TokenRequest) {
errs = append(errs, errors.New("the TokenRequest feature is not enabled but --service-account-signing-key-file, --service-account-issuer and/or --api-audiences flags were passed"))
}
if utilfeature.DefaultFeatureGate.Enabled(features.BoundServiceAccountTokenVolume) && !utilfeature.DefaultFeatureGate.Enabled(features.TokenRequest) {
errs = append(errs, errors.New("the BoundServiceAccountTokenVolume feature depends on the TokenRequest feature, but the TokenRequest features is not enabled"))
}
if !enableAttempted && utilfeature.DefaultFeatureGate.Enabled(features.BoundServiceAccountTokenVolume) {
errs = append(errs, errors.New("--service-account-signing-key-file and --service-account-issuer are required flags"))
}

View File

@ -39,7 +39,6 @@ import (
"k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/healthz"
"k8s.io/apiserver/pkg/server/mux"
utilfeature "k8s.io/apiserver/pkg/util/feature"
cacheddiscovery "k8s.io/client-go/discovery/cached"
"k8s.io/client-go/informers"
clientset "k8s.io/client-go/kubernetes"
@ -67,7 +66,6 @@ import (
"k8s.io/kubernetes/pkg/controller"
kubectrlmgrconfig "k8s.io/kubernetes/pkg/controller/apis/config"
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/serviceaccount"
)
@ -621,9 +619,6 @@ func readCA(file string) ([]byte, error) {
}
func shouldTurnOnDynamicClient(client clientset.Interface) bool {
if !utilfeature.DefaultFeatureGate.Enabled(features.TokenRequest) {
return false
}
apiResourceList, err := client.Discovery().ServerResourcesForGroupVersion(v1.SchemeGroupVersion.String())
if err != nil {
klog.Warningf("fetch api resource lists failed, use legacy client builder: %v", err)

View File

@ -137,6 +137,8 @@ func getAPIServerCommand(cfg *kubeadmapi.ClusterConfiguration, localAPIEndpoint
"enable-admission-plugins": "NodeRestriction",
"service-cluster-ip-range": cfg.Networking.ServiceSubnet,
"service-account-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPublicKeyName),
"service-account-signing-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPrivateKeyName),
"service-account-issuer": fmt.Sprintf("https://kubernetes.default.svc.%s", cfg.Networking.DNSDomain),
"client-ca-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName),
"tls-cert-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerCertName),
"tls-private-key-file": filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKeyName),

View File

@ -197,7 +197,7 @@ func TestGetAPIServerCommand(t *testing.T) {
{
name: "testing defaults",
cfg: &kubeadmapi.ClusterConfiguration{
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar", DNSDomain: "cluster.local"},
CertificatesDir: testCertsDir,
},
endpoint: &kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "1.2.3.4"},
@ -207,6 +207,8 @@ func TestGetAPIServerCommand(t *testing.T) {
"--enable-admission-plugins=NodeRestriction",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--service-account-signing-key-file=" + testCertsDir + "/sa.key",
"--service-account-issuer=https://kubernetes.default.svc.cluster.local",
"--client-ca-file=" + testCertsDir + "/ca.crt",
"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
@ -234,7 +236,7 @@ func TestGetAPIServerCommand(t *testing.T) {
{
name: "ipv6 advertise address",
cfg: &kubeadmapi.ClusterConfiguration{
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar", DNSDomain: "cluster.local"},
CertificatesDir: testCertsDir,
},
endpoint: &kubeadmapi.APIEndpoint{BindPort: 123, AdvertiseAddress: "2001:db8::1"},
@ -244,6 +246,8 @@ func TestGetAPIServerCommand(t *testing.T) {
"--enable-admission-plugins=NodeRestriction",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--service-account-signing-key-file=" + testCertsDir + "/sa.key",
"--service-account-issuer=https://kubernetes.default.svc.cluster.local",
"--client-ca-file=" + testCertsDir + "/ca.crt",
"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
@ -271,7 +275,7 @@ func TestGetAPIServerCommand(t *testing.T) {
{
name: "an external etcd with custom ca, certs and keys",
cfg: &kubeadmapi.ClusterConfiguration{
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar", DNSDomain: "cluster.local"},
Etcd: kubeadmapi.Etcd{
External: &kubeadmapi.ExternalEtcd{
Endpoints: []string{"https://[2001:abcd:bcda::1]:2379", "https://[2001:abcd:bcda::2]:2379"},
@ -289,6 +293,8 @@ func TestGetAPIServerCommand(t *testing.T) {
"--enable-admission-plugins=NodeRestriction",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--service-account-signing-key-file=" + testCertsDir + "/sa.key",
"--service-account-issuer=https://kubernetes.default.svc.cluster.local",
"--client-ca-file=" + testCertsDir + "/ca.crt",
"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
@ -316,7 +322,7 @@ func TestGetAPIServerCommand(t *testing.T) {
{
name: "an insecure etcd",
cfg: &kubeadmapi.ClusterConfiguration{
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar", DNSDomain: "cluster.local"},
Etcd: kubeadmapi.Etcd{
External: &kubeadmapi.ExternalEtcd{
Endpoints: []string{"http://[::1]:2379", "http://[::1]:2380"},
@ -331,6 +337,8 @@ func TestGetAPIServerCommand(t *testing.T) {
"--enable-admission-plugins=NodeRestriction",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--service-account-signing-key-file=" + testCertsDir + "/sa.key",
"--service-account-issuer=https://kubernetes.default.svc.cluster.local",
"--client-ca-file=" + testCertsDir + "/ca.crt",
"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
@ -355,7 +363,7 @@ func TestGetAPIServerCommand(t *testing.T) {
{
name: "test APIServer.ExtraArgs works as expected",
cfg: &kubeadmapi.ClusterConfiguration{
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar", DNSDomain: "cluster.local"},
CertificatesDir: testCertsDir,
APIServer: kubeadmapi.APIServer{
ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
@ -375,6 +383,8 @@ func TestGetAPIServerCommand(t *testing.T) {
"--enable-admission-plugins=NodeRestriction",
"--service-cluster-ip-range=baz",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--service-account-signing-key-file=" + testCertsDir + "/sa.key",
"--service-account-issuer=https://kubernetes.default.svc.cluster.local",
"--client-ca-file=" + testCertsDir + "/ca.crt",
"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
@ -404,7 +414,7 @@ func TestGetAPIServerCommand(t *testing.T) {
{
name: "authorization-mode extra-args ABAC",
cfg: &kubeadmapi.ClusterConfiguration{
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar", DNSDomain: "cluster.local"},
CertificatesDir: testCertsDir,
APIServer: kubeadmapi.APIServer{
ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
@ -421,6 +431,8 @@ func TestGetAPIServerCommand(t *testing.T) {
"--enable-admission-plugins=NodeRestriction",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--service-account-signing-key-file=" + testCertsDir + "/sa.key",
"--service-account-issuer=https://kubernetes.default.svc.cluster.local",
"--client-ca-file=" + testCertsDir + "/ca.crt",
"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
@ -448,7 +460,7 @@ func TestGetAPIServerCommand(t *testing.T) {
{
name: "insecure-port extra-args",
cfg: &kubeadmapi.ClusterConfiguration{
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar", DNSDomain: "cluster.local"},
CertificatesDir: testCertsDir,
APIServer: kubeadmapi.APIServer{
ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
@ -465,6 +477,8 @@ func TestGetAPIServerCommand(t *testing.T) {
"--enable-admission-plugins=NodeRestriction",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--service-account-signing-key-file=" + testCertsDir + "/sa.key",
"--service-account-issuer=https://kubernetes.default.svc.cluster.local",
"--client-ca-file=" + testCertsDir + "/ca.crt",
"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
@ -492,7 +506,7 @@ func TestGetAPIServerCommand(t *testing.T) {
{
name: "authorization-mode extra-args Webhook",
cfg: &kubeadmapi.ClusterConfiguration{
Networking: kubeadmapi.Networking{ServiceSubnet: "bar"},
Networking: kubeadmapi.Networking{ServiceSubnet: "bar", DNSDomain: "cluster.local"},
CertificatesDir: testCertsDir,
APIServer: kubeadmapi.APIServer{
ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{
@ -513,6 +527,8 @@ func TestGetAPIServerCommand(t *testing.T) {
"--enable-admission-plugins=NodeRestriction",
"--service-cluster-ip-range=bar",
"--service-account-key-file=" + testCertsDir + "/sa.pub",
"--service-account-signing-key-file=" + testCertsDir + "/sa.key",
"--service-account-issuer=https://kubernetes.default.svc.cluster.local",
"--client-ca-file=" + testCertsDir + "/ca.crt",
"--tls-cert-file=" + testCertsDir + "/apiserver.crt",
"--tls-private-key-file=" + testCertsDir + "/apiserver.key",
@ -628,7 +644,7 @@ func TestGetControllerManagerCommand(t *testing.T) {
{
name: "custom cluster-cidr for " + cpVersion,
cfg: &kubeadmapi.ClusterConfiguration{
Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16"},
Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16", DNSDomain: "cluster.local"},
CertificatesDir: testCertsDir,
KubernetesVersion: cpVersion,
},
@ -657,7 +673,9 @@ func TestGetControllerManagerCommand(t *testing.T) {
cfg: &kubeadmapi.ClusterConfiguration{
Networking: kubeadmapi.Networking{
PodSubnet: "10.0.1.15/16",
ServiceSubnet: "172.20.0.0/24"},
ServiceSubnet: "172.20.0.0/24",
DNSDomain: "cluster.local",
},
CertificatesDir: testCertsDir,
KubernetesVersion: cpVersion,
},
@ -685,7 +703,7 @@ func TestGetControllerManagerCommand(t *testing.T) {
{
name: "custom extra-args for " + cpVersion,
cfg: &kubeadmapi.ClusterConfiguration{
Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16"},
Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16", DNSDomain: "cluster.local"},
ControllerManager: kubeadmapi.ControlPlaneComponent{
ExtraArgs: map[string]string{"node-cidr-mask-size": "20"},
},
@ -719,7 +737,9 @@ func TestGetControllerManagerCommand(t *testing.T) {
Networking: kubeadmapi.Networking{
PodSubnet: "2001:db8::/64",
ServiceSubnet: "fd03::/112",
DNSDomain: "cluster.local",
},
CertificatesDir: testCertsDir,
KubernetesVersion: cpVersion,
},
@ -750,6 +770,7 @@ func TestGetControllerManagerCommand(t *testing.T) {
Networking: kubeadmapi.Networking{
PodSubnet: "2001:db8::/64,10.1.0.0/16",
ServiceSubnet: "fd03::/112,192.168.0.0/16",
DNSDomain: "cluster.local",
},
CertificatesDir: testCertsDir,
KubernetesVersion: cpVersion,
@ -780,7 +801,10 @@ func TestGetControllerManagerCommand(t *testing.T) {
{
name: "dual-stack networking custom extra-args for " + cpVersion,
cfg: &kubeadmapi.ClusterConfiguration{
Networking: kubeadmapi.Networking{PodSubnet: "10.0.1.15/16,2001:db8::/64"},
Networking: kubeadmapi.Networking{
PodSubnet: "10.0.1.15/16,2001:db8::/64",
DNSDomain: "cluster.local",
},
ControllerManager: kubeadmapi.ControlPlaneComponent{
ExtraArgs: map[string]string{"node-cidr-mask-size-ipv4": "20", "node-cidr-mask-size-ipv6": "80"},
},

View File

@ -34,6 +34,15 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
source "${KUBE_ROOT}/hack/lib/test.sh"
source "${KUBE_ROOT}/test/cmd/legacy-script.sh"
# setup envs for TokenRequest required flags
SERVICE_ACCOUNT_LOOKUP=${SERVICE_ACCOUNT_LOOKUP:-true}
SERVICE_ACCOUNT_KEY=${SERVICE_ACCOUNT_KEY:-/tmp/kube-serviceaccount.key}
# Generate ServiceAccount key if needed
if [[ ! -f "${SERVICE_ACCOUNT_KEY}" ]]; then
mkdir -p "$(dirname "${SERVICE_ACCOUNT_KEY}")"
openssl genrsa -out "${SERVICE_ACCOUNT_KEY}" 2048 2>/dev/null
fi
# Runs kube-apiserver
#
# Exports:
@ -64,6 +73,10 @@ function run_kube_apiserver() {
--disable-admission-plugins="${DISABLE_ADMISSION_PLUGINS}" \
--etcd-servers="http://${ETCD_HOST}:${ETCD_PORT}" \
--runtime-config=api/v1 \
--service-account-key-file="${SERVICE_ACCOUNT_KEY}" \
--service-account-lookup="${SERVICE_ACCOUNT_LOOKUP}" \
--service-account-issuer="https://kubernetes.default.svc" \
--service-account-signing-key-file="${SERVICE_ACCOUNT_KEY}" \
--storage-media-type="${KUBE_TEST_API_STORAGE_TYPE-}" \
--cert-dir="${TMPDIR:-/tmp/}" \
--service-cluster-ip-range="10.0.0.0/24" \

View File

@ -58,6 +58,15 @@ kube::etcd::start
echo "dummy_token,admin,admin" > "${TMP_DIR}/tokenauth.csv"
# setup envs for TokenRequest required flags
SERVICE_ACCOUNT_LOOKUP=${SERVICE_ACCOUNT_LOOKUP:-true}
SERVICE_ACCOUNT_KEY=${SERVICE_ACCOUNT_KEY:-/tmp/kube-serviceaccount.key}
# Generate ServiceAccount key if needed
if [[ ! -f "${SERVICE_ACCOUNT_KEY}" ]]; then
mkdir -p "$(dirname "${SERVICE_ACCOUNT_KEY}")"
openssl genrsa -out "${SERVICE_ACCOUNT_KEY}" 2048 2>/dev/null
fi
# Start kube-apiserver
kube::log::status "Starting kube-apiserver"
"${KUBE_OUTPUT_HOSTBIN}/kube-apiserver" \
@ -69,8 +78,10 @@ kube::log::status "Starting kube-apiserver"
--runtime-config="api/all=true" \
--token-auth-file="${TMP_DIR}/tokenauth.csv" \
--authorization-mode=RBAC \
--service-account-issuer="https://kubernetes.default.svc/" \
--service-account-signing-key-file="${KUBE_ROOT}/staging/src/k8s.io/client-go/util/cert/testdata/dontUseThisKey.pem" \
--service-account-key-file="${SERVICE_ACCOUNT_KEY}" \
--service-account-lookup="${SERVICE_ACCOUNT_LOOKUP}" \
--service-account-issuer="https://kubernetes.default.svc" \
--service-account-signing-key-file="${SERVICE_ACCOUNT_KEY}" \
--logtostderr \
--v=2 \
--service-cluster-ip-range="10.0.0.0/24" >"${API_LOGFILE}" 2>&1 &

View File

@ -19,7 +19,7 @@ package pod
import (
"strings"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
api "k8s.io/kubernetes/pkg/apis/core"
@ -349,18 +349,6 @@ func dropDisabledFields(
podSpec = &api.PodSpec{}
}
if !utilfeature.DefaultFeatureGate.Enabled(features.TokenRequestProjection) &&
!tokenRequestProjectionInUse(oldPodSpec) {
for i := range podSpec.Volumes {
if podSpec.Volumes[i].Projected != nil {
for j := range podSpec.Volumes[i].Projected.Sources {
podSpec.Volumes[i].Projected.Sources[j].ServiceAccountToken = nil
}
}
}
}
if !utilfeature.DefaultFeatureGate.Enabled(features.AppArmor) && !appArmorInUse(oldPodAnnotations) {
for k := range podAnnotations {
if strings.HasPrefix(k, v1.AppArmorBetaContainerAnnotationKeyPrefix) {
@ -593,23 +581,6 @@ func appArmorInUse(podAnnotations map[string]string) bool {
return false
}
func tokenRequestProjectionInUse(podSpec *api.PodSpec) bool {
if podSpec == nil {
return false
}
for _, v := range podSpec.Volumes {
if v.Projected == nil {
continue
}
for _, s := range v.Projected.Sources {
if s.ServiceAccountToken != nil {
return true
}
}
}
return false
}
// podPriorityInUse returns true if the pod spec is non-nil and has Priority or PriorityClassName set.
func podPriorityInUse(podSpec *api.PodSpec) bool {
if podSpec == nil {

View File

@ -24,7 +24,7 @@ import (
"github.com/google/go-cmp/cmp"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/diff"
@ -1106,122 +1106,6 @@ func TestDropAppArmor(t *testing.T) {
}
}
func TestDropTokenRequestProjection(t *testing.T) {
podWithoutTRProjection := func() *api.Pod {
return &api.Pod{
Spec: api.PodSpec{
Volumes: []api.Volume{{
VolumeSource: api.VolumeSource{
Projected: &api.ProjectedVolumeSource{
Sources: []api.VolumeProjection{{
ServiceAccountToken: nil,
}},
}}},
},
},
}
}
podWithoutProjectedVolumeSource := func() *api.Pod {
return &api.Pod{
Spec: api.PodSpec{
Volumes: []api.Volume{
{VolumeSource: api.VolumeSource{
ConfigMap: &api.ConfigMapVolumeSource{},
}},
},
},
}
}
podWithTRProjection := func() *api.Pod {
return &api.Pod{
Spec: api.PodSpec{
Volumes: []api.Volume{{
VolumeSource: api.VolumeSource{
Projected: &api.ProjectedVolumeSource{
Sources: []api.VolumeProjection{{
ServiceAccountToken: &api.ServiceAccountTokenProjection{
Audience: "api",
ExpirationSeconds: 3600,
Path: "token",
}},
}},
},
},
},
}}
}
podInfo := []struct {
description string
hasTRProjection bool
pod func() *api.Pod
}{
{
description: "has TokenRequestProjection",
hasTRProjection: true,
pod: podWithTRProjection,
},
{
description: "does not have TokenRequestProjection",
hasTRProjection: false,
pod: podWithoutTRProjection,
},
{
description: "does not have ProjectedVolumeSource",
hasTRProjection: false,
pod: podWithoutProjectedVolumeSource,
},
{
description: "is nil",
hasTRProjection: false,
pod: func() *api.Pod { return nil },
},
}
for _, enabled := range []bool{true, false} {
for _, oldPodInfo := range podInfo {
for _, newPodInfo := range podInfo {
oldPodhasTRProjection, oldPod := oldPodInfo.hasTRProjection, oldPodInfo.pod()
newPodhasTRProjection, newPod := newPodInfo.hasTRProjection, newPodInfo.pod()
if newPod == nil {
continue
}
t.Run(fmt.Sprintf("feature enabled=%v, old pod %v, new pod %v", enabled, oldPodInfo.description, newPodInfo.description), func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TokenRequestProjection, enabled)()
var oldPodSpec *api.PodSpec
if oldPod != nil {
oldPodSpec = &oldPod.Spec
}
dropDisabledFields(&newPod.Spec, nil, oldPodSpec, nil)
// old pod should never be changed
if !reflect.DeepEqual(oldPod, oldPodInfo.pod()) {
t.Errorf("old pod changed: %v", diff.ObjectReflectDiff(oldPod, oldPodInfo.pod()))
}
switch {
case enabled || oldPodhasTRProjection:
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
t.Errorf("new pod changed: %v", diff.ObjectReflectDiff(newPod, newPodInfo.pod()))
}
case newPodhasTRProjection:
// new pod should be changed
if reflect.DeepEqual(newPod, newPodInfo.pod()) {
t.Errorf("%v", oldPod)
t.Errorf("%v", newPod)
t.Errorf("new pod was not changed")
}
if !reflect.DeepEqual(newPod, podWithoutTRProjection()) {
t.Errorf("new pod had Tokenrequestprojection: %v", diff.ObjectReflectDiff(newPod, podWithoutTRProjection()))
}
default:
// new pod should not need to be changed
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
t.Errorf("new pod changed: %v", diff.ObjectReflectDiff(newPod, newPodInfo.pod()))
}
}
})
}
}
}
}
func TestDropRunAsGroup(t *testing.T) {
group := func() *int64 {
testGroup := int64(1000)

View File

@ -211,12 +211,14 @@ const (
// owner: @mikedanese
// beta: v1.12
// ga: v1.20
//
// Implement TokenRequest endpoint on service account resources.
TokenRequest featuregate.Feature = "TokenRequest"
// owner: @mikedanese
// beta: v1.12
// ga: v1.20
//
// Enable ServiceAccountTokenVolumeProjection support in ProjectedVolumes.
TokenRequestProjection featuregate.Feature = "TokenRequestProjection"
@ -686,8 +688,8 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
SupportPodPidsLimit: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.21
SupportNodePidsLimit: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.21
HyperVContainer: {Default: false, PreRelease: featuregate.Deprecated},
TokenRequest: {Default: true, PreRelease: featuregate.Beta},
TokenRequestProjection: {Default: true, PreRelease: featuregate.Beta},
TokenRequest: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.21
TokenRequestProjection: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.21
BoundServiceAccountTokenVolume: {Default: false, PreRelease: featuregate.Alpha},
ServiceAccountIssuerDiscovery: {Default: true, PreRelease: featuregate.Beta},
CRIContainerLogRotation: {Default: true, PreRelease: featuregate.Beta},

View File

@ -10,7 +10,6 @@ go_library(
srcs = ["config.go"],
importpath = "k8s.io/kubernetes/pkg/kubeapiserver/authenticator",
deps = [
"//pkg/features:go_default_library",
"//pkg/serviceaccount:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
@ -26,7 +25,6 @@ go_library(
"//staging/src/k8s.io/apiserver/pkg/authentication/token/tokenfile:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/token/union:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/server/dynamiccertificates:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc:go_default_library",
"//staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook:go_default_library",
"//staging/src/k8s.io/client-go/plugin/pkg/client/auth:go_default_library",

View File

@ -35,14 +35,12 @@ import (
"k8s.io/apiserver/pkg/authentication/token/tokenfile"
tokenunion "k8s.io/apiserver/pkg/authentication/token/union"
"k8s.io/apiserver/pkg/server/dynamiccertificates"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/apiserver/plugin/pkg/authenticator/token/oidc"
"k8s.io/apiserver/plugin/pkg/authenticator/token/webhook"
// Initialize all known client auth plugins.
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/client-go/util/keyutil"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/serviceaccount"
)
@ -127,7 +125,7 @@ func (config Config) New() (authenticator.Request, *spec.SecurityDefinitions, er
}
tokenAuthenticators = append(tokenAuthenticators, serviceAccountAuth)
}
if utilfeature.DefaultFeatureGate.Enabled(features.TokenRequest) && config.ServiceAccountIssuer != "" {
if config.ServiceAccountIssuer != "" {
serviceAccountAuth, err := newServiceAccountAuthenticator(config.ServiceAccountIssuer, config.ServiceAccountKeyFiles, config.APIAudiences, config.ServiceAccountTokenGetter)
if err != nil {
return nil, nil, err

View File

@ -192,10 +192,6 @@ func (o *BuiltInAuthenticationOptions) Validate() []error {
}
}
if o.ServiceAccounts != nil && utilfeature.DefaultFeatureGate.Enabled(features.BoundServiceAccountTokenVolume) {
if !utilfeature.DefaultFeatureGate.Enabled(features.TokenRequest) || !utilfeature.DefaultFeatureGate.Enabled(features.TokenRequestProjection) {
allErrors = append(allErrors, errors.New("if the BoundServiceAccountTokenVolume feature is enabled,"+
" the TokenRequest and TokenRequestProjection features must also be enabled"))
}
if len(o.ServiceAccounts.Issuer) == 0 {
allErrors = append(allErrors, errors.New("service-account-issuer is a required flag when BoundServiceAccountTokenVolume is enabled"))
}
@ -313,7 +309,7 @@ func (o *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
"that this value comply with the OpenID spec: https://openid.net/specs/openid-connect-discovery-1_0.html. "+
"In practice, this means that service-account-issuer must be an https URL. It is also highly "+
"recommended that this URL be capable of serving OpenID discovery documents at "+
"`{service-account-issuer}/.well-known/openid-configuration`.")
"{service-account-issuer}/.well-known/openid-configuration.")
fs.StringVar(&o.ServiceAccounts.JWKSURI, "service-account-jwks-uri", o.ServiceAccounts.JWKSURI, ""+
"Overrides the URI for the JSON Web Key Set in the discovery doc served at "+
@ -464,14 +460,13 @@ func (o *BuiltInAuthenticationOptions) ApplyTo(authInfo *genericapiserver.Authen
authInfo.APIAudiences = authenticator.Audiences{o.ServiceAccounts.Issuer}
}
if o.ServiceAccounts.Lookup || utilfeature.DefaultFeatureGate.Enabled(features.TokenRequest) {
authenticatorConfig.ServiceAccountTokenGetter = serviceaccountcontroller.NewGetterFromClient(
extclient,
versionedInformer.Core().V1().Secrets().Lister(),
versionedInformer.Core().V1().ServiceAccounts().Lister(),
versionedInformer.Core().V1().Pods().Lister(),
)
}
authenticatorConfig.BootstrapTokenAuthenticator = bootstrap.NewTokenAuthenticator(
versionedInformer.Core().V1().Secrets().Lister().Secrets(metav1.NamespaceSystem),
)

View File

@ -181,7 +181,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi
}
var serviceAccountStorage *serviceaccountstore.REST
if c.ServiceAccountIssuer != nil && utilfeature.DefaultFeatureGate.Enabled(features.TokenRequest) {
if c.ServiceAccountIssuer != nil {
serviceAccountStorage, err = serviceaccountstore.NewREST(restOptionsGetter, c.ServiceAccountIssuer, c.APIAudiences, c.ServiceAccountMaxExpiration, podStorage.Pod.Store, secretStorage.Store, c.ExtendExpiration)
} else {
serviceAccountStorage, err = serviceaccountstore.NewREST(restOptionsGetter, nil, nil, 0, nil, nil, false)

View File

@ -36,7 +36,6 @@ go_library(
srcs = ["projected.go"],
importpath = "k8s.io/kubernetes/pkg/volume/projected",
deps = [
"//pkg/features:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/configmap:go_default_library",
"//pkg/volume/downwardapi:go_default_library",
@ -48,7 +47,6 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//vendor/k8s.io/klog/v2:go_default_library",
"//vendor/k8s.io/utils/strings:go_default_library",
],

View File

@ -25,9 +25,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/klog/v2"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/configmap"
"k8s.io/kubernetes/pkg/volume/downwardapi"
@ -322,10 +320,6 @@ func (s *projectedVolumeMounter) collectData(mounterArgs volume.MounterArgs) (ma
payload[k] = v
}
case source.ServiceAccountToken != nil:
if !utilfeature.DefaultFeatureGate.Enabled(features.TokenRequestProjection) {
errlist = append(errlist, fmt.Errorf("pod request ServiceAccountToken projection but the TokenRequestProjection feature was not enabled"))
continue
}
tp := source.ServiceAccountToken
// When FsGroup is set, we depend on SetVolumeOwnership to

View File

@ -71,7 +71,6 @@ type Plugin struct {
podsGetter corev1lister.PodLister
nodesGetter corev1lister.NodeLister
tokenRequestEnabled bool
csiNodeInfoEnabled bool
expandPersistentVolumesEnabled bool
}
@ -84,7 +83,6 @@ var (
// InspectFeatureGates allows setting bools without taking a dep on a global variable
func (p *Plugin) InspectFeatureGates(featureGates featuregate.FeatureGate) {
p.tokenRequestEnabled = featureGates.Enabled(features.TokenRequest)
p.csiNodeInfoEnabled = featureGates.Enabled(features.CSINodeInfo)
p.expandPersistentVolumesEnabled = featureGates.Enabled(features.ExpandPersistentVolumes)
}
@ -159,10 +157,7 @@ func (p *Plugin) Admit(ctx context.Context, a admission.Attributes, o admission.
}
case svcacctResource:
if p.tokenRequestEnabled {
return p.admitServiceAccount(nodeName, a)
}
return nil
case leaseResource:
return p.admitLease(nodeName, a)

View File

@ -48,7 +48,6 @@ import (
)
var (
trEnabledFeature = featuregate.NewFeatureGate()
csiNodeInfoEnabledFeature = featuregate.NewFeatureGate()
csiNodeInfoDisabledFeature = featuregate.NewFeatureGate()
)
@ -56,15 +55,12 @@ var (
func init() {
// all features need to be set on all featuregates for the tests. We set everything and then then the if's below override it.
relevantFeatures := map[featuregate.Feature]featuregate.FeatureSpec{
features.TokenRequest: {Default: false},
features.CSINodeInfo: {Default: false},
features.ExpandPersistentVolumes: {Default: false},
}
utilruntime.Must(trEnabledFeature.Add(relevantFeatures))
utilruntime.Must(csiNodeInfoEnabledFeature.Add(relevantFeatures))
utilruntime.Must(csiNodeInfoDisabledFeature.Add(relevantFeatures))
utilruntime.Must(trEnabledFeature.SetFromMap(map[string]bool{string(features.TokenRequest): true}))
utilruntime.Must(csiNodeInfoEnabledFeature.SetFromMap(map[string]bool{string(features.CSINodeInfo): true}))
}
@ -1086,35 +1082,30 @@ func Test_nodePlugin_Admit(t *testing.T) {
{
name: "forbid create of unbound token",
podsGetter: noExistingPods,
features: trEnabledFeature,
attributes: admission.NewAttributesRecord(makeTokenRequest("", ""), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
err: "not bound to a pod",
},
{
name: "forbid create of token bound to nonexistant pod",
podsGetter: noExistingPods,
features: trEnabledFeature,
attributes: admission.NewAttributesRecord(makeTokenRequest("nopod", "someuid"), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
err: "not found",
},
{
name: "forbid create of token bound to pod without uid",
podsGetter: existingPods,
features: trEnabledFeature,
attributes: admission.NewAttributesRecord(makeTokenRequest(coremypod.Name, ""), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
err: "pod binding without a uid",
},
{
name: "forbid create of token bound to pod scheduled on another node",
podsGetter: existingPods,
features: trEnabledFeature,
attributes: admission.NewAttributesRecord(makeTokenRequest(coreotherpod.Name, coreotherpod.UID), nil, tokenrequestKind, coreotherpod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
err: "pod scheduled on a different node",
},
{
name: "allow create of token bound to pod scheduled this node",
podsGetter: existingPods,
features: trEnabledFeature,
attributes: admission.NewAttributesRecord(makeTokenRequest(coremypod.Name, coremypod.UID), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
},

View File

@ -123,10 +123,7 @@ func (r *NodeAuthorizer) Authorize(ctx context.Context, attrs authorizer.Attribu
case vaResource:
return r.authorizeGet(nodeName, vaVertexType, attrs)
case svcAcctResource:
if r.features.Enabled(features.TokenRequest) {
return r.authorizeCreateToken(nodeName, serviceAccountVertexType, attrs)
}
return authorizer.DecisionNoOpinion, fmt.Sprintf("disabled by feature gate %s", features.TokenRequest), nil
case leaseResource:
return r.authorizeLease(nodeName, attrs)
case csiNodeResource:

View File

@ -42,19 +42,11 @@ import (
)
var (
trEnabledFeature = featuregate.NewFeatureGate()
trDisabledFeature = featuregate.NewFeatureGate()
csiNodeInfoEnabledFeature = featuregate.NewFeatureGate()
csiNodeInfoDisabledFeature = featuregate.NewFeatureGate()
)
func init() {
if err := trEnabledFeature.Add(map[featuregate.Feature]featuregate.FeatureSpec{features.TokenRequest: {Default: true}}); err != nil {
panic(err)
}
if err := trDisabledFeature.Add(map[featuregate.Feature]featuregate.FeatureSpec{features.TokenRequest: {Default: false}}); err != nil {
panic(err)
}
if err := csiNodeInfoEnabledFeature.Add(map[featuregate.Feature]featuregate.FeatureSpec{features.CSINodeInfo: {Default: true}}); err != nil {
panic(err)
}
@ -189,33 +181,23 @@ func TestAuthorizer(t *testing.T) {
expect: authorizer.DecisionAllow,
},
{
name: "allowed svcacct token create - feature enabled",
name: "allowed svcacct token create",
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "create", Resource: "serviceaccounts", Subresource: "token", Name: "svcacct0-node0", Namespace: "ns0"},
features: trEnabledFeature,
expect: authorizer.DecisionAllow,
},
{
name: "disallowed svcacct token create - serviceaccount not attached to node",
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "create", Resource: "serviceaccounts", Subresource: "token", Name: "svcacct0-node1", Namespace: "ns0"},
features: trEnabledFeature,
expect: authorizer.DecisionNoOpinion,
},
{
name: "disallowed svcacct token create - feature disabled",
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "create", Resource: "serviceaccounts", Subresource: "token", Name: "svcacct0-node0", Namespace: "ns0"},
features: trDisabledFeature,
expect: authorizer.DecisionNoOpinion,
},
{
name: "disallowed svcacct token create - no subresource",
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "create", Resource: "serviceaccounts", Name: "svcacct0-node0", Namespace: "ns0"},
features: trEnabledFeature,
expect: authorizer.DecisionNoOpinion,
},
{
name: "disallowed svcacct token create - non create",
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "update", Resource: "serviceaccounts", Subresource: "token", Name: "svcacct0-node0", Namespace: "ns0"},
features: trEnabledFeature,
expect: authorizer.DecisionNoOpinion,
},
{

View File

@ -153,6 +153,10 @@ func NodeRules() []rbacv1.PolicyRule {
// CSI
rbacv1helpers.NewRule("get").Groups(storageGroup).Resources("volumeattachments").RuleOrDie(),
// Use the Node authorization to limit a node to create tokens for service accounts running on that node
// Use the NodeRestriction admission plugin to limit a node to create tokens bound to pods on that node
rbacv1helpers.NewRule("create").Groups(legacyGroup).Resources("serviceaccounts/token").RuleOrDie(),
}
if utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) {
@ -162,13 +166,6 @@ func NodeRules() []rbacv1.PolicyRule {
nodePolicyRules = append(nodePolicyRules, pvcStatusPolicyRule)
}
if utilfeature.DefaultFeatureGate.Enabled(features.TokenRequest) {
// Use the Node authorization to limit a node to create tokens for service accounts running on that node
// Use the NodeRestriction admission plugin to limit a node to create tokens bound to pods on that node
tokenRequestRule := rbacv1helpers.NewRule("create").Groups(legacyGroup).Resources("serviceaccounts/token").RuleOrDie()
nodePolicyRules = append(nodePolicyRules, tokenRequestRule)
}
// CSI
csiDriverRule := rbacv1helpers.NewRule("get", "watch", "list").Groups("storage.k8s.io").Resources("csidrivers").RuleOrDie()
nodePolicyRules = append(nodePolicyRules, csiDriverRule)

View File

@ -1018,6 +1018,12 @@ items:
- volumeattachments
verbs:
- get
- apiGroups:
- ""
resources:
- serviceaccounts/token
verbs:
- create
- apiGroups:
- ""
resources:
@ -1026,12 +1032,6 @@ items:
- get
- patch
- update
- apiGroups:
- ""
resources:
- serviceaccounts/token
verbs:
- create
- apiGroups:
- storage.k8s.io
resources:

View File

@ -41,6 +41,7 @@ import (
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
imageutils "k8s.io/kubernetes/test/utils/image"
utilptr "k8s.io/utils/pointer"
"github.com/onsi/ginkgo"
)
@ -418,6 +419,59 @@ var _ = SIGDescribe("ServiceAccounts", func() {
}
})
/*
Release : v1.20
Testname: TokenRequestProjection should mount a projected volume with token using TokenRequest API.
Description: Ensure that projected service account token is mounted.
*/
ginkgo.It("should mount projected service account token when requested", func() {
var (
podName = "test-pod-" + string(uuid.NewUUID())
volumeName = "test-volume"
volumeMountPath = "/test-volume"
tokenVolumePath = "/test-volume/token"
)
volumes := []v1.Volume{
{
Name: volumeName,
VolumeSource: v1.VolumeSource{
Projected: &v1.ProjectedVolumeSource{
Sources: []v1.VolumeProjection{
{
ServiceAccountToken: &v1.ServiceAccountTokenProjection{
Path: "token",
ExpirationSeconds: utilptr.Int64Ptr(60 * 60),
},
},
},
},
},
},
}
volumeMounts := []v1.VolumeMount{
{
Name: volumeName,
MountPath: volumeMountPath,
ReadOnly: true,
},
}
mounttestArgs := []string{
"mounttest",
fmt.Sprintf("--file_content=%v", tokenVolumePath),
}
pod := e2epod.NewAgnhostPod(f.Namespace.Name, podName, volumes, volumeMounts, nil, mounttestArgs...)
pod.Spec.RestartPolicy = v1.RestartPolicyNever
output := []string{
fmt.Sprintf("content of file \"%v\": %s", tokenVolumePath, `[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*`),
}
f.TestContainerOutputRegexp("service account token: ", pod, 0, output)
})
/*
Testname: Projected service account token file ownership and permission.
Description: Ensure that Projected Service Account Token is mounted with
@ -431,24 +485,17 @@ var _ = SIGDescribe("ServiceAccounts", func() {
Containers MUST verify that the projected service account token can be
read and has correct file mode set including ownership and permission.
*/
ginkgo.It("should set ownership and permission when RunAsUser or FsGroup is present [LinuxOnly] [NodeFeature:FSGroup] [Feature:TokenRequestProjection]", func() {
ginkgo.It("should set ownership and permission when RunAsUser or FsGroup is present [LinuxOnly] [NodeFeature:FSGroup]", func() {
e2eskipper.SkipIfNodeOSDistroIs("windows")
var (
podName = "test-pod-" + string(uuid.NewUUID())
containerName = "test-container"
volumeName = "test-volume"
volumeMountPath = "/test-volume"
tokenVolumePath = "/test-volume/token"
int64p = func(i int64) *int64 { return &i }
)
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: podName,
},
Spec: v1.PodSpec{
Volumes: []v1.Volume{
volumes := []v1.Volume{
{
Name: volumeName,
VolumeSource: v1.VolumeSource{
@ -457,36 +504,31 @@ var _ = SIGDescribe("ServiceAccounts", func() {
{
ServiceAccountToken: &v1.ServiceAccountTokenProjection{
Path: "token",
ExpirationSeconds: int64p(60 * 60),
ExpirationSeconds: utilptr.Int64Ptr(60 * 60),
},
},
},
},
},
},
},
Containers: []v1.Container{
}
volumeMounts := []v1.VolumeMount{
{
Name: containerName,
Image: imageutils.GetE2EImage(imageutils.Agnhost),
Args: []string{
Name: volumeName,
MountPath: volumeMountPath,
ReadOnly: true,
},
}
mounttestArgs := []string{
"mounttest",
fmt.Sprintf("--file_perm=%v", tokenVolumePath),
fmt.Sprintf("--file_owner=%v", tokenVolumePath),
fmt.Sprintf("--file_content=%v", tokenVolumePath),
},
VolumeMounts: []v1.VolumeMount{
{
Name: volumeName,
MountPath: volumeMountPath,
},
},
},
},
RestartPolicy: v1.RestartPolicyNever,
},
}
pod := e2epod.NewAgnhostPod(f.Namespace.Name, podName, volumes, volumeMounts, nil, mounttestArgs...)
pod.Spec.RestartPolicy = v1.RestartPolicyNever
testcases := []struct {
runAsUser bool
fsGroup bool
@ -531,7 +573,7 @@ var _ = SIGDescribe("ServiceAccounts", func() {
output := []string{
fmt.Sprintf("perms of file \"%v\": %s", tokenVolumePath, tc.wantPerm),
fmt.Sprintf("content of file \"%v\": %s", tokenVolumePath, ".+"),
fmt.Sprintf("content of file \"%v\": %s", tokenVolumePath, `[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*`),
fmt.Sprintf("owner UID of \"%v\": %d", tokenVolumePath, tc.wantUID),
fmt.Sprintf("owner GID of \"%v\": %d", tokenVolumePath, tc.wantGID),
}
@ -539,7 +581,7 @@ var _ = SIGDescribe("ServiceAccounts", func() {
}
})
ginkgo.It("should support InClusterConfig with token rotation [Slow] [Feature:TokenRequestProjection]", func() {
ginkgo.It("should support InClusterConfig with token rotation [Slow]", func() {
cfg, err := framework.LoadConfig()
framework.ExpectNoError(err)

View File

@ -26,21 +26,16 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
utilfeature "k8s.io/apiserver/pkg/util/feature"
clientset "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
featuregatetesting "k8s.io/component-base/featuregate/testing"
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
"k8s.io/kubernetes/pkg/controller"
"k8s.io/kubernetes/pkg/controlplane"
"k8s.io/kubernetes/pkg/features"
kubeoptions "k8s.io/kubernetes/pkg/kubeapiserver/options"
"k8s.io/kubernetes/test/integration/framework"
)
func TestDynamicClientBuilder(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TokenRequest, true)()
tmpfile, err := ioutil.TempFile("/tmp", "key")
if err != nil {
t.Fatalf("create temp file failed: %v", err)

View File

@ -64,7 +64,6 @@ AwEHoUQDQgAEH6cuzP8XuD5wal6wf9M6xDljTOPLX2i8uIp/C/ASqiIGUeeKQtX0
-----END EC PRIVATE KEY-----`
func TestServiceAccountTokenCreate(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TokenRequest, true)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceAccountIssuerDiscovery, true)()
// Build client config, clientset, and informers