Skip to content

Commit f3d2562

Browse files
author
OpenShift Bot
committed
Merge pull request #8766 from deads2k/project-request-limit
Merged by openshift-bot
2 parents fd7caa6 + 4142134 commit f3d2562

File tree

6 files changed

+67
-2
lines changed

6 files changed

+67
-2
lines changed

pkg/project/admission/requestlimit/admission.go

+20
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
kapi "k8s.io/kubernetes/pkg/api"
1111
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
1212
"k8s.io/kubernetes/pkg/labels"
13+
"k8s.io/kubernetes/pkg/serviceaccount"
1314

1415
"github.com/openshift/origin/pkg/client"
1516
oadmission "github.com/openshift/origin/pkg/cmd/server/admission"
@@ -18,6 +19,7 @@ import (
1819
requestlimitapivalidation "github.com/openshift/origin/pkg/project/admission/requestlimit/api/validation"
1920
projectapi "github.com/openshift/origin/pkg/project/api"
2021
projectcache "github.com/openshift/origin/pkg/project/cache"
22+
uservalidation "github.com/openshift/origin/pkg/user/api/validation"
2123
)
2224

2325
// allowedTerminatingProjects is the number of projects that are owned by a user, are in terminating state,
@@ -98,6 +100,24 @@ func (o *projectRequestLimit) Admit(a admission.Attributes) (err error) {
98100
// maxProjectsByRequester returns the maximum number of projects allowed for a given user, whether a limit exists, and an error
99101
// if an error occurred. If a limit doesn't exist, the maximum number should be ignored.
100102
func (o *projectRequestLimit) maxProjectsByRequester(userName string) (int, bool, error) {
103+
// service accounts have a different ruleset, check them
104+
if _, _, err := serviceaccount.SplitUsername(userName); err == nil {
105+
if o.config.MaxProjectsForServiceAccounts == nil {
106+
return 0, false, nil
107+
}
108+
109+
return *o.config.MaxProjectsForServiceAccounts, true, nil
110+
}
111+
112+
// if we aren't a valid username, we came in as cert user for certain, use our cert user rules
113+
if valid, _ := uservalidation.ValidateUserName(userName, false); !valid {
114+
if o.config.MaxProjectsForSystemUsers == nil {
115+
return 0, false, nil
116+
}
117+
118+
return *o.config.MaxProjectsForSystemUsers, true, nil
119+
}
120+
101121
// prevent a user lookup if no limits are configured
102122
if len(o.config.Limits) == 0 {
103123
return 0, false, nil

pkg/project/admission/requestlimit/api/types.go

+9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ import (
1010
type ProjectRequestLimitConfig struct {
1111
unversioned.TypeMeta
1212
Limits []ProjectLimitBySelector
13+
14+
// MaxProjectsForSystemUsers controls how many projects a certificate user may have. Certificate
15+
// users do not have any labels associated with them for more fine grained control
16+
MaxProjectsForSystemUsers *int
17+
18+
// MaxProjectsForServiceAccounts controls how many projects a service account may have. Service
19+
// accounts can't create projects by default, but if they are allowed to create projects, you cannot
20+
// trust any labels placed on them since project editors can manipulate those labels
21+
MaxProjectsForServiceAccounts *int
1322
}
1423

1524
// ProjectLimitBySelector specifies the maximum number of projects allowed for a given user label selector

pkg/project/admission/requestlimit/api/v1/swagger_doc.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ func (ProjectLimitBySelector) SwaggerDoc() map[string]string {
1616
}
1717

1818
var map_ProjectRequestLimitConfig = map[string]string{
19-
"": "ProjectRequestLimitConfig is the configuration for the project request limit plug-in It contains an ordered list of limits based on user label selectors. Selectors will be checked in order and the first one that applies will be used as the limit.",
20-
"limits": "Limits are the project request limits",
19+
"": "ProjectRequestLimitConfig is the configuration for the project request limit plug-in It contains an ordered list of limits based on user label selectors. Selectors will be checked in order and the first one that applies will be used as the limit.",
20+
"limits": "Limits are the project request limits",
21+
"maxProjectsForSystemUsers": "MaxProjectsForSystemUsers controls how many projects a certificate user may have. Certificate users do not have any labels associated with them for more fine grained control",
22+
"maxProjectsForServiceAccounts": "MaxProjectsForServiceAccounts controls how many projects a service account may have. Service accounts can't create projects by default, but if they are allowed to create projects, you cannot trust any labels placed on them since project editors can manipulate those labels",
2123
}
2224

2325
func (ProjectRequestLimitConfig) SwaggerDoc() map[string]string {

pkg/project/admission/requestlimit/api/v1/types.go

+9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ type ProjectRequestLimitConfig struct {
1212

1313
// Limits are the project request limits
1414
Limits []ProjectLimitBySelector `json:"limits",description:"project request limits"`
15+
16+
// MaxProjectsForSystemUsers controls how many projects a certificate user may have. Certificate
17+
// users do not have any labels associated with them for more fine grained control
18+
MaxProjectsForSystemUsers *int `json:"maxProjectsForSystemUsers"`
19+
20+
// MaxProjectsForServiceAccounts controls how many projects a service account may have. Service
21+
// accounts can't create projects by default, but if they are allowed to create projects, you cannot
22+
// trust any labels placed on them since project editors can manipulate those labels
23+
MaxProjectsForServiceAccounts *int `json:"maxProjectsForServiceAccounts"`
1524
}
1625

1726
// ProjectLimitBySelector specifies the maximum number of projects allowed for a given user label selector

pkg/project/admission/requestlimit/api/validation/validation.go

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ func ValidateProjectRequestLimitConfig(config *api.ProjectRequestLimitConfig) fi
1212
for i, projectLimit := range config.Limits {
1313
allErrs = append(allErrs, ValidateProjectLimitBySelector(projectLimit, field.NewPath("limits").Index(i))...)
1414
}
15+
if config.MaxProjectsForSystemUsers != nil && *config.MaxProjectsForSystemUsers < 0 {
16+
allErrs = append(allErrs, field.Invalid(field.NewPath("maxProjectsForSystemUsers"), *config.MaxProjectsForSystemUsers, "cannot be a negative number"))
17+
}
18+
if config.MaxProjectsForServiceAccounts != nil && *config.MaxProjectsForServiceAccounts < 0 {
19+
allErrs = append(allErrs, field.Invalid(field.NewPath("maxProjectsForServiceAccounts"), *config.MaxProjectsForServiceAccounts, "cannot be a negative number"))
20+
}
1521
return allErrs
1622
}
1723

test/integration/project_reqlimit_test.go

+19
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ func projectRequestLimitSingleDefaultConfig() *requestlimit.ProjectRequestLimitC
111111
MaxProjects: intPointer(1),
112112
},
113113
},
114+
115+
MaxProjectsForSystemUsers: intPointer(1),
114116
}
115117
}
116118

@@ -167,6 +169,23 @@ func TestProjectRequestLimitSingleConfig(t *testing.T) {
167169
})
168170
}
169171

172+
// we had a bug where this failed on ` uenxpected error: metadata.name: Invalid value: "system:admin": may not contain ":"`
173+
// make sure we never have that bug again and that project limits for them work
174+
func TestProjectRequestLimitAsSystemAdmin(t *testing.T) {
175+
_, oclient, _ := setupProjectRequestLimitTest(t, projectRequestLimitSingleDefaultConfig())
176+
177+
if _, err := oclient.ProjectRequests().Create(&projectapi.ProjectRequest{
178+
ObjectMeta: kapi.ObjectMeta{Name: "foo"},
179+
}); err != nil {
180+
t.Errorf("uenxpected error: %v", err)
181+
}
182+
if _, err := oclient.ProjectRequests().Create(&projectapi.ProjectRequest{
183+
ObjectMeta: kapi.ObjectMeta{Name: "bar"},
184+
}); !apierrors.IsForbidden(err) {
185+
t.Errorf("missing error: %v", err)
186+
}
187+
}
188+
170189
func testProjectRequestLimitAdmission(t *testing.T, errorPrefix string, clientConfig *restclient.Config, tests map[string]bool) {
171190
for user, expectSuccess := range tests {
172191
oclient, _, _, err := testutil.GetClientForUser(*clientConfig, user)

0 commit comments

Comments
 (0)