Fresh dep ensure

This commit is contained in:
Mike Cronce
2018-11-26 13:23:56 -05:00
parent 93cb8a04d7
commit 407478ab9a
9016 changed files with 551394 additions and 279685 deletions

View File

@ -17,23 +17,25 @@ go_test(
"rbac_test.go",
"svcaccttoken_test.go",
],
data = [
"//staging/src/k8s.io/csi-api/pkg/crd:csi-manifests",
],
tags = ["integration"],
deps = [
"//cmd/kube-apiserver/app/testing:go_default_library",
"//pkg/api/legacyscheme:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/apis/authorization:go_default_library",
"//pkg/apis/autoscaling:go_default_library",
"//pkg/apis/coordination:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/policy:go_default_library",
"//pkg/apis/rbac:go_default_library",
"//pkg/auth/authorizer/abac:go_default_library",
"//pkg/auth/nodeidentifier:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
"//pkg/controller/serviceaccount:go_default_library",
"//pkg/features:go_default_library",
"//pkg/kubeapiserver/authorizer:go_default_library",
"//pkg/master:go_default_library",
"//pkg/registry/rbac/clusterrole:go_default_library",
"//pkg/registry/rbac/clusterrole/storage:go_default_library",
@ -44,46 +46,53 @@ go_test(
"//pkg/registry/rbac/rolebinding:go_default_library",
"//pkg/registry/rbac/rolebinding/storage:go_default_library",
"//pkg/serviceaccount:go_default_library",
"//plugin/pkg/admission/noderestriction:go_default_library",
"//plugin/pkg/auth/authenticator/token/bootstrap:go_default_library",
"//plugin/pkg/auth/authorizer/rbac:go_default_library",
"//staging/src/k8s.io/api/authentication/v1:go_default_library",
"//staging/src/k8s.io/api/authentication/v1beta1:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/storage/v1beta1:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/group:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/request/bearertoken:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/serviceaccount:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/token/cache:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/token/tokenfile:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizerfactory:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library",
"//staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/tokentest:go_default_library",
"//staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/client-go/tools/clientcmd/api/v1:go_default_library",
"//staging/src/k8s.io/client-go/tools/watch:go_default_library",
"//staging/src/k8s.io/client-go/transport:go_default_library",
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
"//staging/src/k8s.io/cluster-bootstrap/token/api:go_default_library",
"//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library",
"//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library",
"//test/e2e/lifecycle/bootstrap:go_default_library",
"//test/integration:go_default_library",
"//test/integration/etcd:go_default_library",
"//test/integration/framework:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/gopkg.in/square/go-jose.v2/jwt:go_default_library",
"//vendor/k8s.io/api/authentication/v1:go_default_library",
"//vendor/k8s.io/api/authentication/v1beta1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/storage/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/group:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/request/bearertoken:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/serviceaccount:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/token/tokenfile:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/generic:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature/testing:go_default_library",
"//vendor/k8s.io/apiserver/plugin/pkg/authenticator/token/tokentest:go_default_library",
"//vendor/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook:go_default_library",
"//vendor/k8s.io/client-go/informers:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/tools/bootstrap/token/api:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd/api/v1:go_default_library",
"//vendor/k8s.io/client-go/transport:go_default_library",
"//vendor/k8s.io/client-go/util/cert:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/utils/pointer:go_default_library",
],
)

View File

@ -46,9 +46,11 @@ func (sarAuthorizer) Authorize(a authorizer.Attributes) (authorizer.Decision, st
return authorizer.DecisionAllow, "you're not dave", nil
}
func alwaysAlice(req *http.Request) (user.Info, bool, error) {
return &user.DefaultInfo{
Name: "alice",
func alwaysAlice(req *http.Request) (*authenticator.Response, bool, error) {
return &authenticator.Response{
User: &user.DefaultInfo{
Name: "alice",
},
}, true, nil
}
@ -145,8 +147,10 @@ func TestSubjectAccessReview(t *testing.T) {
func TestSelfSubjectAccessReview(t *testing.T) {
username := "alice"
masterConfig := framework.NewIntegrationTestMasterConfig()
masterConfig.GenericConfig.Authentication.Authenticator = authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
return &user.DefaultInfo{Name: username}, true, nil
masterConfig.GenericConfig.Authentication.Authenticator = authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
return &authenticator.Response{
User: &user.DefaultInfo{Name: username},
}, true, nil
})
masterConfig.GenericConfig.Authorization.Authorizer = sarAuthorizer{}
_, s, closeFn := framework.RunAMaster(masterConfig)

View File

@ -40,6 +40,7 @@ import (
"k8s.io/apiserver/pkg/authentication/group"
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
"k8s.io/apiserver/pkg/authentication/serviceaccount"
"k8s.io/apiserver/pkg/authentication/token/cache"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
@ -84,11 +85,11 @@ func getTestWebhookTokenAuth(serverURL string) (authenticator.Request, error) {
if err := json.NewEncoder(kubecfgFile).Encode(config); err != nil {
return nil, err
}
webhookTokenAuth, err := webhook.New(kubecfgFile.Name(), 2*time.Minute)
webhookTokenAuth, err := webhook.New(kubecfgFile.Name(), nil)
if err != nil {
return nil, err
}
return bearertoken.New(webhookTokenAuth), nil
return bearertoken.New(cache.New(webhookTokenAuth, false, 2*time.Minute, 2*time.Minute)), nil
}
func path(resource, namespace, name string) string {
@ -397,7 +398,7 @@ func getTestRequests(namespace string) []struct {
return requests
}
// The TestAuthMode* tests tests a large number of URLs and checks that they
// The TestAuthMode* tests a large number of URLs and checks that they
// are FORBIDDEN or not, depending on the mode. They do not attempt to do
// detailed verification of behaviour beyond authorization. They are not
// fuzz tests.

View File

@ -24,24 +24,24 @@ import (
"testing"
"time"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
bootstrapapi "k8s.io/client-go/tools/bootstrap/token/api"
api "k8s.io/kubernetes/pkg/apis/core"
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/bootstrap"
bootstraputil "k8s.io/kubernetes/test/e2e/lifecycle/bootstrap"
"k8s.io/kubernetes/test/integration"
"k8s.io/kubernetes/test/integration/framework"
)
type bootstrapSecrets []*api.Secret
type bootstrapSecrets []*corev1.Secret
func (b bootstrapSecrets) List(selector labels.Selector) (ret []*api.Secret, err error) {
func (b bootstrapSecrets) List(selector labels.Selector) (ret []*corev1.Secret, err error) {
return b, nil
}
func (b bootstrapSecrets) Get(name string) (*api.Secret, error) {
func (b bootstrapSecrets) Get(name string) (*corev1.Secret, error) {
return b[0], nil
}
@ -55,36 +55,36 @@ func TestBootstrapTokenAuth(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
var bootstrapSecretValid = &api.Secret{
var bootstrapSecretValid = &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: metav1.NamespaceSystem,
Name: bootstrapapi.BootstrapTokenSecretPrefix,
},
Type: api.SecretTypeBootstrapToken,
Type: corev1.SecretTypeBootstrapToken,
Data: map[string][]byte{
bootstrapapi.BootstrapTokenIDKey: []byte(tokenId),
bootstrapapi.BootstrapTokenSecretKey: []byte(secret),
bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
},
}
var bootstrapSecretInvalid = &api.Secret{
var bootstrapSecretInvalid = &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: metav1.NamespaceSystem,
Name: bootstrapapi.BootstrapTokenSecretPrefix,
},
Type: api.SecretTypeBootstrapToken,
Type: corev1.SecretTypeBootstrapToken,
Data: map[string][]byte{
bootstrapapi.BootstrapTokenIDKey: []byte(tokenId),
bootstrapapi.BootstrapTokenSecretKey: []byte("invalid"),
bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
},
}
var expiredBootstrapToken = &api.Secret{
var expiredBootstrapToken = &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: metav1.NamespaceSystem,
Name: bootstrapapi.BootstrapTokenSecretPrefix,
},
Type: api.SecretTypeBootstrapToken,
Type: corev1.SecretTypeBootstrapToken,
Data: map[string][]byte{
bootstrapapi.BootstrapTokenIDKey: []byte(tokenId),
bootstrapapi.BootstrapTokenSecretKey: []byte("invalid"),
@ -101,7 +101,7 @@ func TestBootstrapTokenAuth(t *testing.T) {
tests := []struct {
name string
request request
secret *api.Secret
secret *corev1.Secret
}{
{
name: "valid token",

View File

@ -18,45 +18,38 @@ package auth
import (
"fmt"
"net/http"
"net/http/httptest"
"io/ioutil"
"strings"
"testing"
"time"
storagev1beta1 "k8s.io/api/storage/v1beta1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
"k8s.io/apiserver/pkg/authentication/token/tokenfile"
"k8s.io/apiserver/pkg/authentication/user"
utilfeature "k8s.io/apiserver/pkg/util/feature"
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
versionedinformers "k8s.io/client-go/informers"
externalclientset "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
csiv1alpha1 "k8s.io/csi-api/pkg/apis/csi/v1alpha1"
csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned"
kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/coordination"
"k8s.io/kubernetes/pkg/apis/core"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/policy"
"k8s.io/kubernetes/pkg/auth/nodeidentifier"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/kubeapiserver/authorizer"
"k8s.io/kubernetes/plugin/pkg/admission/noderestriction"
"k8s.io/kubernetes/test/integration/etcd"
"k8s.io/kubernetes/test/integration/framework"
"k8s.io/utils/pointer"
)
func TestNodeAuthorizer(t *testing.T) {
// Start the server so we know the address
h := &framework.MasterHolder{Initialized: make(chan struct{})}
apiServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
<-h.Initialized
h.M.GenericAPIServer.Handler.ServeHTTP(w, req)
}))
const (
// Define credentials
tokenMaster = "master-token"
@ -65,57 +58,44 @@ func TestNodeAuthorizer(t *testing.T) {
tokenNode2 = "node2-token"
)
authenticator := bearertoken.New(tokenfile.New(map[string]*user.DefaultInfo{
tokenMaster: {Name: "admin", Groups: []string{"system:masters"}},
tokenNodeUnknown: {Name: "unknown", Groups: []string{"system:nodes"}},
tokenNode1: {Name: "system:node:node1", Groups: []string{"system:nodes"}},
tokenNode2: {Name: "system:node:node2", Groups: []string{"system:nodes"}},
}))
// Build client config, clientset, and informers
clientConfig := &restclient.Config{Host: apiServer.URL, ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs}}
superuserClient, superuserClientExternal := clientsetForToken(tokenMaster, clientConfig)
informerFactory := informers.NewSharedInformerFactory(superuserClient, time.Minute)
versionedInformerFactory := versionedinformers.NewSharedInformerFactory(superuserClientExternal, time.Minute)
// Enabled CSIPersistentVolume feature at startup so volumeattachments get watched
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIPersistentVolume, true)()
// Enable DynamicKubeletConfig feature so that Node.Spec.ConfigSource can be set
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DynamicKubeletConfig, true)()
// Set up Node+RBAC authorizer
authorizerConfig := &authorizer.AuthorizationConfig{
AuthorizationModes: []string{"Node", "RBAC"},
InformerFactory: informerFactory,
VersionedInformerFactory: versionedInformerFactory,
}
nodeRBACAuthorizer, _, err := authorizerConfig.New()
// Enable NodeLease feature so that nodes can create leases
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.NodeLease, true)()
// Enable CSINodeInfo feature so that nodes can create CSINodeInfo objects.
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSINodeInfo, true)()
tokenFile, err := ioutil.TempFile("", "kubeconfig")
if err != nil {
t.Fatal(err)
}
tokenFile.WriteString(strings.Join([]string{
fmt.Sprintf(`%s,admin,uid1,"system:masters"`, tokenMaster),
fmt.Sprintf(`%s,unknown,uid2,"system:nodes"`, tokenNodeUnknown),
fmt.Sprintf(`%s,system:node:node1,uid3,"system:nodes"`, tokenNode1),
fmt.Sprintf(`%s,system:node:node2,uid4,"system:nodes"`, tokenNode2),
}, "\n"))
tokenFile.Close()
// Set up NodeRestriction admission
nodeRestrictionAdmission := noderestriction.NewPlugin(nodeidentifier.NewDefaultNodeIdentifier())
nodeRestrictionAdmission.SetInternalKubeInformerFactory(informerFactory)
if err := nodeRestrictionAdmission.ValidateInitialization(); err != nil {
t.Fatal(err)
}
server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{
"--authorization-mode", "Node,RBAC",
"--token-auth-file", tokenFile.Name(),
"--enable-admission-plugins", "NodeRestriction",
// The "default" SA is not installed, causing the ServiceAccount plugin to retry for ~1s per
// API request.
"--disable-admission-plugins", "ServiceAccount",
}, framework.SharedEtcd())
defer server.TearDownFn()
// Start the server
masterConfig := framework.NewIntegrationTestMasterConfig()
masterConfig.GenericConfig.Authentication.Authenticator = authenticator
masterConfig.GenericConfig.Authorization.Authorizer = nodeRBACAuthorizer
masterConfig.GenericConfig.AdmissionControl = nodeRestrictionAdmission
_, _, closeFn := framework.RunAMasterUsingServer(masterConfig, apiServer, h)
defer closeFn()
// Start the informers
stopCh := make(chan struct{})
defer close(stopCh)
informerFactory.Start(stopCh)
versionedInformerFactory.Start(stopCh)
// Build client config and superuser clientset
clientConfig := server.ClientConfig
superuserClient, superuserClientExternal := clientsetForToken(tokenMaster, clientConfig)
superuserCRDClient := crdClientsetForToken(tokenMaster, clientConfig)
// Wait for a healthy server
for {
@ -129,6 +109,10 @@ func TestNodeAuthorizer(t *testing.T) {
}
// Create objects
if _, err := superuserClient.Core().Namespaces().Create(&core.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "ns"}}); err != nil {
t.Fatal(err)
}
if _, err := superuserClient.Core().Secrets("ns").Create(&api.Secret{ObjectMeta: metav1.ObjectMeta{Name: "mysecret"}}); err != nil {
t.Fatal(err)
}
@ -174,6 +158,13 @@ func TestNodeAuthorizer(t *testing.T) {
t.Fatal(err)
}
csiNodeInfoCRD, err := crdFromManifest("../../../staging/src/k8s.io/csi-api/pkg/crd/manifests/csinodeinfo.yaml")
if err != nil {
t.Fatal(err)
}
etcd.CreateTestCRDs(t, superuserCRDClient, false, csiNodeInfoCRD)
getSecret := func(client clientset.Interface) func() error {
return func() error {
_, err := client.Core().Secrets("ns").Get("mysecret", metav1.GetOptions{})
@ -369,9 +360,132 @@ func TestNodeAuthorizer(t *testing.T) {
}
}
getNode1Lease := func(client clientset.Interface) func() error {
return func() error {
_, err := client.Coordination().Leases(api.NamespaceNodeLease).Get("node1", metav1.GetOptions{})
return err
}
}
node1LeaseDurationSeconds := int32(40)
createNode1Lease := func(client clientset.Interface) func() error {
return func() error {
lease := &coordination.Lease{
ObjectMeta: metav1.ObjectMeta{
Name: "node1",
},
Spec: coordination.LeaseSpec{
HolderIdentity: pointer.StringPtr("node1"),
LeaseDurationSeconds: pointer.Int32Ptr(node1LeaseDurationSeconds),
RenewTime: &metav1.MicroTime{Time: time.Now()},
},
}
_, err := client.Coordination().Leases(api.NamespaceNodeLease).Create(lease)
return err
}
}
updateNode1Lease := func(client clientset.Interface) func() error {
return func() error {
lease, err := client.Coordination().Leases(api.NamespaceNodeLease).Get("node1", metav1.GetOptions{})
if err != nil {
return err
}
lease.Spec.RenewTime = &metav1.MicroTime{Time: time.Now()}
_, err = client.Coordination().Leases(api.NamespaceNodeLease).Update(lease)
return err
}
}
patchNode1Lease := func(client clientset.Interface) func() error {
return func() error {
node1LeaseDurationSeconds++
bs := []byte(fmt.Sprintf(`{"spec": {"leaseDurationSeconds": %d}}`, node1LeaseDurationSeconds))
_, err := client.Coordination().Leases(api.NamespaceNodeLease).Patch("node1", types.StrategicMergePatchType, bs)
return err
}
}
deleteNode1Lease := func(client clientset.Interface) func() error {
return func() error {
return client.Coordination().Leases(api.NamespaceNodeLease).Delete("node1", &metav1.DeleteOptions{})
}
}
getNode1CSINodeInfo := func(client csiclientset.Interface) func() error {
return func() error {
_, err := client.CsiV1alpha1().CSINodeInfos().Get("node1", metav1.GetOptions{})
return err
}
}
createNode1CSINodeInfo := func(client csiclientset.Interface) func() error {
return func() error {
nodeInfo := &csiv1alpha1.CSINodeInfo{
ObjectMeta: metav1.ObjectMeta{
Name: "node1",
},
Spec: csiv1alpha1.CSINodeInfoSpec{
Drivers: []csiv1alpha1.CSIDriverInfoSpec{
{
Name: "com.example.csi/driver1",
NodeID: "com.example.csi/node1",
TopologyKeys: []string{"com.example.csi/zone"},
},
},
},
Status: csiv1alpha1.CSINodeInfoStatus{
Drivers: []csiv1alpha1.CSIDriverInfoStatus{
{
Name: "com.example.csi/driver1",
Available: true,
VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree,
},
},
},
}
_, err := client.CsiV1alpha1().CSINodeInfos().Create(nodeInfo)
return err
}
}
updateNode1CSINodeInfo := func(client csiclientset.Interface) func() error {
return func() error {
nodeInfo, err := client.CsiV1alpha1().CSINodeInfos().Get("node1", metav1.GetOptions{})
if err != nil {
return err
}
nodeInfo.Spec.Drivers = []csiv1alpha1.CSIDriverInfoSpec{
{
Name: "com.example.csi/driver1",
NodeID: "com.example.csi/node1",
TopologyKeys: []string{"com.example.csi/rack"},
},
}
nodeInfo.Status.Drivers = []csiv1alpha1.CSIDriverInfoStatus{
{
Name: "com.example.csi/driver1",
Available: true,
VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree,
},
}
_, err = client.CsiV1alpha1().CSINodeInfos().Update(nodeInfo)
return err
}
}
patchNode1CSINodeInfo := func(client csiclientset.Interface) func() error {
return func() error {
bs := []byte(fmt.Sprintf(`{"csiDrivers": [ { "driver": "net.example.storage/driver2", "nodeID": "net.example.storage/node1", "topologyKeys": [ "net.example.storage/region" ] } ] }`))
// StrategicMergePatch is unsupported by CRs. Falling back to MergePatch
_, err := client.CsiV1alpha1().CSINodeInfos().Patch("node1", types.MergePatchType, bs)
return err
}
}
deleteNode1CSINodeInfo := func(client csiclientset.Interface) func() error {
return func() error {
return client.CsiV1alpha1().CSINodeInfos().Delete("node1", &metav1.DeleteOptions{})
}
}
nodeanonClient, _ := clientsetForToken(tokenNodeUnknown, clientConfig)
node1Client, node1ClientExternal := clientsetForToken(tokenNode1, clientConfig)
node2Client, node2ClientExternal := clientsetForToken(tokenNode2, clientConfig)
csiNode1Client := csiClientsetForToken(tokenNode1, clientConfig)
csiNode2Client := csiClientsetForToken(tokenNode2, clientConfig)
// all node requests from node1 and unknown node fail
expectForbidden(t, getSecret(nodeanonClient))
@ -416,7 +530,10 @@ func TestNodeAuthorizer(t *testing.T) {
expectAllowed(t, createNode2MirrorPodEviction(node2Client))
expectAllowed(t, createNode2(node2Client))
expectAllowed(t, updateNode2Status(node2Client))
expectAllowed(t, deleteNode2(node2Client))
// self deletion is not allowed
expectForbidden(t, deleteNode2(node2Client))
// clean up node2
expectAllowed(t, deleteNode2(superuserClient))
// create a pod as an admin to add object references
expectAllowed(t, createNode2NormalPod(superuserClient))
@ -507,9 +624,35 @@ func TestNodeAuthorizer(t *testing.T) {
// node2 can no longer get the configmap after it is unassigned as its config source
expectForbidden(t, getConfigMapConfigSource(node2Client))
// clean up node2
expectAllowed(t, deleteNode2(node2Client))
expectAllowed(t, deleteNode2(superuserClient))
//TODO(mikedanese): integration test node restriction of TokenRequest
// node1 allowed to operate on its own lease
expectAllowed(t, createNode1Lease(node1Client))
expectAllowed(t, getNode1Lease(node1Client))
expectAllowed(t, updateNode1Lease(node1Client))
expectAllowed(t, patchNode1Lease(node1Client))
expectAllowed(t, deleteNode1Lease(node1Client))
// node2 not allowed to operate on another node's lease
expectForbidden(t, createNode1Lease(node2Client))
expectForbidden(t, getNode1Lease(node2Client))
expectForbidden(t, updateNode1Lease(node2Client))
expectForbidden(t, patchNode1Lease(node2Client))
expectForbidden(t, deleteNode1Lease(node2Client))
// node1 allowed to operate on its own CSINodeInfo
expectAllowed(t, createNode1CSINodeInfo(csiNode1Client))
expectAllowed(t, getNode1CSINodeInfo(csiNode1Client))
expectAllowed(t, updateNode1CSINodeInfo(csiNode1Client))
expectAllowed(t, patchNode1CSINodeInfo(csiNode1Client))
expectAllowed(t, deleteNode1CSINodeInfo(csiNode1Client))
// node2 not allowed to operate on another node's CSINodeInfo
expectForbidden(t, createNode1CSINodeInfo(csiNode2Client))
expectForbidden(t, getNode1CSINodeInfo(csiNode2Client))
expectForbidden(t, updateNode1CSINodeInfo(csiNode2Client))
expectForbidden(t, patchNode1CSINodeInfo(csiNode2Client))
expectForbidden(t, deleteNode1CSINodeInfo(csiNode2Client))
}
// expect executes a function a set number of times until it either returns the
@ -549,3 +692,17 @@ func expectAllowed(t *testing.T, f func() error) {
t.Errorf("Expected no error, got %v", err)
}
}
// crdFromManifest reads a .json/yaml file and returns the CRD in it.
func crdFromManifest(filename string) (*apiextensionsv1beta1.CustomResourceDefinition, error) {
var crd apiextensionsv1beta1.CustomResourceDefinition
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
if err := runtime.DecodeInto(legacyscheme.Codecs.UniversalDecoder(), data, &crd); err != nil {
return nil, err
}
return &crd, nil
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package auth
import (
"context"
"fmt"
"io"
"io/ioutil"
@ -26,8 +27,9 @@ import (
"testing"
"time"
"github.com/golang/glog"
"k8s.io/klog"
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/watch"
@ -38,7 +40,9 @@ import (
"k8s.io/apiserver/pkg/registry/generic"
externalclientset "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
watchtools "k8s.io/client-go/tools/watch"
"k8s.io/client-go/transport"
csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/api/testapi"
api "k8s.io/kubernetes/pkg/apis/core"
@ -72,6 +76,19 @@ func clientsetForToken(user string, config *restclient.Config) (clientset.Interf
return clientset.NewForConfigOrDie(&configCopy), externalclientset.NewForConfigOrDie(&configCopy)
}
func crdClientsetForToken(user string, config *restclient.Config) apiextensionsclient.Interface {
configCopy := *config
configCopy.BearerToken = user
return apiextensionsclient.NewForConfigOrDie(&configCopy)
}
func csiClientsetForToken(user string, config *restclient.Config) csiclientset.Interface {
configCopy := *config
configCopy.BearerToken = user
configCopy.ContentType = "application/json" // // csi client works with CRDs that support json only
return csiclientset.NewForConfigOrDie(&configCopy)
}
type testRESTOptionsGetter struct {
config *master.Config
}
@ -219,6 +236,15 @@ var (
}
}
}
`
aLimitRange = `
{
"apiVersion": "v1",
"kind": "LimitRange",
"metadata": {
"name": "a"%s
}
}
`
podNamespace = `
{
@ -246,6 +272,15 @@ var (
"name": "forbidden-namespace"%s
}
}
`
limitRangeNamespace = `
{
"apiVersion": "` + testapi.Groups[api.GroupName].GroupVersion().String() + `",
"kind": "Namespace",
"metadata": {
"name": "limitrange-namespace"%s
}
}
`
)
@ -409,6 +444,40 @@ func TestRBAC(t *testing.T) {
{superUser, "DELETE", "rbac.authorization.k8s.io", "rolebindings", "job-namespace", "pi", "", http.StatusOK},
},
},
{
bootstrapRoles: bootstrapRoles{
clusterRoles: []rbacapi.ClusterRole{
{
ObjectMeta: metav1.ObjectMeta{Name: "allow-all"},
Rules: []rbacapi.PolicyRule{ruleAllowAll},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "update-limitranges"},
Rules: []rbacapi.PolicyRule{
rbacapi.NewRule("update").Groups("").Resources("limitranges").RuleOrDie(),
},
},
},
clusterRoleBindings: []rbacapi.ClusterRoleBinding{
{
ObjectMeta: metav1.ObjectMeta{Name: "update-limitranges"},
Subjects: []rbacapi.Subject{
{Kind: "User", Name: "limitrange-updater"},
},
RoleRef: rbacapi.RoleRef{Kind: "ClusterRole", Name: "update-limitranges"},
},
},
},
requests: []request{
// Create the namespace used later in the test
{superUser, "POST", "", "namespaces", "", "", limitRangeNamespace, http.StatusCreated},
{"limitrange-updater", "PUT", "", "limitranges", "limitrange-namespace", "a", aLimitRange, http.StatusForbidden},
{superUser, "PUT", "", "limitranges", "limitrange-namespace", "a", aLimitRange, http.StatusCreated},
{superUser, "PUT", "", "limitranges", "limitrange-namespace", "a", aLimitRange, http.StatusOK},
{"limitrange-updater", "PUT", "", "limitranges", "limitrange-namespace", "a", aLimitRange, http.StatusOK},
},
},
}
for i, tc := range tests {
@ -424,6 +493,7 @@ func TestRBAC(t *testing.T) {
"job-writer-namespace": {Name: "job-writer-namespace"},
"nonescalating-rolebinding-writer": {Name: "nonescalating-rolebinding-writer"},
"pod-reader": {Name: "pod-reader"},
"limitrange-updater": {Name: "limitrange-updater"},
"user-with-no-permissions": {Name: "user-with-no-permissions"},
}))
_, s, closeFn := framework.RunAMaster(masterConfig)
@ -492,7 +562,7 @@ func TestRBAC(t *testing.T) {
//
// go test -v -tags integration -run RBAC -args -v 10
//
glog.V(8).Infof("case %d, req %d: %s\n%s\n", i, j, reqDump, respDump)
klog.V(8).Infof("case %d, req %d: %s\n%s\n", i, j, reqDump, respDump)
t.Errorf("case %d, req %d: %s expected %q got %q", i, j, r, statusCode(r.expectedStatus), statusCode(resp.StatusCode))
}
@ -530,7 +600,9 @@ func TestBootstrapping(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
_, err = watch.Until(30*time.Second, watcher, func(event watch.Event) (bool, error) {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
_, err = watchtools.UntilWithoutRetry(ctx, watcher, func(event watch.Event) (bool, error) {
if event.Type != watch.Added {
return false, nil
}

View File

@ -20,22 +20,25 @@ import (
"crypto/ecdsa"
"encoding/base64"
"encoding/json"
"fmt"
"reflect"
"strings"
"testing"
"time"
"gopkg.in/square/go-jose.v2/jwt"
authenticationv1 "k8s.io/api/authentication/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
utilfeature "k8s.io/apiserver/pkg/util/feature"
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
clientset "k8s.io/client-go/kubernetes"
externalclientset "k8s.io/client-go/kubernetes"
certutil "k8s.io/client-go/util/cert"
"k8s.io/kubernetes/pkg/apis/core"
serviceaccountgetter "k8s.io/kubernetes/pkg/controller/serviceaccount"
@ -61,22 +64,35 @@ func TestServiceAccountTokenCreate(t *testing.T) {
pk := sk.(*ecdsa.PrivateKey).PublicKey
const iss = "https://foo.bar.example.com"
aud := []string{"api"}
aud := authenticator.Audiences{"api"}
maxExpirationSeconds := int64(60 * 60)
maxExpirationDuration, err := time.ParseDuration(fmt.Sprintf("%ds", maxExpirationSeconds))
if err != nil {
t.Fatalf("err: %v", err)
}
gcs := &clientset.Clientset{}
// Start the server
masterConfig := framework.NewIntegrationTestMasterConfig()
masterConfig.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer()
masterConfig.GenericConfig.Authentication.APIAudiences = aud
masterConfig.GenericConfig.Authentication.Authenticator = bearertoken.New(
serviceaccount.JWTTokenAuthenticator(
iss,
[]interface{}{&pk},
serviceaccount.NewValidator(aud, serviceaccountgetter.NewGetterFromClient(gcs)),
aud,
serviceaccount.NewValidator(serviceaccountgetter.NewGetterFromClient(gcs)),
),
)
masterConfig.ExtraConfig.ServiceAccountIssuer = serviceaccount.JWTTokenGenerator(iss, sk)
masterConfig.ExtraConfig.ServiceAccountAPIAudiences = aud
tokenGenerator, err := serviceaccount.JWTTokenGenerator(iss, sk)
if err != nil {
t.Fatalf("err: %v", err)
}
masterConfig.ExtraConfig.ServiceAccountIssuer = tokenGenerator
masterConfig.ExtraConfig.ServiceAccountMaxExpiration = maxExpirationDuration
masterConfig.GenericConfig.Authentication.APIAudiences = aud
master, _, closeFn := framework.RunAMaster(masterConfig)
defer closeFn()
@ -150,7 +166,10 @@ func TestServiceAccountTokenCreate(t *testing.T) {
checkPayload(t, treq.Status.Token, `"myns"`, "kubernetes.io", "namespace")
checkPayload(t, treq.Status.Token, `"test-svcacct"`, "kubernetes.io", "serviceaccount", "name")
doTokenReview(t, cs, treq, false)
info := doTokenReview(t, cs, treq, false)
if info.Extra != nil {
t.Fatalf("expected Extra to be nil but got: %#v", info.Extra)
}
delSvcAcct()
doTokenReview(t, cs, treq, true)
})
@ -203,7 +222,16 @@ func TestServiceAccountTokenCreate(t *testing.T) {
checkPayload(t, treq.Status.Token, `"myns"`, "kubernetes.io", "namespace")
checkPayload(t, treq.Status.Token, `"test-svcacct"`, "kubernetes.io", "serviceaccount", "name")
doTokenReview(t, cs, treq, false)
info := doTokenReview(t, cs, treq, false)
if len(info.Extra) != 2 {
t.Fatalf("expected Extra have length of 2 but was length %d: %#v", len(info.Extra), info.Extra)
}
if expected := map[string]authenticationv1.ExtraValue{
"authentication.kubernetes.io/pod-name": {pod.ObjectMeta.Name},
"authentication.kubernetes.io/pod-uid": {string(pod.ObjectMeta.UID)},
}; !reflect.DeepEqual(info.Extra, expected) {
t.Fatalf("unexpected Extra:\ngot:\t%#v\nwant:\t%#v", info.Extra, expected)
}
delPod()
doTokenReview(t, cs, treq, true)
})
@ -438,9 +466,97 @@ func TestServiceAccountTokenCreate(t *testing.T) {
doTokenReview(t, cs, treq, true)
})
t.Run("a token request within expiration time", func(t *testing.T) {
normalExpirationTime := maxExpirationSeconds - 10*60
treq := &authenticationv1.TokenRequest{
Spec: authenticationv1.TokenRequestSpec{
Audiences: []string{"api"},
ExpirationSeconds: &normalExpirationTime,
BoundObjectRef: &authenticationv1.BoundObjectReference{
Kind: "Secret",
APIVersion: "v1",
Name: secret.Name,
UID: secret.UID,
},
},
}
sa, del := createDeleteSvcAcct(t, cs, sa)
defer del()
originalSecret, originalDelSecret := createDeleteSecret(t, cs, secret)
defer originalDelSecret()
treq.Spec.BoundObjectRef.UID = originalSecret.UID
if treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq); err != nil {
t.Fatalf("err: %v", err)
}
checkPayload(t, treq.Status.Token, `"system:serviceaccount:myns:test-svcacct"`, "sub")
checkPayload(t, treq.Status.Token, `["api"]`, "aud")
checkPayload(t, treq.Status.Token, `null`, "kubernetes.io", "pod")
checkPayload(t, treq.Status.Token, `"test-secret"`, "kubernetes.io", "secret", "name")
checkPayload(t, treq.Status.Token, `"myns"`, "kubernetes.io", "namespace")
checkPayload(t, treq.Status.Token, `"test-svcacct"`, "kubernetes.io", "serviceaccount", "name")
checkExpiration(t, treq, normalExpirationTime)
doTokenReview(t, cs, treq, false)
originalDelSecret()
doTokenReview(t, cs, treq, true)
_, recreateDelSecret := createDeleteSecret(t, cs, secret)
defer recreateDelSecret()
doTokenReview(t, cs, treq, true)
})
t.Run("a token request with out-of-range expiration", func(t *testing.T) {
tooLongExpirationTime := maxExpirationSeconds + 10*60
treq := &authenticationv1.TokenRequest{
Spec: authenticationv1.TokenRequestSpec{
Audiences: []string{"api"},
ExpirationSeconds: &tooLongExpirationTime,
BoundObjectRef: &authenticationv1.BoundObjectReference{
Kind: "Secret",
APIVersion: "v1",
Name: secret.Name,
UID: secret.UID,
},
},
}
sa, del := createDeleteSvcAcct(t, cs, sa)
defer del()
originalSecret, originalDelSecret := createDeleteSecret(t, cs, secret)
defer originalDelSecret()
treq.Spec.BoundObjectRef.UID = originalSecret.UID
if treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq); err != nil {
t.Fatalf("err: %v", err)
}
checkPayload(t, treq.Status.Token, `"system:serviceaccount:myns:test-svcacct"`, "sub")
checkPayload(t, treq.Status.Token, `["api"]`, "aud")
checkPayload(t, treq.Status.Token, `null`, "kubernetes.io", "pod")
checkPayload(t, treq.Status.Token, `"test-secret"`, "kubernetes.io", "secret", "name")
checkPayload(t, treq.Status.Token, `"myns"`, "kubernetes.io", "namespace")
checkPayload(t, treq.Status.Token, `"test-svcacct"`, "kubernetes.io", "serviceaccount", "name")
checkExpiration(t, treq, maxExpirationSeconds)
doTokenReview(t, cs, treq, false)
originalDelSecret()
doTokenReview(t, cs, treq, true)
_, recreateDelSecret := createDeleteSecret(t, cs, secret)
defer recreateDelSecret()
doTokenReview(t, cs, treq, true)
})
}
func doTokenReview(t *testing.T, cs externalclientset.Interface, treq *authenticationv1.TokenRequest, expectErr bool) {
func doTokenReview(t *testing.T, cs clientset.Interface, treq *authenticationv1.TokenRequest, expectErr bool) authenticationv1.UserInfo {
t.Helper()
trev, err := cs.AuthenticationV1().TokenReviews().Create(&authenticationv1.TokenReview{
Spec: authenticationv1.TokenReviewSpec{
@ -460,6 +576,7 @@ func doTokenReview(t *testing.T, cs externalclientset.Interface, treq *authentic
if !trev.Status.Authenticated && !expectErr {
t.Fatal("expected token to be authenticated but it wasn't")
}
return trev.Status.User
}
func checkPayload(t *testing.T, tok string, want string, parts ...string) {
@ -470,6 +587,16 @@ func checkPayload(t *testing.T, tok string, want string, parts ...string) {
}
}
func checkExpiration(t *testing.T, treq *authenticationv1.TokenRequest, expectedExpiration int64) {
t.Helper()
if treq.Spec.ExpirationSeconds == nil {
t.Errorf("unexpected nil expiration seconds.")
}
if *treq.Spec.ExpirationSeconds != expectedExpiration {
t.Errorf("unexpected expiration seconds.\nsaw:\t%d\nwant:\t%d", treq.Spec.ExpirationSeconds, expectedExpiration)
}
}
func getSubObject(t *testing.T, b string, parts ...string) string {
t.Helper()
var obj interface{}