diff --git a/pkg/authorization/authorizer/subjects_test.go b/pkg/authorization/authorizer/subjects_test.go index 94bfd1139c41..619ea8d100d8 100644 --- a/pkg/authorization/authorizer/subjects_test.go +++ b/pkg/authorization/authorizer/subjects_test.go @@ -34,7 +34,7 @@ func TestSubjects(t *testing.T) { Verb: "get", Resource: "pods", }, - expectedUsers: sets.NewString("Anna", "ClusterAdmin", "Ellen", "Valerie", "system:serviceaccount:adze:second", "system:serviceaccount:foo:default", "system:serviceaccount:other:first"), + expectedUsers: sets.NewString("Anna", "ClusterAdmin", "Ellen", "Valerie", "system:serviceaccount:adze:second", "system:serviceaccount:foo:default", "system:serviceaccount:other:first", "system:admin"), expectedGroups: sets.NewString("RootUsers", "system:cluster-admins", "system:cluster-readers", "system:masters", "system:nodes"), } test.clusterPolicies = newDefaultClusterPolicies() diff --git a/pkg/cmd/server/bootstrappolicy/constants.go b/pkg/cmd/server/bootstrappolicy/constants.go index 45c385e78573..699f51d94c42 100644 --- a/pkg/cmd/server/bootstrappolicy/constants.go +++ b/pkg/cmd/server/bootstrappolicy/constants.go @@ -16,9 +16,10 @@ const ( RouterUnqualifiedUsername = "openshift-router" RegistryUnqualifiedUsername = "openshift-registry" - MasterUsername = "system:" + MasterUnqualifiedUsername - RouterUsername = "system:" + RouterUnqualifiedUsername - RegistryUsername = "system:" + RegistryUnqualifiedUsername + MasterUsername = "system:" + MasterUnqualifiedUsername + RouterUsername = "system:" + RouterUnqualifiedUsername + RegistryUsername = "system:" + RegistryUnqualifiedUsername + SystemAdminUsername = "system:admin" // Not granted any API permissions, just an identity for a client certificate for the API proxy to use // Should not be changed without considering impact to pods that may be verifying this identity by default @@ -51,6 +52,7 @@ const ( // Roles const ( ClusterAdminRoleName = "cluster-admin" + SudoerRoleName = "sudoer" ClusterReaderRoleName = "cluster-reader" AdminRoleName = "admin" EditRoleName = "edit" diff --git a/pkg/cmd/server/bootstrappolicy/policy.go b/pkg/cmd/server/bootstrappolicy/policy.go index 222f17a98eae..2f83c28fc328 100644 --- a/pkg/cmd/server/bootstrappolicy/policy.go +++ b/pkg/cmd/server/bootstrappolicy/policy.go @@ -64,6 +64,19 @@ func GetBootstrapClusterRoles() []authorizationapi.ClusterRole { }, }, }, + { + ObjectMeta: kapi.ObjectMeta{ + Name: SudoerRoleName, + }, + Rules: []authorizationapi.PolicyRule{ + { + APIGroups: []string{kapi.GroupName}, + Verbs: sets.NewString("impersonate"), + Resources: sets.NewString(authorizationapi.SystemUserResource), + ResourceNames: sets.NewString(SystemAdminUsername), + }, + }, + }, { ObjectMeta: kapi.ObjectMeta{ Name: ClusterReaderRoleName, @@ -162,6 +175,11 @@ func GetBootstrapClusterRoles() []authorizationapi.ClusterRole { "replicationcontrollers/scale", ), }, + { + APIGroups: []string{kapi.GroupName}, + Verbs: sets.NewString("impersonate"), + Resources: sets.NewString("serviceaccounts"), + }, { APIGroups: []string{api.GroupName}, Verbs: sets.NewString("get", "list", "watch", "create", "update", "patch", "delete", "deletecollection"), @@ -225,6 +243,11 @@ func GetBootstrapClusterRoles() []authorizationapi.ClusterRole { "replicationcontrollers/scale", ), }, + { + APIGroups: []string{kapi.GroupName}, + Verbs: sets.NewString("impersonate"), + Resources: sets.NewString("serviceaccounts"), + }, { APIGroups: []string{api.GroupName}, Verbs: sets.NewString("get", "list", "watch", "create", "update", "patch", "delete", "deletecollection"), @@ -858,7 +881,11 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding { RoleRef: kapi.ObjectReference{ Name: ClusterAdminRoleName, }, - Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: ClusterAdminGroup}}, + Subjects: []kapi.ObjectReference{ + {Kind: authorizationapi.SystemGroupKind, Name: ClusterAdminGroup}, + // add system:admin to this binding so that members of the sudoer group can use --as=system:admin to run a command as a cluster-admin + {Kind: authorizationapi.SystemUserKind, Name: SystemAdminUsername}, + }, }, { ObjectMeta: kapi.ObjectMeta{ diff --git a/test/cmd/policy.sh b/test/cmd/policy.sh index e46ca8f53654..c7908fd23202 100755 --- a/test/cmd/policy.sh +++ b/test/cmd/policy.sh @@ -15,6 +15,21 @@ os::test::junit::declare_suite_start "cmd/policy" # This test validates user level policy os::cmd::expect_success_and_text 'oc whoami --as deads' "deads" +os::cmd::expect_success 'oadm policy add-cluster-role-to-user sudoer wheel' +os::cmd::expect_success 'oc login -u wheel -p pw' +os::cmd::expect_success_and_text 'oc whoami' "wheel" +os::cmd::expect_failure 'oc whoami --as deads' +os::cmd::expect_success_and_text 'oc whoami --as=system:admin' "system:admin" + +os::cmd::expect_success 'oc login -u local-admin -p pw' +os::cmd::expect_success 'oc new-project foo' +os::cmd::expect_failure 'oc whoami --as=system:admin' +os::cmd::expect_success_and_text 'oc whoami --as=system:serviceaccount:foo:default' "system:serviceaccount:foo:default" +os::cmd::expect_failure 'oc whoami --as=system:serviceaccount:another:default' +os::cmd::expect_success 'oc login -u system:admin -n cmd-policy' +os::cmd::expect_success 'oc delete project foo' + + # This test validates user level policy os::cmd::expect_failure_and_text 'oc policy add-role-to-user' 'you must specify a role' os::cmd::expect_failure_and_text 'oc policy add-role-to-user -z NamespaceWithoutRole' 'you must specify a role' diff --git a/test/fixtures/bootstrappolicy/bootstrap_cluster_role_bindings.yaml b/test/fixtures/bootstrappolicy/bootstrap_cluster_role_bindings.yaml index fb117d878a8b..193aeb590898 100644 --- a/test/fixtures/bootstrappolicy/bootstrap_cluster_role_bindings.yaml +++ b/test/fixtures/bootstrappolicy/bootstrap_cluster_role_bindings.yaml @@ -41,7 +41,10 @@ items: subjects: - kind: SystemGroup name: system:cluster-admins - userNames: null + - kind: SystemUser + name: system:admin + userNames: + - system:admin - apiVersion: v1 groupNames: - system:cluster-readers diff --git a/test/fixtures/bootstrappolicy/bootstrap_cluster_roles.yaml b/test/fixtures/bootstrappolicy/bootstrap_cluster_roles.yaml index 59858dee50bc..69f13d7a3d71 100644 --- a/test/fixtures/bootstrappolicy/bootstrap_cluster_roles.yaml +++ b/test/fixtures/bootstrappolicy/bootstrap_cluster_roles.yaml @@ -20,6 +20,21 @@ items: resources: [] verbs: - '*' +- apiVersion: v1 + kind: ClusterRole + metadata: + creationTimestamp: null + name: sudoer + rules: + - apiGroups: + - "" + attributeRestrictions: null + resourceNames: + - system:admin + resources: + - systemusers + verbs: + - impersonate - apiVersion: v1 kind: ClusterRole metadata: @@ -231,6 +246,13 @@ items: - patch - update - watch + - apiGroups: + - "" + attributeRestrictions: null + resources: + - serviceaccounts + verbs: + - impersonate - apiGroups: - "" attributeRestrictions: null @@ -408,6 +430,13 @@ items: - patch - update - watch + - apiGroups: + - "" + attributeRestrictions: null + resources: + - serviceaccounts + verbs: + - impersonate - apiGroups: - "" attributeRestrictions: null diff --git a/test/integration/authorization_test.go b/test/integration/authorization_test.go index 8a49a0897527..024484324a51 100644 --- a/test/integration/authorization_test.go +++ b/test/integration/authorization_test.go @@ -175,11 +175,11 @@ func TestAuthorizationResolution(t *testing.T) { } // TODO this list should start collapsing as we continue to tighten access on generated system ids -var globalClusterAdminUsers = sets.NewString() +var globalClusterAdminUsers = sets.NewString("system:admin") var globalClusterAdminGroups = sets.NewString("system:cluster-admins", "system:masters") // This list includes the admins from above, plus users or groups known to have global view access -var globalClusterReaderUsers = sets.NewString("system:serviceaccount:openshift-infra:namespace-controller") +var globalClusterReaderUsers = sets.NewString("system:serviceaccount:openshift-infra:namespace-controller", "system:admin") var globalClusterReaderGroups = sets.NewString("system:cluster-readers", "system:cluster-admins", "system:masters") type resourceAccessReviewTest struct { @@ -1052,7 +1052,7 @@ func TestOldLocalResourceAccessReviewEndpoint(t *testing.T) { expectedResponse := &authorizationapi.ResourceAccessReviewResponse{ Namespace: namespace, - Users: sets.NewString("harold", "system:serviceaccount:hammer-project:builder", "system:serviceaccount:openshift-infra:namespace-controller"), + Users: sets.NewString("harold", "system:serviceaccount:hammer-project:builder", "system:serviceaccount:openshift-infra:namespace-controller", "system:admin"), Groups: sets.NewString("system:cluster-admins", "system:masters", "system:serviceaccounts:hammer-project"), } if (actualResponse.Namespace != expectedResponse.Namespace) || @@ -1079,7 +1079,7 @@ func TestOldLocalResourceAccessReviewEndpoint(t *testing.T) { expectedResponse := &authorizationapi.ResourceAccessReviewResponse{ Namespace: namespace, - Users: sets.NewString("harold", "system:serviceaccount:hammer-project:builder", "system:serviceaccount:openshift-infra:namespace-controller"), + Users: sets.NewString("harold", "system:serviceaccount:hammer-project:builder", "system:serviceaccount:openshift-infra:namespace-controller", "system:admin"), Groups: sets.NewString("system:cluster-admins", "system:masters", "system:serviceaccounts:hammer-project"), } if (actualResponse.Namespace != expectedResponse.Namespace) ||