Browse code

hide authorization resource groups to prevent further usage

deads2k authored on 2016/06/22 23:32:19
Showing 7 changed files
... ...
@@ -7,85 +7,85 @@ import (
7 7
 // NEVER TOUCH ANYTHING IN THIS FILE!
8 8
 
9 9
 const (
10
-	// ResourceGroupPrefix is the prefix for indicating that a resource entry is actually a group of resources.  The groups are defined in code and indicate resources that are commonly permissioned together
11
-	ResourceGroupPrefix = "resourcegroup:"
12
-	BuildGroupName      = ResourceGroupPrefix + "builds"
13
-	DeploymentGroupName = ResourceGroupPrefix + "deployments"
14
-	ImageGroupName      = ResourceGroupPrefix + "images"
15
-	OAuthGroupName      = ResourceGroupPrefix + "oauth"
16
-	UserGroupName       = ResourceGroupPrefix + "users"
17
-	TemplateGroupName   = ResourceGroupPrefix + "templates"
18
-	SDNGroupName        = ResourceGroupPrefix + "sdn"
19
-	// PolicyOwnerGroupName includes the physical resources behind the PermissionGrantingGroupName.  Unless these physical objects are created first, users with privileges to PermissionGrantingGroupName will
10
+	// resourceGroupPrefix is the prefix for indicating that a resource entry is actually a group of resources.  The groups are defined in code and indicate resources that are commonly permissioned together
11
+	resourceGroupPrefix = "resourcegroup:"
12
+	buildGroupName      = resourceGroupPrefix + "builds"
13
+	deploymentGroupName = resourceGroupPrefix + "deployments"
14
+	imageGroupName      = resourceGroupPrefix + "images"
15
+	oauthGroupName      = resourceGroupPrefix + "oauth"
16
+	userGroupName       = resourceGroupPrefix + "users"
17
+	templateGroupName   = resourceGroupPrefix + "templates"
18
+	sdnGroupName        = resourceGroupPrefix + "sdn"
19
+	// policyOwnerGroupName includes the physical resources behind the permissionGrantingGroupName.  Unless these physical objects are created first, users with privileges to permissionGrantingGroupName will
20 20
 	// only be able to bind to global roles
21
-	PolicyOwnerGroupName = ResourceGroupPrefix + "policy"
22
-	// PermissionGrantingGroupName includes resources that are necessary to maintain authorization roles and bindings.  By itself, this group is insufficient to create anything except for bindings
21
+	policyOwnerGroupName = resourceGroupPrefix + "policy"
22
+	// permissionGrantingGroupName includes resources that are necessary to maintain authorization roles and bindings.  By itself, this group is insufficient to create anything except for bindings
23 23
 	// to master roles.  If a local Policy already exists, then privileges to this group will allow for modification of local roles.
24
-	PermissionGrantingGroupName = ResourceGroupPrefix + "granter"
25
-	// OpenshiftExposedGroupName includes resources that are commonly viewed and modified by end users of the system.  It does not include any sensitive resources that control authentication or authorization
26
-	OpenshiftExposedGroupName = ResourceGroupPrefix + "exposedopenshift"
27
-	OpenshiftAllGroupName     = ResourceGroupPrefix + "allopenshift"
28
-	OpenshiftStatusGroupName  = ResourceGroupPrefix + "allopenshift-status"
24
+	permissionGrantingGroupName = resourceGroupPrefix + "granter"
25
+	// openshiftExposedGroupName includes resources that are commonly viewed and modified by end users of the system.  It does not include any sensitive resources that control authentication or authorization
26
+	openshiftExposedGroupName = resourceGroupPrefix + "exposedopenshift"
27
+	openshiftAllGroupName     = resourceGroupPrefix + "allopenshift"
28
+	openshiftStatusGroupName  = resourceGroupPrefix + "allopenshift-status"
29 29
 
30
-	QuotaGroupName = ResourceGroupPrefix + "quota"
31
-	// KubeInternalsGroupName includes those resources that should reasonably be viewable to end users, but that most users should probably not modify.  Kubernetes herself will maintain these resources
32
-	KubeInternalsGroupName = ResourceGroupPrefix + "privatekube"
33
-	// KubeExposedGroupName includes resources that are commonly viewed and modified by end users of the system.
34
-	KubeExposedGroupName = ResourceGroupPrefix + "exposedkube"
35
-	KubeAllGroupName     = ResourceGroupPrefix + "allkube"
36
-	KubeStatusGroupName  = ResourceGroupPrefix + "allkube-status"
30
+	quotaGroupName = resourceGroupPrefix + "quota"
31
+	// kubeInternalsGroupName includes those resources that should reasonably be viewable to end users, but that most users should probably not modify.  Kubernetes herself will maintain these resources
32
+	kubeInternalsGroupName = resourceGroupPrefix + "privatekube"
33
+	// kubeExposedGroupName includes resources that are commonly viewed and modified by end users of the system.
34
+	kubeExposedGroupName = resourceGroupPrefix + "exposedkube"
35
+	kubeAllGroupName     = resourceGroupPrefix + "allkube"
36
+	kubeStatusGroupName  = resourceGroupPrefix + "allkube-status"
37 37
 
38
-	// NonEscalatingResourcesGroupName contains all resources that can be viewed without exposing the risk of using view rights to locate a secret to escalate privileges.  For example, view
38
+	// nonescalatingResourcesGroupName contains all resources that can be viewed without exposing the risk of using view rights to locate a secret to escalate privileges.  For example, view
39 39
 	// rights on secrets could be used locate a secret that happened to be  serviceaccount token that has more privileges
40
-	NonEscalatingResourcesGroupName         = ResourceGroupPrefix + "non-escalating"
41
-	KubeNonEscalatingViewableGroupName      = ResourceGroupPrefix + "kube-non-escalating"
42
-	OpenshiftNonEscalatingViewableGroupName = ResourceGroupPrefix + "openshift-non-escalating"
40
+	nonescalatingResourcesGroupName         = resourceGroupPrefix + "non-escalating"
41
+	kubeNonEscalatingViewableGroupName      = resourceGroupPrefix + "kube-non-escalating"
42
+	openshiftNonEscalatingViewableGroupName = resourceGroupPrefix + "openshift-non-escalating"
43 43
 
44
-	// EscalatingResourcesGroupName contains all resources that can be used to escalate privileges when simply viewed
45
-	EscalatingResourcesGroupName         = ResourceGroupPrefix + "escalating"
46
-	KubeEscalatingViewableGroupName      = ResourceGroupPrefix + "kube-escalating"
47
-	OpenshiftEscalatingViewableGroupName = ResourceGroupPrefix + "openshift-escalating"
44
+	// escalatingResourcesGroupName contains all resources that can be used to escalate privileges when simply viewed
45
+	escalatingResourcesGroupName         = resourceGroupPrefix + "escalating"
46
+	kubeEscalatingViewableGroupName      = resourceGroupPrefix + "kube-escalating"
47
+	openshiftEscalatingViewableGroupName = resourceGroupPrefix + "openshift-escalating"
48 48
 )
49 49
 
50 50
 var (
51
-	GroupsToResources = map[string][]string{
52
-		BuildGroupName:       {"builds", "buildconfigs", "buildlogs", "buildconfigs/instantiate", "buildconfigs/instantiatebinary", "builds/log", "builds/clone", "buildconfigs/webhooks"},
53
-		ImageGroupName:       {"imagestreams", "imagestreammappings", "imagestreamtags", "imagestreamimages", "imagestreamimports"},
54
-		DeploymentGroupName:  {"deploymentconfigs", "generatedeploymentconfigs", "deploymentconfigrollbacks", "deploymentconfigs/log", "deploymentconfigs/scale"},
55
-		SDNGroupName:         {"clusternetworks", "hostsubnets", "netnamespaces"},
56
-		TemplateGroupName:    {"templates", "templateconfigs", "processedtemplates"},
57
-		UserGroupName:        {"identities", "users", "useridentitymappings", "groups"},
58
-		OAuthGroupName:       {"oauthauthorizetokens", "oauthaccesstokens", "oauthclients", "oauthclientauthorizations"},
59
-		PolicyOwnerGroupName: {"policies", "policybindings"},
51
+	groupsToResources = map[string][]string{
52
+		buildGroupName:       {"builds", "buildconfigs", "buildlogs", "buildconfigs/instantiate", "buildconfigs/instantiatebinary", "builds/log", "builds/clone", "buildconfigs/webhooks"},
53
+		imageGroupName:       {"imagestreams", "imagestreammappings", "imagestreamtags", "imagestreamimages", "imagestreamimports"},
54
+		deploymentGroupName:  {"deploymentconfigs", "generatedeploymentconfigs", "deploymentconfigrollbacks", "deploymentconfigs/log", "deploymentconfigs/scale"},
55
+		sdnGroupName:         {"clusternetworks", "hostsubnets", "netnamespaces"},
56
+		templateGroupName:    {"templates", "templateconfigs", "processedtemplates"},
57
+		userGroupName:        {"identities", "users", "useridentitymappings", "groups"},
58
+		oauthGroupName:       {"oauthauthorizetokens", "oauthaccesstokens", "oauthclients", "oauthclientauthorizations"},
59
+		policyOwnerGroupName: {"policies", "policybindings"},
60 60
 
61 61
 		// RAR and SAR are in this list to support backwards compatibility with clients that expect access to those resource in a namespace scope and a cluster scope.
62 62
 		// TODO remove once we have eliminated the namespace scoped resource.
63
-		PermissionGrantingGroupName: {"roles", "rolebindings", "resourceaccessreviews" /* cluster scoped*/, "subjectaccessreviews" /* cluster scoped*/, "localresourceaccessreviews", "localsubjectaccessreviews"},
64
-		OpenshiftExposedGroupName:   {BuildGroupName, ImageGroupName, DeploymentGroupName, TemplateGroupName, "routes"},
65
-		OpenshiftAllGroupName: {OpenshiftExposedGroupName, UserGroupName, OAuthGroupName, PolicyOwnerGroupName, SDNGroupName, PermissionGrantingGroupName, OpenshiftStatusGroupName, "projects",
63
+		permissionGrantingGroupName: {"roles", "rolebindings", "resourceaccessreviews" /* cluster scoped*/, "subjectaccessreviews" /* cluster scoped*/, "localresourceaccessreviews", "localsubjectaccessreviews"},
64
+		openshiftExposedGroupName:   {buildGroupName, imageGroupName, deploymentGroupName, templateGroupName, "routes"},
65
+		openshiftAllGroupName: {openshiftExposedGroupName, userGroupName, oauthGroupName, policyOwnerGroupName, sdnGroupName, permissionGrantingGroupName, openshiftStatusGroupName, "projects",
66 66
 			"clusterroles", "clusterrolebindings", "clusterpolicies", "clusterpolicybindings", "images" /* cluster scoped*/, "projectrequests", "builds/details", "imagestreams/secrets",
67 67
 			"selfsubjectrulesreviews"},
68
-		OpenshiftStatusGroupName: {"imagestreams/status", "routes/status", "deploymentconfigs/status"},
68
+		openshiftStatusGroupName: {"imagestreams/status", "routes/status", "deploymentconfigs/status"},
69 69
 
70
-		QuotaGroupName:         {"limitranges", "resourcequotas", "resourcequotausages"},
71
-		KubeExposedGroupName:   {"pods", "replicationcontrollers", "serviceaccounts", "services", "endpoints", "persistentvolumeclaims", "pods/log", "configmaps"},
72
-		KubeInternalsGroupName: {"minions", "nodes", "bindings", "events", "namespaces", "persistentvolumes", "securitycontextconstraints"},
73
-		KubeAllGroupName:       {KubeInternalsGroupName, KubeExposedGroupName, QuotaGroupName},
74
-		KubeStatusGroupName:    {"pods/status", "resourcequotas/status", "namespaces/status", "replicationcontrollers/status"},
70
+		quotaGroupName:         {"limitranges", "resourcequotas", "resourcequotausages"},
71
+		kubeExposedGroupName:   {"pods", "replicationcontrollers", "serviceaccounts", "services", "endpoints", "persistentvolumeclaims", "pods/log", "configmaps"},
72
+		kubeInternalsGroupName: {"minions", "nodes", "bindings", "events", "namespaces", "persistentvolumes", "securitycontextconstraints"},
73
+		kubeAllGroupName:       {kubeInternalsGroupName, kubeExposedGroupName, quotaGroupName},
74
+		kubeStatusGroupName:    {"pods/status", "resourcequotas/status", "namespaces/status", "replicationcontrollers/status"},
75 75
 
76
-		OpenshiftEscalatingViewableGroupName: {"oauthauthorizetokens", "oauthaccesstokens", "imagestreams/secrets"},
77
-		KubeEscalatingViewableGroupName:      {"secrets"},
78
-		EscalatingResourcesGroupName:         {OpenshiftEscalatingViewableGroupName, KubeEscalatingViewableGroupName},
76
+		openshiftEscalatingViewableGroupName: {"oauthauthorizetokens", "oauthaccesstokens", "imagestreams/secrets"},
77
+		kubeEscalatingViewableGroupName:      {"secrets"},
78
+		escalatingResourcesGroupName:         {openshiftEscalatingViewableGroupName, kubeEscalatingViewableGroupName},
79 79
 
80
-		NonEscalatingResourcesGroupName: {OpenshiftNonEscalatingViewableGroupName, KubeNonEscalatingViewableGroupName},
80
+		nonescalatingResourcesGroupName: {openshiftNonEscalatingViewableGroupName, kubeNonEscalatingViewableGroupName},
81 81
 	}
82 82
 )
83 83
 
84 84
 func init() {
85 85
 	// set the non-escalating groups
86
-	GroupsToResources[OpenshiftNonEscalatingViewableGroupName] = NormalizeResources(sets.NewString(GroupsToResources[OpenshiftAllGroupName]...)).
87
-		Difference(NormalizeResources(sets.NewString(GroupsToResources[OpenshiftEscalatingViewableGroupName]...))).List()
86
+	groupsToResources[openshiftNonEscalatingViewableGroupName] = NormalizeResources(sets.NewString(groupsToResources[openshiftAllGroupName]...)).
87
+		Difference(NormalizeResources(sets.NewString(groupsToResources[openshiftEscalatingViewableGroupName]...))).List()
88 88
 
89
-	GroupsToResources[KubeNonEscalatingViewableGroupName] = NormalizeResources(sets.NewString(GroupsToResources[KubeAllGroupName]...)).
90
-		Difference(NormalizeResources(sets.NewString(GroupsToResources[KubeEscalatingViewableGroupName]...))).List()
89
+	groupsToResources[kubeNonEscalatingViewableGroupName] = NormalizeResources(sets.NewString(groupsToResources[kubeAllGroupName]...)).
90
+		Difference(NormalizeResources(sets.NewString(groupsToResources[kubeEscalatingViewableGroupName]...))).List()
91 91
 }
... ...
@@ -7,8 +7,8 @@ import (
7 7
 )
8 8
 
9 9
 func TestEscalating(t *testing.T) {
10
-	escalatingResources := NormalizeResources(sets.NewString(GroupsToResources[EscalatingResourcesGroupName]...))
11
-	nonEscalatingResources := NormalizeResources(sets.NewString(GroupsToResources[NonEscalatingResourcesGroupName]...))
10
+	escalatingResources := NormalizeResources(sets.NewString(groupsToResources[escalatingResourcesGroupName]...))
11
+	nonEscalatingResources := NormalizeResources(sets.NewString(groupsToResources[nonescalatingResourcesGroupName]...))
12 12
 	if len(nonEscalatingResources) <= len(escalatingResources) {
13 13
 		t.Errorf("groups look bad: escalating=%v nonescalating=%v", escalatingResources.List(), nonEscalatingResources.List())
14 14
 	}
... ...
@@ -23,7 +23,7 @@ func TestNormalizeResources(t *testing.T) {
23 23
 		{"capA", "capA", "capa"},
24 24
 		{"capH", "capH", "caph"},
25 25
 		{"capZ", "capZ", "capz"},
26
-		{"group", BuildGroupName, "builds"},
26
+		{"group", buildGroupName, "builds"},
27 27
 	}
28 28
 
29 29
 	for _, test := range tests {
... ...
@@ -52,7 +52,7 @@ func TestNeedsNormalization(t *testing.T) {
52 52
 		{"/", "/", false},
53 53
 		{"-", "-", false},
54 54
 		{".", ".", false},
55
-		{ResourceGroupPrefix, ResourceGroupPrefix, true},
55
+		{resourceGroupPrefix, resourceGroupPrefix, true},
56 56
 	}
57 57
 
58 58
 	for _, test := range tests {
... ...
@@ -44,12 +44,12 @@ func NormalizeResources(rawResources sets.String) sets.String {
44 44
 		}
45 45
 		visited.Insert(currResource)
46 46
 
47
-		if !strings.HasPrefix(currResource, ResourceGroupPrefix) {
47
+		if !strings.HasPrefix(currResource, resourceGroupPrefix) {
48 48
 			ret.Insert(strings.ToLower(currResource))
49 49
 			continue
50 50
 		}
51 51
 
52
-		if resourceTypes, exists := GroupsToResources[currResource]; exists {
52
+		if resourceTypes, exists := groupsToResources[currResource]; exists {
53 53
 			toVisit = append(toVisit, resourceTypes...)
54 54
 		}
55 55
 	}
... ...
@@ -58,7 +58,7 @@ func NormalizeResources(rawResources sets.String) sets.String {
58 58
 }
59 59
 
60 60
 func needsNormalizing(in string) bool {
61
-	if strings.HasPrefix(in, ResourceGroupPrefix) {
61
+	if strings.HasPrefix(in, resourceGroupPrefix) {
62 62
 		return true
63 63
 	}
64 64
 	for _, r := range in {
... ...
@@ -52,15 +52,10 @@ func GetBootstrapOpenshiftRoles(openshiftNamespace string) []authorizationapi.Ro
52 52
 				Namespace: openshiftNamespace,
53 53
 			},
54 54
 			Rules: []authorizationapi.PolicyRule{
55
-				{
56
-					Verbs:     sets.NewString("get", "list"),
57
-					Resources: sets.NewString("templates", authorizationapi.ImageGroupName),
58
-				},
59
-				{
60
-					// so anyone can pull from openshift/* image streams
61
-					Verbs:     sets.NewString("get"),
62
-					Resources: sets.NewString("imagestreams/layers"),
63
-				},
55
+				authorizationapi.NewRule(read...).Groups(templateGroup).Resources("templates").RuleOrDie(),
56
+				authorizationapi.NewRule(read...).Groups(imageGroup).Resources("imagestreams", "imagestreamtags", "imagestreamimages").RuleOrDie(),
57
+				// so anyone can pull from openshift/* image streams
58
+				authorizationapi.NewRule("get").Groups(imageGroup).Resources("imagestreams/layers").RuleOrDie(),
64 59
 			},
65 60
 		},
66 61
 	}
... ...
@@ -2,7 +2,6 @@ package origin
2 2
 
3 3
 import (
4 4
 	"reflect"
5
-	"strings"
6 5
 	"testing"
7 6
 
8 7
 	"k8s.io/kubernetes/pkg/api"
... ...
@@ -11,11 +10,9 @@ import (
11 11
 	"k8s.io/kubernetes/pkg/genericapiserver"
12 12
 	kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
13 13
 	etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
14
-	"k8s.io/kubernetes/pkg/util/sets"
15 14
 
16 15
 	_ "github.com/openshift/origin/pkg/api/install"
17 16
 	"github.com/openshift/origin/pkg/api/validation"
18
-	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
19 17
 	"github.com/openshift/origin/pkg/util/restoptions"
20 18
 )
21 19
 
... ...
@@ -228,7 +228,7 @@ func TestAuthorizationResolution(t *testing.T) {
228 228
 	roleWithGroup.Name = "with-group"
229 229
 	roleWithGroup.Rules = append(roleWithGroup.Rules, authorizationapi.PolicyRule{
230 230
 		Verbs:     sets.NewString("list"),
231
-		Resources: sets.NewString(authorizationapi.BuildGroupName),
231
+		Resources: sets.NewString("resourcegroup:builds"),
232 232
 	})
233 233
 	if _, err := clusterAdminClient.ClusterRoles().Create(roleWithGroup); err != nil {
234 234
 		t.Fatalf("unexpected error: %v", err)
... ...
@@ -1143,7 +1143,7 @@ func TestOldLocalResourceAccessReviewEndpoint(t *testing.T) {
1143 1143
 		expectedResponse := &authorizationapi.ResourceAccessReviewResponse{
1144 1144
 			Namespace: namespace,
1145 1145
 			Users:     sets.NewString("harold", "system:serviceaccount:hammer-project:builder", "system:serviceaccount:openshift-infra:namespace-controller", "system:admin"),
1146
-			Groups:    sets.NewString("system:cluster-admins", "system:masters", "system:serviceaccounts:hammer-project"),
1146
+			Groups:    sets.NewString("system:cluster-admins", "system:masters", "system:cluster-readers", "system:serviceaccounts:hammer-project"),
1147 1147
 		}
1148 1148
 		if (actualResponse.Namespace != expectedResponse.Namespace) ||
1149 1149
 			!reflect.DeepEqual(actualResponse.Users.List(), expectedResponse.Users.List()) ||
... ...
@@ -1170,7 +1170,7 @@ func TestOldLocalResourceAccessReviewEndpoint(t *testing.T) {
1170 1170
 		expectedResponse := &authorizationapi.ResourceAccessReviewResponse{
1171 1171
 			Namespace: namespace,
1172 1172
 			Users:     sets.NewString("harold", "system:serviceaccount:hammer-project:builder", "system:serviceaccount:openshift-infra:namespace-controller", "system:admin"),
1173
-			Groups:    sets.NewString("system:cluster-admins", "system:masters", "system:serviceaccounts:hammer-project"),
1173
+			Groups:    sets.NewString("system:cluster-admins", "system:masters", "system:cluster-readers", "system:serviceaccounts:hammer-project"),
1174 1174
 		}
1175 1175
 		if (actualResponse.Namespace != expectedResponse.Namespace) ||
1176 1176
 			!reflect.DeepEqual(actualResponse.Users.List(), expectedResponse.Users.List()) ||
... ...
@@ -7,19 +7,28 @@ items:
7 7
     name: shared-resource-viewer
8 8
     namespace: openshift
9 9
   rules:
10
-  - apiGroups: null
10
+  - apiGroups:
11
+    - ""
12
+    attributeRestrictions: null
13
+    resources:
14
+    - templates
15
+    verbs:
16
+    - get
17
+    - list
18
+    - watch
19
+  - apiGroups:
20
+    - ""
11 21
     attributeRestrictions: null
12 22
     resources:
13 23
     - imagestreamimages
14
-    - imagestreamimports
15
-    - imagestreammappings
16 24
     - imagestreams
17 25
     - imagestreamtags
18
-    - templates
19 26
     verbs:
20 27
     - get
21 28
     - list
22
-  - apiGroups: null
29
+    - watch
30
+  - apiGroups:
31
+    - ""
23 32
     attributeRestrictions: null
24 33
     resources:
25 34
     - imagestreams/layers