| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
|
| 7 | 7 |
// we have a strong dependency on kube objects for deployments and scale |
| 8 | 8 |
_ "k8s.io/kubernetes/pkg/api/install" |
| 9 |
+ _ "k8s.io/kubernetes/pkg/apis/authentication/install" |
|
| 9 | 10 |
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install" |
| 10 | 11 |
_ "k8s.io/kubernetes/pkg/apis/batch/install" |
| 11 | 12 |
_ "k8s.io/kubernetes/pkg/apis/extensions/install" |
| 12 | 13 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,52 @@ |
| 0 |
+package remotetokenreview |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "errors" |
|
| 4 |
+ |
|
| 5 |
+ "k8s.io/kubernetes/pkg/apis/authentication" |
|
| 6 |
+ "k8s.io/kubernetes/pkg/auth/user" |
|
| 7 |
+ unversionedauthentication "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/authentication/unversioned" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+type Authenticator struct {
|
|
| 11 |
+ authenticationClient unversionedauthentication.TokenReviewsGetter |
|
| 12 |
+} |
|
| 13 |
+ |
|
| 14 |
+// NewAuthenticator authenticates by doing a tokenreview |
|
| 15 |
+func NewAuthenticator(authenticationClient unversionedauthentication.TokenReviewsGetter) (*Authenticator, error) {
|
|
| 16 |
+ return &Authenticator{
|
|
| 17 |
+ authenticationClient: authenticationClient, |
|
| 18 |
+ }, nil |
|
| 19 |
+} |
|
| 20 |
+ |
|
| 21 |
+func (a *Authenticator) AuthenticateToken(value string) (user.Info, bool, error) {
|
|
| 22 |
+ if len(value) == 0 {
|
|
| 23 |
+ return nil, false, nil |
|
| 24 |
+ } |
|
| 25 |
+ tokenReview := &authentication.TokenReview{}
|
|
| 26 |
+ tokenReview.Spec.Token = value |
|
| 27 |
+ |
|
| 28 |
+ response, err := a.authenticationClient.TokenReviews().Create(tokenReview) |
|
| 29 |
+ if err != nil {
|
|
| 30 |
+ return nil, false, err |
|
| 31 |
+ } |
|
| 32 |
+ |
|
| 33 |
+ if len(response.Status.Error) > 0 {
|
|
| 34 |
+ return nil, false, errors.New(response.Status.Error) |
|
| 35 |
+ } |
|
| 36 |
+ if !response.Status.Authenticated {
|
|
| 37 |
+ return nil, false, nil |
|
| 38 |
+ } |
|
| 39 |
+ |
|
| 40 |
+ userInfo := &user.DefaultInfo{
|
|
| 41 |
+ Name: response.Status.User.Username, |
|
| 42 |
+ UID: response.Status.User.UID, |
|
| 43 |
+ Groups: response.Status.User.Groups, |
|
| 44 |
+ Extra: map[string][]string{},
|
|
| 45 |
+ } |
|
| 46 |
+ for k, v := range response.Status.User.Extra {
|
|
| 47 |
+ userInfo.Extra[k] = v |
|
| 48 |
+ } |
|
| 49 |
+ |
|
| 50 |
+ return userInfo, true, nil |
|
| 51 |
+} |
| ... | ... |
@@ -15,8 +15,7 @@ var _ = kauthorizer.Attributes(AdapterAttributes{})
|
| 15 | 15 |
// AdapterAttributes satisfies k8s authorizer.Attributes interfaces |
| 16 | 16 |
type AdapterAttributes struct {
|
| 17 | 17 |
namespace string |
| 18 |
- userName string |
|
| 19 |
- groups []string |
|
| 18 |
+ user user.Info |
|
| 20 | 19 |
authorizationAttributes oauthorizer.AuthorizationAttributes |
| 21 | 20 |
} |
| 22 | 21 |
|
| ... | ... |
@@ -26,10 +25,7 @@ func OriginAuthorizerAttributes(kattrs kauthorizer.Attributes) (kapi.Context, oa |
| 26 | 26 |
// Build a context to hold the namespace and user info |
| 27 | 27 |
ctx := kapi.NewContext() |
| 28 | 28 |
ctx = kapi.WithNamespace(ctx, kattrs.GetNamespace()) |
| 29 |
- ctx = kapi.WithUser(ctx, &user.DefaultInfo{
|
|
| 30 |
- Name: kattrs.GetUserName(), |
|
| 31 |
- Groups: kattrs.GetGroups(), |
|
| 32 |
- }) |
|
| 29 |
+ ctx = kapi.WithUser(ctx, kattrs.GetUser()) |
|
| 33 | 30 |
|
| 34 | 31 |
// If we recognize the type, use the embedded type. Do NOT use it directly, because not all things that quack are ducks. |
| 35 | 32 |
if castAdapterAttributes, ok := kattrs.(AdapterAttributes); ok {
|
| ... | ... |
@@ -59,11 +55,10 @@ func OriginAuthorizerAttributes(kattrs kauthorizer.Attributes) (kapi.Context, oa |
| 59 | 59 |
|
| 60 | 60 |
// KubernetesAuthorizerAttributes adapts Origin authorization attributes to Kubernetes authorization attributes |
| 61 | 61 |
// The returned attributes can be passed to OriginAuthorizerAttributes to access extra information from the Origin attributes interface |
| 62 |
-func KubernetesAuthorizerAttributes(namespace string, userName string, groups []string, oattrs oauthorizer.AuthorizationAttributes) kauthorizer.Attributes {
|
|
| 62 |
+func KubernetesAuthorizerAttributes(namespace string, user user.Info, oattrs oauthorizer.AuthorizationAttributes) kauthorizer.Attributes {
|
|
| 63 | 63 |
return AdapterAttributes{
|
| 64 |
- namespace: namespace, |
|
| 65 |
- userName: userName, |
|
| 66 |
- groups: groups, |
|
| 64 |
+ namespace: namespace, |
|
| 65 |
+ user: user, |
|
| 67 | 66 |
authorizationAttributes: oattrs, |
| 68 | 67 |
} |
| 69 | 68 |
} |
| ... | ... |
@@ -108,14 +103,8 @@ func (a AdapterAttributes) GetResource() string {
|
| 108 | 108 |
|
| 109 | 109 |
// GetUserName satisfies the kubernetes authorizer.Attributes interface |
| 110 | 110 |
// origin gets this value from the request context |
| 111 |
-func (a AdapterAttributes) GetUserName() string {
|
|
| 112 |
- return a.userName |
|
| 113 |
-} |
|
| 114 |
- |
|
| 115 |
-// GetGroups satisfies the kubernetes authorizer.Attributes interface |
|
| 116 |
-// origin gets this value from the request context |
|
| 117 |
-func (a AdapterAttributes) GetGroups() []string {
|
|
| 118 |
- return a.groups |
|
| 111 |
+func (a AdapterAttributes) GetUser() user.Info {
|
|
| 112 |
+ return a.user |
|
| 119 | 113 |
} |
| 120 | 114 |
|
| 121 | 115 |
// IsReadOnly satisfies the kubernetes authorizer.Attributes interface based on the verb |
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
|
| 7 | 7 |
kapi "k8s.io/kubernetes/pkg/api" |
| 8 | 8 |
kauthorizer "k8s.io/kubernetes/pkg/auth/authorizer" |
| 9 |
+ "k8s.io/kubernetes/pkg/auth/user" |
|
| 9 | 10 |
"k8s.io/kubernetes/pkg/util/sets" |
| 10 | 11 |
|
| 11 | 12 |
oauthorizer "github.com/openshift/origin/pkg/authorization/authorizer" |
| ... | ... |
@@ -28,12 +29,12 @@ func TestRoundTrip(t *testing.T) {
|
| 28 | 28 |
} |
| 29 | 29 |
|
| 30 | 30 |
// Convert to kube attributes |
| 31 |
- kattrs := KubernetesAuthorizerAttributes("ns", "myuser", []string{"mygroup"}, oattrs)
|
|
| 32 |
- if kattrs.GetUserName() != "myuser" {
|
|
| 33 |
- t.Errorf("Expected %v, got %v", "myuser", kattrs.GetUserName())
|
|
| 31 |
+ kattrs := KubernetesAuthorizerAttributes("ns", &user.DefaultInfo{Name: "myuser", Groups: []string{"mygroup"}}, oattrs)
|
|
| 32 |
+ if kattrs.GetUser().GetName() != "myuser" {
|
|
| 33 |
+ t.Errorf("Expected %v, got %v", "myuser", kattrs.GetUser().GetName())
|
|
| 34 | 34 |
} |
| 35 |
- if !reflect.DeepEqual(kattrs.GetGroups(), []string{"mygroup"}) {
|
|
| 36 |
- t.Errorf("Expected %v, got %v", []string{"mygroup"}, kattrs.GetGroups())
|
|
| 35 |
+ if !reflect.DeepEqual(kattrs.GetUser().GetGroups(), []string{"mygroup"}) {
|
|
| 36 |
+ t.Errorf("Expected %v, got %v", []string{"mygroup"}, kattrs.GetUser().GetGroups())
|
|
| 37 | 37 |
} |
| 38 | 38 |
if kattrs.GetVerb() != "get" {
|
| 39 | 39 |
t.Errorf("Expected %v, got %v", "get", kattrs.GetVerb())
|
| ... | ... |
@@ -104,7 +105,7 @@ func TestAttributeIntersection(t *testing.T) {
|
| 104 | 104 |
// Everything in this list should be used by OriginAuthorizerAttributes or derivative (like IsReadOnly) |
| 105 | 105 |
expectedKubernetesOnly := sets.NewString( |
| 106 | 106 |
// used to build context in OriginAuthorizerAttributes |
| 107 |
- "GetGroups", "GetUserName", "GetNamespace", |
|
| 107 |
+ "GetUser", "GetNamespace", |
|
| 108 | 108 |
// Based on verb, derivative |
| 109 | 109 |
"IsReadOnly", |
| 110 | 110 |
// Non-matching, but used |
| ... | ... |
@@ -14,6 +14,7 @@ import ( |
| 14 | 14 |
utilruntime "k8s.io/kubernetes/pkg/util/runtime" |
| 15 | 15 |
"k8s.io/kubernetes/pkg/util/sets" |
| 16 | 16 |
|
| 17 |
+ authorizationapi "github.com/openshift/origin/pkg/authorization/api" |
|
| 17 | 18 |
"github.com/openshift/origin/pkg/authorization/authorizer" |
| 18 | 19 |
) |
| 19 | 20 |
|
| ... | ... |
@@ -144,6 +145,7 @@ func cacheKey(ctx kapi.Context, a authorizer.AuthorizationAttributes) (string, e |
| 144 | 144 |
if user, ok := kapi.UserFrom(ctx); ok {
|
| 145 | 145 |
keyData["user"] = user.GetName() |
| 146 | 146 |
keyData["groups"] = user.GetGroups() |
| 147 |
+ keyData["scopes"] = user.GetExtra()[authorizationapi.ScopesKey] |
|
| 147 | 148 |
} |
| 148 | 149 |
|
| 149 | 150 |
key, err := json.Marshal(keyData) |
| ... | ... |
@@ -48,7 +48,7 @@ func TestCacheKey(t *testing.T) {
|
| 48 | 48 |
NonResourceURL: true, |
| 49 | 49 |
URL: "/abc", |
| 50 | 50 |
}, |
| 51 |
- ExpectedKey: `{"apiGroup":"ag","apiVersion":"av","groups":["group1","group2"],"namespace":"myns","nonResourceURL":true,"resource":"r","resourceName":"rn","url":"/abc","user":"me","verb":"v"}`,
|
|
| 51 |
+ ExpectedKey: `{"apiGroup":"ag","apiVersion":"av","groups":["group1","group2"],"namespace":"myns","nonResourceURL":true,"resource":"r","resourceName":"rn","scopes":null,"url":"/abc","user":"me","verb":"v"}`,
|
|
| 52 | 52 |
}, |
| 53 | 53 |
} |
| 54 | 54 |
|
| ... | ... |
@@ -39,21 +39,23 @@ var ( |
| 39 | 39 |
// exposed externally. |
| 40 | 40 |
DeadOpenShiftStorageVersionLevels = []string{"v1beta1", "v1beta3"}
|
| 41 | 41 |
|
| 42 |
- APIGroupKube = "" |
|
| 43 |
- APIGroupExtensions = "extensions" |
|
| 44 |
- APIGroupAutoscaling = "autoscaling" |
|
| 45 |
- APIGroupBatch = "batch" |
|
| 46 |
- APIGroupPolicy = "policy" |
|
| 47 |
- APIGroupApps = "apps" |
|
| 48 |
- APIGroupFederation = "federation" |
|
| 42 |
+ APIGroupKube = "" |
|
| 43 |
+ APIGroupExtensions = "extensions" |
|
| 44 |
+ APIGroupAutoscaling = "autoscaling" |
|
| 45 |
+ APIGroupAuthentication = "authentication.k8s.io" |
|
| 46 |
+ APIGroupBatch = "batch" |
|
| 47 |
+ APIGroupPolicy = "policy" |
|
| 48 |
+ APIGroupApps = "apps" |
|
| 49 |
+ APIGroupFederation = "federation" |
|
| 49 | 50 |
|
| 50 | 51 |
// Map of group names to allowed REST API versions |
| 51 | 52 |
KubeAPIGroupsToAllowedVersions = map[string][]string{
|
| 52 |
- APIGroupKube: {"v1"},
|
|
| 53 |
- APIGroupExtensions: {"v1beta1"},
|
|
| 54 |
- APIGroupAutoscaling: {"v1"},
|
|
| 55 |
- APIGroupBatch: {"v1", "v2alpha1"},
|
|
| 56 |
- APIGroupApps: {"v1alpha1"},
|
|
| 53 |
+ APIGroupKube: {"v1"},
|
|
| 54 |
+ APIGroupExtensions: {"v1beta1"},
|
|
| 55 |
+ APIGroupAutoscaling: {"v1"},
|
|
| 56 |
+ APIGroupAuthentication: {"v1beta1"},
|
|
| 57 |
+ APIGroupBatch: {"v1", "v2alpha1"},
|
|
| 58 |
+ APIGroupApps: {"v1alpha1"},
|
|
| 57 | 59 |
// TODO: enable as part of a separate binary |
| 58 | 60 |
//APIGroupFederation: {"v1beta1"},
|
| 59 | 61 |
} |
| ... | ... |
@@ -154,6 +154,7 @@ func GetBootstrapClusterRoles() []authorizationapi.ClusterRole {
|
| 154 | 154 |
// permissions to check access. These creates are non-mutating |
| 155 | 155 |
authorizationapi.NewRule("create").Groups(authzGroup).Resources("localresourceaccessreviews", "localsubjectaccessreviews", "resourceaccessreviews",
|
| 156 | 156 |
"selfsubjectrulesreviews", "subjectaccessreviews").RuleOrDie(), |
| 157 |
+ authorizationapi.NewRule("create").Groups("authentication.k8s.io").Resources("tokenreviews").RuleOrDie(),
|
|
| 157 | 158 |
// Allow read access to node metrics |
| 158 | 159 |
authorizationapi.NewRule("get").Groups(kapiGroup).Resources(authorizationapi.NodeMetricsResource).RuleOrDie(),
|
| 159 | 160 |
// Allow read access to stats |
| ... | ... |
@@ -543,6 +544,7 @@ func GetBootstrapClusterRoles() []authorizationapi.ClusterRole {
|
| 543 | 543 |
}, |
| 544 | 544 |
Rules: []authorizationapi.PolicyRule{
|
| 545 | 545 |
// Needed to check API access. These creates are non-mutating |
| 546 |
+ authorizationapi.NewRule("create").Groups("authentication.k8s.io").Resources("tokenreviews").RuleOrDie(),
|
|
| 546 | 547 |
authorizationapi.NewRule("create").Groups(authzGroup).Resources("subjectaccessreviews", "localsubjectaccessreviews").RuleOrDie(),
|
| 547 | 548 |
// Needed to build serviceLister, to populate env vars for services |
| 548 | 549 |
authorizationapi.NewRule(read...).Groups(kapiGroup).Resources("services").RuleOrDie(),
|
| ... | ... |
@@ -21,6 +21,7 @@ import ( |
| 21 | 21 |
"k8s.io/kubernetes/pkg/apis/batch" |
| 22 | 22 |
"k8s.io/kubernetes/pkg/apis/extensions" |
| 23 | 23 |
"k8s.io/kubernetes/pkg/apiserver" |
| 24 |
+ "k8s.io/kubernetes/pkg/auth/authenticator" |
|
| 24 | 25 |
kclient "k8s.io/kubernetes/pkg/client/unversioned" |
| 25 | 26 |
"k8s.io/kubernetes/pkg/cloudprovider" |
| 26 | 27 |
"k8s.io/kubernetes/pkg/genericapiserver" |
| ... | ... |
@@ -53,7 +54,7 @@ type MasterConfig struct {
|
| 53 | 53 |
Informers shared.InformerFactory |
| 54 | 54 |
} |
| 55 | 55 |
|
| 56 |
-func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextMapper kapi.RequestContextMapper, kubeClient *kclient.Client, informers shared.InformerFactory, admissionControl admission.Interface) (*MasterConfig, error) {
|
|
| 56 |
+func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextMapper kapi.RequestContextMapper, kubeClient *kclient.Client, informers shared.InformerFactory, admissionControl admission.Interface, originAuthenticator authenticator.Request) (*MasterConfig, error) {
|
|
| 57 | 57 |
if options.KubernetesMasterConfig == nil {
|
| 58 | 58 |
return nil, errors.New("insufficient information to build KubernetesMasterConfig")
|
| 59 | 59 |
} |
| ... | ... |
@@ -197,6 +198,7 @@ func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextM |
| 197 | 197 |
PublicAddress: publicAddress, |
| 198 | 198 |
ReadWritePort: port, |
| 199 | 199 |
|
| 200 |
+ Authenticator: originAuthenticator, // this is used to fulfill the tokenreviews endpoint which is used by node authentication |
|
| 200 | 201 |
Authorizer: apiserver.NewAlwaysAllowAuthorizer(), |
| 201 | 202 |
AdmissionControl: admissionControl, |
| 202 | 203 |
|
| ... | ... |
@@ -11,7 +11,7 @@ import ( |
| 11 | 11 |
"k8s.io/kubernetes/pkg/auth/authenticator" |
| 12 | 12 |
kauthorizer "k8s.io/kubernetes/pkg/auth/authorizer" |
| 13 | 13 |
"k8s.io/kubernetes/pkg/auth/user" |
| 14 |
- "k8s.io/kubernetes/pkg/client/restclient" |
|
| 14 |
+ unversionedauthentication "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/authentication/unversioned" |
|
| 15 | 15 |
|
| 16 | 16 |
oauthenticator "github.com/openshift/origin/pkg/auth/authenticator" |
| 17 | 17 |
"github.com/openshift/origin/pkg/auth/authenticator/anonymous" |
| ... | ... |
@@ -19,7 +19,7 @@ import ( |
| 19 | 19 |
"github.com/openshift/origin/pkg/auth/authenticator/request/unionrequest" |
| 20 | 20 |
"github.com/openshift/origin/pkg/auth/authenticator/request/x509request" |
| 21 | 21 |
authncache "github.com/openshift/origin/pkg/auth/authenticator/token/cache" |
| 22 |
- authnremote "github.com/openshift/origin/pkg/auth/authenticator/token/remotemaster" |
|
| 22 |
+ authnremote "github.com/openshift/origin/pkg/auth/authenticator/token/remotetokenreview" |
|
| 23 | 23 |
"github.com/openshift/origin/pkg/auth/group" |
| 24 | 24 |
authorizationapi "github.com/openshift/origin/pkg/authorization/api" |
| 25 | 25 |
oauthorizer "github.com/openshift/origin/pkg/authorization/authorizer" |
| ... | ... |
@@ -30,7 +30,7 @@ import ( |
| 30 | 30 |
"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" |
| 31 | 31 |
) |
| 32 | 32 |
|
| 33 |
-func newAuthenticator(clientCAs *x509.CertPool, anonymousConfig restclient.Config, cacheTTL time.Duration, cacheSize int) (authenticator.Request, error) {
|
|
| 33 |
+func newAuthenticator(authenticationClient unversionedauthentication.TokenReviewsGetter, clientCAs *x509.CertPool, cacheTTL time.Duration, cacheSize int) (authenticator.Request, error) {
|
|
| 34 | 34 |
authenticators := []oauthenticator.Request{}
|
| 35 | 35 |
|
| 36 | 36 |
// API token auth |
| ... | ... |
@@ -39,7 +39,7 @@ func newAuthenticator(clientCAs *x509.CertPool, anonymousConfig restclient.Confi |
| 39 | 39 |
err error |
| 40 | 40 |
) |
| 41 | 41 |
// Authenticate against the remote master |
| 42 |
- tokenAuthenticator, err = authnremote.NewAuthenticator(anonymousConfig) |
|
| 42 |
+ tokenAuthenticator, err = authnremote.NewAuthenticator(authenticationClient) |
|
| 43 | 43 |
if err != nil {
|
| 44 | 44 |
return nil, err |
| 45 | 45 |
} |
| ... | ... |
@@ -107,8 +107,6 @@ func (n NodeAuthorizerAttributesGetter) GetRequestAttributes(u user.Info, r *htt |
| 107 | 107 |
} |
| 108 | 108 |
|
| 109 | 109 |
namespace := "" |
| 110 |
- userName := u.GetName() |
|
| 111 |
- groups := u.GetGroups() |
|
| 112 | 110 |
|
| 113 | 111 |
apiVerb := "" |
| 114 | 112 |
switch r.Method {
|
| ... | ... |
@@ -139,9 +137,9 @@ func (n NodeAuthorizerAttributesGetter) GetRequestAttributes(u user.Info, r *htt |
| 139 | 139 |
} |
| 140 | 140 |
// TODO: handle other things like /healthz/*? not sure if "non-resource" urls on the kubelet make sense to authorize against master non-resource URL policy |
| 141 | 141 |
|
| 142 |
- glog.V(2).Infof("Node request attributes: namespace=%s, user=%s, groups=%v, attrs=%#v", namespace, userName, groups, attrs)
|
|
| 142 |
+ glog.V(2).Infof("Node request attributes: namespace=%s, user=%#v, attrs=%#v", namespace, u, attrs)
|
|
| 143 | 143 |
|
| 144 |
- return authzadapter.KubernetesAuthorizerAttributes(namespace, userName, groups, attrs) |
|
| 144 |
+ return authzadapter.KubernetesAuthorizerAttributes(namespace, u, attrs) |
|
| 145 | 145 |
} |
| 146 | 146 |
|
| 147 | 147 |
func newAuthorizer(c *oclient.Client, cacheTTL time.Duration, cacheSize int) (kauthorizer.Authorizer, error) {
|
| ... | ... |
@@ -31,7 +31,6 @@ import ( |
| 31 | 31 |
configapi "github.com/openshift/origin/pkg/cmd/server/api" |
| 32 | 32 |
"github.com/openshift/origin/pkg/cmd/server/crypto" |
| 33 | 33 |
cmdutil "github.com/openshift/origin/pkg/cmd/util" |
| 34 |
- "github.com/openshift/origin/pkg/cmd/util/clientcmd" |
|
| 35 | 34 |
cmdflags "github.com/openshift/origin/pkg/cmd/util/flags" |
| 36 | 35 |
"github.com/openshift/origin/pkg/cmd/util/variable" |
| 37 | 36 |
"github.com/openshift/origin/pkg/dns" |
| ... | ... |
@@ -82,7 +81,7 @@ type NodeConfig struct {
|
| 82 | 82 |
} |
| 83 | 83 |
|
| 84 | 84 |
func BuildKubernetesNodeConfig(options configapi.NodeConfig, enableProxy, enableDNS bool) (*NodeConfig, error) {
|
| 85 |
- originClient, osClientConfig, err := configapi.GetOpenShiftClient(options.MasterKubeConfig) |
|
| 85 |
+ originClient, _, err := configapi.GetOpenShiftClient(options.MasterKubeConfig) |
|
| 86 | 86 |
if err != nil {
|
| 87 | 87 |
return nil, err |
| 88 | 88 |
} |
| ... | ... |
@@ -213,7 +212,7 @@ func BuildKubernetesNodeConfig(options configapi.NodeConfig, enableProxy, enable |
| 213 | 213 |
if err != nil {
|
| 214 | 214 |
return nil, err |
| 215 | 215 |
} |
| 216 |
- authn, err := newAuthenticator(clientCAs, clientcmd.AnonymousClientConfig(osClientConfig), authnTTL, options.AuthConfig.AuthenticationCacheSize) |
|
| 216 |
+ authn, err := newAuthenticator(cfg.KubeClient.Authentication(), clientCAs, authnTTL, options.AuthConfig.AuthenticationCacheSize) |
|
| 217 | 217 |
if err != nil {
|
| 218 | 218 |
return nil, err |
| 219 | 219 |
} |
| ... | ... |
@@ -336,7 +336,7 @@ func BuildKubernetesMasterConfig(openshiftConfig *origin.MasterConfig) (*kuberne |
| 336 | 336 |
if openshiftConfig.Options.KubernetesMasterConfig == nil {
|
| 337 | 337 |
return nil, nil |
| 338 | 338 |
} |
| 339 |
- kubeConfig, err := kubernetes.BuildKubernetesMasterConfig(openshiftConfig.Options, openshiftConfig.RequestContextMapper, openshiftConfig.KubeClient(), openshiftConfig.Informers, openshiftConfig.KubeAdmissionControl) |
|
| 339 |
+ kubeConfig, err := kubernetes.BuildKubernetesMasterConfig(openshiftConfig.Options, openshiftConfig.RequestContextMapper, openshiftConfig.KubeClient(), openshiftConfig.Informers, openshiftConfig.KubeAdmissionControl, openshiftConfig.Authenticator) |
|
| 340 | 340 |
return kubeConfig, err |
| 341 | 341 |
} |
| 342 | 342 |
|
| ... | ... |
@@ -12,10 +12,13 @@ import ( |
| 12 | 12 |
"k8s.io/kubernetes/pkg/client/restclient" |
| 13 | 13 |
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client" |
| 14 | 14 |
|
| 15 |
+ "github.com/openshift/origin/pkg/authorization/authorizer/scope" |
|
| 15 | 16 |
"github.com/openshift/origin/pkg/cmd/admin/policy" |
| 16 | 17 |
configapi "github.com/openshift/origin/pkg/cmd/server/api" |
| 17 | 18 |
"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" |
| 19 |
+ "github.com/openshift/origin/pkg/cmd/server/origin" |
|
| 18 | 20 |
"github.com/openshift/origin/pkg/cmd/util/clientcmd" |
| 21 |
+ oauthapi "github.com/openshift/origin/pkg/oauth/api" |
|
| 19 | 22 |
testutil "github.com/openshift/origin/test/util" |
| 20 | 23 |
testserver "github.com/openshift/origin/test/util/server" |
| 21 | 24 |
) |
| ... | ... |
@@ -71,6 +74,25 @@ func TestNodeAuth(t *testing.T) {
|
| 71 | 71 |
t.Fatalf("unexpected error: %v", err)
|
| 72 | 72 |
} |
| 73 | 73 |
|
| 74 |
+ // create a scoped token for bob that is only good for getting user info |
|
| 75 |
+ bobUser, err := bobClient.Users().Get("~")
|
|
| 76 |
+ if err != nil {
|
|
| 77 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 78 |
+ } |
|
| 79 |
+ whoamiOnlyBobToken := &oauthapi.OAuthAccessToken{
|
|
| 80 |
+ ObjectMeta: kapi.ObjectMeta{Name: "whoami-token-plus-some-padding-here-to-make-the-limit"},
|
|
| 81 |
+ ClientName: origin.OpenShiftCLIClientID, |
|
| 82 |
+ ExpiresIn: 200, |
|
| 83 |
+ Scopes: []string{scope.UserIndicator + scope.UserInfo},
|
|
| 84 |
+ UserName: bobUser.Name, |
|
| 85 |
+ UserUID: string(bobUser.UID), |
|
| 86 |
+ } |
|
| 87 |
+ if _, err := originAdminClient.OAuthAccessTokens().Create(whoamiOnlyBobToken); err != nil {
|
|
| 88 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 89 |
+ } |
|
| 90 |
+ _, _, bobWhoamiOnlyConfig, err := testutil.GetClientForUser(*adminConfig, "bob") |
|
| 91 |
+ bobWhoamiOnlyConfig.BearerToken = whoamiOnlyBobToken.Name |
|
| 92 |
+ |
|
| 74 | 93 |
// Grant sa1 system:cluster-reader, which should let them read metrics and stats |
| 75 | 94 |
addSA1 := &policy.RoleModificationOptions{
|
| 76 | 95 |
RoleName: bootstrappolicy.ClusterReaderRoleName, |
| ... | ... |
@@ -133,6 +155,11 @@ func TestNodeAuth(t *testing.T) {
|
| 133 | 133 |
KubeletClientConfig: kubeletClientConfig(bobConfig), |
| 134 | 134 |
NodeViewer: true, |
| 135 | 135 |
}, |
| 136 |
+ // bob is normally a viewer, but when using a scoped token, he should end up denied |
|
| 137 |
+ "bob-scoped": {
|
|
| 138 |
+ KubeletClientConfig: kubeletClientConfig(bobWhoamiOnlyConfig), |
|
| 139 |
+ Forbidden: true, |
|
| 140 |
+ }, |
|
| 136 | 141 |
"alice": {
|
| 137 | 142 |
KubeletClientConfig: kubeletClientConfig(aliceConfig), |
| 138 | 143 |
Forbidden: true, |
| ... | ... |
@@ -225,7 +252,7 @@ func TestNodeAuth(t *testing.T) {
|
| 225 | 225 |
} |
| 226 | 226 |
resp.Body.Close() |
| 227 | 227 |
if resp.StatusCode != r.Result {
|
| 228 |
- t.Errorf("%s: %s: expected %d, got %d", k, r.Path, r.Result, resp.StatusCode)
|
|
| 228 |
+ t.Errorf("%s: token=%s %s: expected %d, got %d", k, tc.KubeletClientConfig.BearerToken, r.Path, r.Result, resp.StatusCode)
|
|
| 229 | 229 |
continue |
| 230 | 230 |
} |
| 231 | 231 |
} |
| ... | ... |
@@ -288,6 +288,13 @@ items: |
| 288 | 288 |
verbs: |
| 289 | 289 |
- create |
| 290 | 290 |
- apiGroups: |
| 291 |
+ - authentication.k8s.io |
|
| 292 |
+ attributeRestrictions: null |
|
| 293 |
+ resources: |
|
| 294 |
+ - tokenreviews |
|
| 295 |
+ verbs: |
|
| 296 |
+ - create |
|
| 297 |
+ - apiGroups: |
|
| 291 | 298 |
- "" |
| 292 | 299 |
attributeRestrictions: null |
| 293 | 300 |
resources: |
| ... | ... |
@@ -1729,6 +1736,13 @@ items: |
| 1729 | 1729 |
name: system:node |
| 1730 | 1730 |
rules: |
| 1731 | 1731 |
- apiGroups: |
| 1732 |
+ - authentication.k8s.io |
|
| 1733 |
+ attributeRestrictions: null |
|
| 1734 |
+ resources: |
|
| 1735 |
+ - tokenreviews |
|
| 1736 |
+ verbs: |
|
| 1737 |
+ - create |
|
| 1738 |
+ - apiGroups: |
|
| 1732 | 1739 |
- "" |
| 1733 | 1740 |
attributeRestrictions: null |
| 1734 | 1741 |
resources: |