Browse code

Add reconcile protection for roles

Jordan Liggitt authored on 2016/05/07 02:53:00
Showing 13 changed files
... ...
@@ -362,14 +362,14 @@ Add users or serviceaccount to a security context constraint
362 362
 
363 363
 
364 364
 == oadm policy reconcile-cluster-role-bindings
365
-Replace cluster role bindings to match the recommended bootstrap policy
365
+Update cluster role bindings to match the recommended bootstrap policy
366 366
 
367 367
 ====
368 368
 
369 369
 [options="nowrap"]
370 370
 ----
371
-  # Display the cluster role bindings that would be modified
372
-  $ oadm policy reconcile-cluster-role-bindings
371
+  # Display the names of cluster role bindings that would be modified
372
+  $ oadm policy reconcile-cluster-role-bindings -o name
373 373
 
374 374
   # Display the cluster role bindings that would be modified, removing any extra subjects
375 375
   $ oadm policy reconcile-cluster-role-bindings --additive-only=false
... ...
@@ -387,18 +387,22 @@ Replace cluster role bindings to match the recommended bootstrap policy
387 387
 
388 388
 
389 389
 == oadm policy reconcile-cluster-roles
390
-Replace cluster roles to match the recommended bootstrap policy
390
+Update cluster roles to match the recommended bootstrap policy
391 391
 
392 392
 ====
393 393
 
394 394
 [options="nowrap"]
395 395
 ----
396
-  # Display the cluster roles that would be modified
397
-  $ oadm policy reconcile-cluster-roles
396
+  # Display the names of cluster roles that would be modified
397
+  $ oadm policy reconcile-cluster-roles -o name
398 398
 
399
-  # Replace cluster roles that don't match the current defaults
399
+  # Add missing permissions to cluster roles that don't match the current defaults
400 400
   $ oadm policy reconcile-cluster-roles --confirm
401 401
 
402
+  # Add missing permissions and remove extra permissions from 
403
+  # cluster roles that don't match the current defaults
404
+  $ oadm policy reconcile-cluster-roles --additive-only=false --confirm
405
+
402 406
   # Display the union of the default and modified cluster roles
403 407
   $ oadm policy reconcile-cluster-roles --additive-only
404 408
 ----
... ...
@@ -362,14 +362,14 @@ Add users or serviceaccount to a security context constraint
362 362
 
363 363
 
364 364
 == oc adm policy reconcile-cluster-role-bindings
365
-Replace cluster role bindings to match the recommended bootstrap policy
365
+Update cluster role bindings to match the recommended bootstrap policy
366 366
 
367 367
 ====
368 368
 
369 369
 [options="nowrap"]
370 370
 ----
371
-  # Display the cluster role bindings that would be modified
372
-  $ oc adm policy reconcile-cluster-role-bindings
371
+  # Display the names of cluster role bindings that would be modified
372
+  $ oc adm policy reconcile-cluster-role-bindings -o name
373 373
 
374 374
   # Display the cluster role bindings that would be modified, removing any extra subjects
375 375
   $ oc adm policy reconcile-cluster-role-bindings --additive-only=false
... ...
@@ -387,18 +387,22 @@ Replace cluster role bindings to match the recommended bootstrap policy
387 387
 
388 388
 
389 389
 == oc adm policy reconcile-cluster-roles
390
-Replace cluster roles to match the recommended bootstrap policy
390
+Update cluster roles to match the recommended bootstrap policy
391 391
 
392 392
 ====
393 393
 
394 394
 [options="nowrap"]
395 395
 ----
396
-  # Display the cluster roles that would be modified
397
-  $ oc adm policy reconcile-cluster-roles
396
+  # Display the names of cluster roles that would be modified
397
+  $ oc adm policy reconcile-cluster-roles -o name
398 398
 
399
-  # Replace cluster roles that don't match the current defaults
399
+  # Add missing permissions to cluster roles that don't match the current defaults
400 400
   $ oc adm policy reconcile-cluster-roles --confirm
401 401
 
402
+  # Add missing permissions and remove extra permissions from 
403
+  # cluster roles that don't match the current defaults
404
+  $ oc adm policy reconcile-cluster-roles --additive-only=false --confirm
405
+
402 406
   # Display the union of the default and modified cluster roles
403 407
   $ oc adm policy reconcile-cluster-roles --additive-only
404 408
 ----
... ...
@@ -48,7 +48,7 @@ func NewCommandAdmin(name, fullName string, out io.Writer, errout io.Writer) *co
48 48
 			Message: "Basic Commands:",
49 49
 			Commands: []*cobra.Command{
50 50
 				project.NewCmdNewProject(project.NewProjectRecommendedName, fullName+" "+project.NewProjectRecommendedName, f, out),
51
-				policy.NewCmdPolicy(policy.PolicyRecommendedName, fullName+" "+policy.PolicyRecommendedName, f, out),
51
+				policy.NewCmdPolicy(policy.PolicyRecommendedName, fullName+" "+policy.PolicyRecommendedName, f, out, errout),
52 52
 				groups.NewCmdGroups(groups.GroupsRecommendedName, fullName+" "+groups.GroupsRecommendedName, f, out),
53 53
 			},
54 54
 		},
... ...
@@ -33,7 +33,7 @@ and 'scc'.
33 33
 `
34 34
 
35 35
 // NewCmdPolicy implements the OpenShift cli policy command
36
-func NewCmdPolicy(name, fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
36
+func NewCmdPolicy(name, fullName string, f *clientcmd.Factory, out, errout io.Writer) *cobra.Command {
37 37
 	// Parent command to which all subcommands are added.
38 38
 	cmds := &cobra.Command{
39 39
 		Use:   name,
... ...
@@ -86,7 +86,7 @@ func NewCmdPolicy(name, fullName string, f *clientcmd.Factory, out io.Writer) *c
86 86
 		{
87 87
 			Message: "Upgrade and repair system policy:",
88 88
 			Commands: []*cobra.Command{
89
-				NewCmdReconcileClusterRoles(ReconcileClusterRolesRecommendedName, fullName+" "+ReconcileClusterRolesRecommendedName, f, out),
89
+				NewCmdReconcileClusterRoles(ReconcileClusterRolesRecommendedName, fullName+" "+ReconcileClusterRolesRecommendedName, f, out, errout),
90 90
 				NewCmdReconcileClusterRoleBindings(ReconcileClusterRoleBindingsRecommendedName, fullName+" "+ReconcileClusterRoleBindingsRecommendedName, f, out),
91 91
 				NewCmdReconcileSCC(ReconcileSCCRecommendedName, fullName+" "+ReconcileSCCRecommendedName, f, out),
92 92
 			},
... ...
@@ -41,7 +41,7 @@ type ReconcileClusterRoleBindingsOptions struct {
41 41
 
42 42
 const (
43 43
 	reconcileBindingsLong = `
44
-Replace cluster role bindings to match the recommended bootstrap policy
44
+Update cluster role bindings to match the recommended bootstrap policy
45 45
 
46 46
 This command will inspect the cluster role bindings against the recommended bootstrap policy.
47 47
 Any cluster role binding that does not match will be replaced by the recommended bootstrap role binding.
... ...
@@ -49,8 +49,8 @@ This command will not remove any additional cluster role bindings.
49 49
 
50 50
 You can see which recommended cluster role bindings have changed by choosing an output type.`
51 51
 
52
-	reconcileBindingsExample = `  # Display the cluster role bindings that would be modified
53
-  $ %[1]s
52
+	reconcileBindingsExample = `  # Display the names of cluster role bindings that would be modified
53
+  $ %[1]s -o name
54 54
 
55 55
   # Display the cluster role bindings that would be modified, removing any extra subjects
56 56
   $ %[1]s --additive-only=false
... ...
@@ -77,7 +77,7 @@ func NewCmdReconcileClusterRoleBindings(name, fullName string, f *clientcmd.Fact
77 77
 
78 78
 	cmd := &cobra.Command{
79 79
 		Use:     name + " [ClusterRoleName]...",
80
-		Short:   "Replace cluster role bindings to match the recommended bootstrap policy",
80
+		Short:   "Update cluster role bindings to match the recommended bootstrap policy",
81 81
 		Long:    reconcileBindingsLong,
82 82
 		Example: fmt.Sprintf(reconcileBindingsExample, fullName),
83 83
 		Run: func(cmd *cobra.Command, args []string) {
... ...
@@ -140,9 +140,6 @@ func (o *ReconcileClusterRoleBindingsOptions) Validate() error {
140 140
 	if o.RoleBindingClient == nil {
141 141
 		return errors.New("a role binding client is required")
142 142
 	}
143
-	if o.Output != "yaml" && o.Output != "json" && o.Output != "" {
144
-		return fmt.Errorf("unknown output specified: %s", o.Output)
145
-	}
146 143
 	return nil
147 144
 }
148 145
 
... ...
@@ -21,6 +21,9 @@ import (
21 21
 	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
22 22
 )
23 23
 
24
+// ReconcileProtectAnnotation is the name of an annotation which prevents reconciliation if set to "true"
25
+const ReconcileProtectAnnotation = "openshift.io/reconcile-protect"
26
+
24 27
 // ReconcileClusterRolesRecommendedName is the recommended command name
25 28
 const ReconcileClusterRolesRecommendedName = "reconcile-cluster-roles"
26 29
 
... ...
@@ -33,6 +36,7 @@ type ReconcileClusterRolesOptions struct {
33 33
 	Union     bool
34 34
 
35 35
 	Out    io.Writer
36
+	ErrOut io.Writer
36 37
 	Output string
37 38
 
38 39
 	RoleClient client.ClusterRoleInterface
... ...
@@ -40,35 +44,42 @@ type ReconcileClusterRolesOptions struct {
40 40
 
41 41
 const (
42 42
 	reconcileLong = `
43
-Replace cluster roles to match the recommended bootstrap policy
43
+Update cluster roles to match the recommended bootstrap policy
44 44
 
45
-This command will inspect the cluster roles against the recommended bootstrap policy.  Any cluster role
45
+This command will compare cluster roles against the recommended bootstrap policy.  Any cluster role
46 46
 that does not match will be replaced by the recommended bootstrap role.  This command will not remove
47 47
 any additional cluster role.
48 48
 
49
-You can see which cluster role have recommended changed by choosing an output type.`
49
+Cluster roles with the annotation %s set to "true" are skipped.
50
+
51
+You can see which cluster roles have recommended changed by choosing an output type.`
50 52
 
51
-	reconcileExample = `  # Display the cluster roles that would be modified
52
-  $ %[1]s
53
+	reconcileExample = `  # Display the names of cluster roles that would be modified
54
+  $ %[1]s -o name
53 55
 
54
-  # Replace cluster roles that don't match the current defaults
56
+  # Add missing permissions to cluster roles that don't match the current defaults
55 57
   $ %[1]s --confirm
56 58
 
59
+  # Add missing permissions and remove extra permissions from 
60
+  # cluster roles that don't match the current defaults
61
+  $ %[1]s --additive-only=false --confirm
62
+
57 63
   # Display the union of the default and modified cluster roles
58 64
   $ %[1]s --additive-only`
59 65
 )
60 66
 
61 67
 // NewCmdReconcileClusterRoles implements the OpenShift cli reconcile-cluster-roles command
62
-func NewCmdReconcileClusterRoles(name, fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
68
+func NewCmdReconcileClusterRoles(name, fullName string, f *clientcmd.Factory, out, errout io.Writer) *cobra.Command {
63 69
 	o := &ReconcileClusterRolesOptions{
64
-		Out:   out,
65
-		Union: true,
70
+		Out:    out,
71
+		ErrOut: errout,
72
+		Union:  true,
66 73
 	}
67 74
 
68 75
 	cmd := &cobra.Command{
69 76
 		Use:     name + " [ClusterRoleName]...",
70
-		Short:   "Replace cluster roles to match the recommended bootstrap policy",
71
-		Long:    reconcileLong,
77
+		Short:   "Update cluster roles to match the recommended bootstrap policy",
78
+		Long:    fmt.Sprintf(reconcileLong, ReconcileProtectAnnotation),
72 79
 		Example: fmt.Sprintf(reconcileExample, fullName),
73 80
 		Run: func(cmd *cobra.Command, args []string) {
74 81
 			if err := o.Complete(cmd, f, args); err != nil {
... ...
@@ -126,19 +137,23 @@ func (o *ReconcileClusterRolesOptions) Validate() error {
126 126
 	if o.RoleClient == nil {
127 127
 		return errors.New("a role client is required")
128 128
 	}
129
-	if o.Output != "yaml" && o.Output != "json" && o.Output != "" {
130
-		return fmt.Errorf("unknown output specified: %s", o.Output)
131
-	}
132 129
 	return nil
133 130
 }
134 131
 
135 132
 // RunReconcileClusterRoles contains all the necessary functionality for the OpenShift cli reconcile-cluster-roles command
136 133
 func (o *ReconcileClusterRolesOptions) RunReconcileClusterRoles(cmd *cobra.Command, f *clientcmd.Factory) error {
137
-	changedClusterRoles, err := o.ChangedClusterRoles()
134
+	changedClusterRoles, skippedClusterRoles, err := o.ChangedClusterRoles()
138 135
 	if err != nil {
139 136
 		return err
140 137
 	}
141 138
 
139
+	if len(skippedClusterRoles) > 0 {
140
+		fmt.Fprintf(o.ErrOut, "Skipped reconciling roles with the annotation %s=true\n", ReconcileProtectAnnotation)
141
+		for _, role := range skippedClusterRoles {
142
+			fmt.Fprintf(o.ErrOut, "skipped: clusterrole/%s\n", role.Name)
143
+		}
144
+	}
145
+
142 146
 	if len(changedClusterRoles) == 0 {
143 147
 		return nil
144 148
 	}
... ...
@@ -164,8 +179,9 @@ func (o *ReconcileClusterRolesOptions) RunReconcileClusterRoles(cmd *cobra.Comma
164 164
 
165 165
 // ChangedClusterRoles returns the roles that must be created and/or updated to
166 166
 // match the recommended bootstrap policy
167
-func (o *ReconcileClusterRolesOptions) ChangedClusterRoles() ([]*authorizationapi.ClusterRole, error) {
167
+func (o *ReconcileClusterRolesOptions) ChangedClusterRoles() ([]*authorizationapi.ClusterRole, []*authorizationapi.ClusterRole, error) {
168 168
 	changedRoles := []*authorizationapi.ClusterRole{}
169
+	skippedRoles := []*authorizationapi.ClusterRole{}
169 170
 
170 171
 	rolesToReconcile := sets.NewString(o.RolesToReconcile...)
171 172
 	rolesNotFound := sets.NewString(o.RolesToReconcile...)
... ...
@@ -183,7 +199,7 @@ func (o *ReconcileClusterRolesOptions) ChangedClusterRoles() ([]*authorizationap
183 183
 			continue
184 184
 		}
185 185
 		if err != nil {
186
-			return nil, err
186
+			return nil, nil, err
187 187
 		}
188 188
 
189 189
 		// Copy any existing labels/annotations, so the displayed update is correct
... ...
@@ -202,16 +218,21 @@ func (o *ReconcileClusterRolesOptions) ChangedClusterRoles() ([]*authorizationap
202 202
 			if o.Union {
203 203
 				expectedClusterRole.Rules = append(expectedClusterRole.Rules, extraRules...)
204 204
 			}
205
-			changedRoles = append(changedRoles, expectedClusterRole)
205
+
206
+			if actualClusterRole.Annotations[ReconcileProtectAnnotation] == "true" {
207
+				skippedRoles = append(skippedRoles, expectedClusterRole)
208
+			} else {
209
+				changedRoles = append(changedRoles, expectedClusterRole)
210
+			}
206 211
 		}
207 212
 	}
208 213
 
209 214
 	if len(rolesNotFound) != 0 {
210 215
 		// return the known changes and the error so that a caller can decide if he wants a partial update
211
-		return changedRoles, fmt.Errorf("did not find requested cluster role %s", rolesNotFound.List())
216
+		return changedRoles, skippedRoles, fmt.Errorf("did not find requested cluster role %s", rolesNotFound.List())
212 217
 	}
213 218
 
214
-	return changedRoles, nil
219
+	return changedRoles, skippedRoles, nil
215 220
 }
216 221
 
217 222
 // ReplaceChangedRoles will reconcile all the changed roles back to the recommended bootstrap policy
... ...
@@ -124,9 +124,6 @@ func (o *ReconcileSCCOptions) Validate() error {
124 124
 	if o.SCCClient == nil {
125 125
 		return errors.New("a SCC client is required")
126 126
 	}
127
-	if o.Output != "yaml" && o.Output != "json" && o.Output != "" {
128
-		return fmt.Errorf("unknown output specified: %s", o.Output)
129
-	}
130 127
 	if _, err := o.NSClient.Get(o.InfraNamespace); err != nil {
131 128
 		return fmt.Errorf("%s is not a valid namespace", o.InfraNamespace)
132 129
 	}
... ...
@@ -56,7 +56,7 @@ func (d *ClusterRoles) Check() types.DiagnosticResult {
56 56
 		RoleClient: d.ClusterRolesClient.ClusterRoles(),
57 57
 	}
58 58
 
59
-	changedClusterRoles, err := reconcileOptions.ChangedClusterRoles()
59
+	changedClusterRoles, _, err := reconcileOptions.ChangedClusterRoles()
60 60
 	if err != nil {
61 61
 		r.Error("CRD1000", err, fmt.Sprintf("Error inspecting ClusterRoles: %v", err))
62 62
 		return r
... ...
@@ -24,8 +24,8 @@ trap os::test::junit::reconcile_output EXIT
24 24
   oc delete users/orphaned-user
25 25
   oc delete identities/anypassword:orphaned-user
26 26
   oc delete identities/anypassword:cascaded-user
27
-  oadm policy reconcile-cluster-roles --confirm
28
-  oadm policy reconcile-cluster-role-bindings --confirm
27
+  oadm policy reconcile-cluster-roles --confirm --additive-only=false
28
+  oadm policy reconcile-cluster-role-bindings --confirm --additive-only=false
29 29
 ) &>/dev/null
30 30
 
31 31
 
... ...
@@ -176,11 +176,28 @@ os::cmd::expect_failure 'oc get clusterrole/cluster-status'
176 176
 os::cmd::expect_success 'oadm policy reconcile-cluster-roles clusterrole/cluster-status --confirm'
177 177
 os::cmd::expect_success 'oc get clusterrole/cluster-status'
178 178
 
179
-os::cmd::expect_success 'oc replace --force -f ./test/fixtures/basic-user.json'
179
+# test reconciliation protection by replacing the basic-user role with one that has missing default permissions, and extra non-default permissions
180
+os::cmd::expect_success 'oc replace --force -f ./test/fixtures/basic-user-with-groups-without-projectrequests.yaml'
181
+# 1. mark the role as protected, and ensure the role is skipped by reconciliation
182
+os::cmd::expect_success 'oc annotate clusterrole/basic-user openshift.io/reconcile-protect=true'
183
+os::cmd::expect_success_and_text     'oadm policy reconcile-cluster-roles basic-user --additive-only=false --confirm' 'skipped: clusterrole/basic-user'
184
+# 2. unmark the role as protected, and ensure reconcile expects to remove extra permissions, and put back removed permissions
185
+os::cmd::expect_success 'oc annotate clusterrole/basic-user openshift.io/reconcile-protect=false --overwrite'
186
+os::cmd::expect_success_and_text     'oc get clusterrole/basic-user -o jsonpath="{.rules[*].resources}"' 'groups'
187
+os::cmd::expect_success_and_not_text 'oc get clusterrole/basic-user -o jsonpath="{.rules[*].resources}"' 'projectrequests'
188
+os::cmd::expect_success_and_not_text 'oadm policy reconcile-cluster-roles basic-user -o jsonpath="{.items[*].rules[*].resources}" --additive-only=false' 'groups'
189
+os::cmd::expect_success_and_text     'oadm policy reconcile-cluster-roles basic-user -o jsonpath="{.items[*].rules[*].resources}" --additive-only=false' 'projectrequests'
190
+# reconcile updates the role
191
+os::cmd::expect_success_and_text     'oadm policy reconcile-cluster-roles basic-user --additive-only=false --confirm' 'clusterrole/basic-user'
192
+# a second reconcile doesn't need to update the role
193
+os::cmd::expect_success_and_not_text 'oadm policy reconcile-cluster-roles basic-user --additive-only=false --confirm' 'clusterrole/basic-user'
194
+
195
+# test label/annotation reconciliation by replacing the basic-user role with one that has custom labels, annotations, and permissions
196
+os::cmd::expect_success 'oc replace --force -f ./test/fixtures/basic-user-with-annotations-labels-groups-without-projectrequests.yaml'
180 197
 # display shows customized labels/annotations
181 198
 os::cmd::expect_success_and_text 'oadm policy reconcile-cluster-roles' 'custom-label'
182 199
 os::cmd::expect_success_and_text 'oadm policy reconcile-cluster-roles' 'custom-annotation'
183
-os::cmd::expect_success 'oadm policy reconcile-cluster-roles --additive-only --confirm'
200
+os::cmd::expect_success_and_text 'oadm policy reconcile-cluster-roles --additive-only --confirm' 'clusterrole/basic-user'
184 201
 # reconcile preserves added rules, labels, and annotations
185 202
 os::cmd::expect_success_and_text 'oc get clusterroles/basic-user -o json' 'custom-label'
186 203
 os::cmd::expect_success_and_text 'oc get clusterroles/basic-user -o json' 'custom-annotation'
... ...
@@ -46,7 +46,7 @@ os::cmd::expect_failure_and_text 'oc process template-name key=value other=foo -
46 46
 required_params="${OS_ROOT}/test/fixtures/template_required_params.yaml"
47 47
 
48 48
 # providing something other than a template is not OK
49
-os::cmd::expect_failure_and_text "oc process -f '${OS_ROOT}/test/fixtures/basic-user.json'" 'not a valid Template but'
49
+os::cmd::expect_failure_and_text "oc process -f '${OS_ROOT}/test/fixtures/basic-users-binding.json'" 'not a valid Template but'
50 50
 
51 51
 # not providing required parameter should fail
52 52
 os::cmd::expect_failure_and_text "oc process -f '${required_params}'" 'parameter required_param is required and must be specified'
53 53
new file mode 100644
... ...
@@ -0,0 +1,57 @@
0
+apiVersion: v1
1
+kind: ClusterRole
2
+metadata:
3
+  name: basic-user
4
+  labels:
5
+    # custom labels
6
+    custom-label: "value"
7
+  annotations:
8
+    # custom annotations
9
+    custom-annotation: "value"
10
+rules:
11
+- apiGroups: null
12
+  attributeRestrictions: null
13
+  resourceNames:
14
+  - "~"
15
+  resources:
16
+  - users
17
+  # add an extra resource permission:
18
+  - groups
19
+  verbs:
20
+  - get
21
+# remove default permission:
22
+# - apiGroups: null
23
+#   attributeRestrictions: null
24
+#   resources:
25
+#   - projectrequests
26
+#   verbs:
27
+#   - list
28
+- apiGroups: null
29
+  attributeRestrictions: null
30
+  resources:
31
+  - clusterroles
32
+  verbs:
33
+  - get
34
+  - list
35
+- apiGroups: null
36
+  attributeRestrictions: null
37
+  resources:
38
+  - projects
39
+  verbs:
40
+  - list
41
+  - watch
42
+- apiGroups: null
43
+  attributeRestrictions:
44
+    apiVersion: v1
45
+    kind: IsPersonalSubjectAccessReview
46
+  resources:
47
+  - localsubjectaccessreviews
48
+  - subjectaccessreviews
49
+  verbs:
50
+  - create
51
+- apiGroups: null
52
+  attributeRestrictions: null
53
+  resources:
54
+  - selfsubjectrulesreviews
55
+  verbs:
56
+  - create
0 57
new file mode 100644
... ...
@@ -0,0 +1,51 @@
0
+apiVersion: v1
1
+kind: ClusterRole
2
+metadata:
3
+  name: basic-user
4
+rules:
5
+- apiGroups: null
6
+  attributeRestrictions: null
7
+  resourceNames:
8
+  - "~"
9
+  resources:
10
+  - users
11
+  # add an extra resource permission:
12
+  - groups
13
+  verbs:
14
+  - get
15
+# remove a default permission:
16
+# - apiGroups: null
17
+#   attributeRestrictions: null
18
+#   resources:
19
+#   - projectrequests
20
+#   verbs:
21
+#   - list
22
+- apiGroups: null
23
+  attributeRestrictions: null
24
+  resources:
25
+  - clusterroles
26
+  verbs:
27
+  - get
28
+  - list
29
+- apiGroups: null
30
+  attributeRestrictions: null
31
+  resources:
32
+  - projects
33
+  verbs:
34
+  - list
35
+  - watch
36
+- apiGroups: null
37
+  attributeRestrictions:
38
+    apiVersion: v1
39
+    kind: IsPersonalSubjectAccessReview
40
+  resources:
41
+  - localsubjectaccessreviews
42
+  - subjectaccessreviews
43
+  verbs:
44
+  - create
45
+- apiGroups: null
46
+  attributeRestrictions: null
47
+  resources:
48
+  - selfsubjectrulesreviews
49
+  verbs:
50
+  - create
0 51
deleted file mode 100644
... ...
@@ -1,83 +0,0 @@
1
-{
2
-    "kind": "ClusterRole",
3
-    "apiVersion": "v1",
4
-    "metadata": {
5
-        "name": "basic-user",
6
-        "selfLink": "/osapi/v1beta3/clusterroles/basic-user",
7
-        "uid": "86a5ce7c-3f44-11e5-a9a6-080027c5bfa9",
8
-        "resourceVersion": "18",
9
-        "creationTimestamp": "2015-08-10T09:45:25Z",
10
-        "labels": {
11
-        	"custom-label":"value"
12
-        },
13
-        "annotations": {
14
-        	"custom-annotation":"value"
15
-        }
16
-    },
17
-    "rules": [
18
-        {
19
-            "verbs": [
20
-                "get"
21
-            ],
22
-            "attributeRestrictions": null,
23
-            "resources": [
24
-                "users"
25
-            ],
26
-            "resourceNames": [
27
-                "~"
28
-            ]
29
-        },
30
-        {
31
-            "verbs": [
32
-                "get"
33
-            ],
34
-            "attributeRestrictions": null,
35
-            "resources": [
36
-                "groups"
37
-            ],
38
-            "resourceNames": [
39
-                "~"
40
-            ]
41
-        },
42
-        {
43
-            "verbs": [
44
-                "list"
45
-            ],
46
-            "attributeRestrictions": null,
47
-            "resources": [
48
-                "projectrequests"
49
-            ]
50
-        },
51
-        {
52
-            "verbs": [
53
-                "get",
54
-                "list"
55
-            ],
56
-            "attributeRestrictions": null,
57
-            "resources": [
58
-                "clusterroles"
59
-            ]
60
-        },
61
-        {
62
-            "verbs": [
63
-                "list"
64
-            ],
65
-            "attributeRestrictions": null,
66
-            "resources": [
67
-                "projects"
68
-            ]
69
-        },
70
-        {
71
-            "verbs": [
72
-                "create"
73
-            ],
74
-            "attributeRestrictions": {
75
-                "kind": "IsPersonalSubjectAccessReview",
76
-                "apiVersion": "v1"
77
-            },
78
-            "resources": [
79
-                "subjectaccessreviews"
80
-            ]
81
-        }
82
-    ]
83
-}