| ... | ... |
@@ -81,15 +81,6 @@ func fuzzInternalObject(t *testing.T, forVersion unversioned.GroupVersion, item |
| 81 | 81 |
obj.PodEvictionTimeout = "5m" |
| 82 | 82 |
} |
| 83 | 83 |
}, |
| 84 |
- func(obj *configapi.LegacyClientPolicyConfig, c fuzz.Continue) {
|
|
| 85 |
- c.FuzzNoCustom(obj) |
|
| 86 |
- if len(obj.LegacyClientPolicy) == 0 {
|
|
| 87 |
- obj.LegacyClientPolicy = configapi.AllowAll |
|
| 88 |
- } |
|
| 89 |
- if len(obj.RestrictedHTTPVerbs) == 0 {
|
|
| 90 |
- obj.RestrictedHTTPVerbs = []string{"PUT", "POST"}
|
|
| 91 |
- } |
|
| 92 |
- }, |
|
| 93 | 84 |
func(obj *configapi.NodeConfig, c fuzz.Continue) {
|
| 94 | 85 |
c.FuzzNoCustom(obj) |
| 95 | 86 |
// Defaults/migrations for NetworkConfig |
| ... | ... |
@@ -318,28 +318,38 @@ type PolicyConfig struct {
|
| 318 | 318 |
// OpenShiftInfrastructureNamespace is the namespace where OpenShift infrastructure resources live (like controller service accounts) |
| 319 | 319 |
OpenShiftInfrastructureNamespace string |
| 320 | 320 |
|
| 321 |
- // LegacyClientPolicyConfig controls how API calls from *voluntarily* identifying clients will be handled. THIS DOES NOT DEFEND AGAINST MALICIOUS CLIENTS! |
|
| 322 |
- LegacyClientPolicyConfig LegacyClientPolicyConfig |
|
| 321 |
+ // UserAgentMatchingConfig controls how API calls from *voluntarily* identifying clients will be handled. THIS DOES NOT DEFEND AGAINST MALICIOUS CLIENTS! |
|
| 322 |
+ UserAgentMatchingConfig UserAgentMatchingConfig |
|
| 323 | 323 |
} |
| 324 | 324 |
|
| 325 |
-type LegacyClientPolicyConfig struct {
|
|
| 326 |
- // LegacyClientPolicy controls how API calls from *voluntarily* identifying clients will be handled. THIS DOES NOT DEFEND AGAINST MALICIOUS CLIENTS! |
|
| 327 |
- // The default is AllowAll |
|
| 328 |
- LegacyClientPolicy LegacyClientPolicy |
|
| 329 |
- // RestrictedHTTPVerbs specifies which HTTP verbs are restricted. By default this is PUT and POST |
|
| 330 |
- RestrictedHTTPVerbs []string |
|
| 325 |
+// UserAgentMatchingConfig controls how API calls from *voluntarily* identifying clients will be handled. THIS DOES NOT DEFEND AGAINST MALICIOUS CLIENTS! |
|
| 326 |
+type UserAgentMatchingConfig struct {
|
|
| 327 |
+ // If this list is non-empty, then a User-Agent must match one of the UserAgentRegexes to be allowed |
|
| 328 |
+ RequiredClients []UserAgentMatchRule |
|
| 329 |
+ |
|
| 330 |
+ // If this list is non-empty, then a User-Agent must not match any of the UserAgentRegexes |
|
| 331 |
+ DeniedClients []UserAgentDenyRule |
|
| 332 |
+ |
|
| 333 |
+ // DefaultRejectionMessage is the message shown when rejecting a client. If it is not a set, a generic message is given. |
|
| 334 |
+ DefaultRejectionMessage string |
|
| 331 | 335 |
} |
| 332 | 336 |
|
| 333 |
-type LegacyClientPolicy string |
|
| 337 |
+// UserAgentMatchRule describes how to match a given request based on User-Agent and HTTPVerb |
|
| 338 |
+type UserAgentMatchRule struct {
|
|
| 339 |
+ // UserAgentRegex is a regex that is checked against the User-Agent. |
|
| 340 |
+ Regex string |
|
| 334 | 341 |
|
| 335 |
-var ( |
|
| 336 |
- // AllowAll does not prevent any kinds of client version skew |
|
| 337 |
- AllowAll LegacyClientPolicy = "allow-all" |
|
| 338 |
- // DenyOldClients prevents older clients (but not newer ones) from issuing stomping requests |
|
| 339 |
- DenyOldClients LegacyClientPolicy = "deny-old-clients" |
|
| 340 |
- // DenySkewedClients prevents any non-matching client from issuing stomping requests |
|
| 341 |
- DenySkewedClients LegacyClientPolicy = "deny-skewed-clients" |
|
| 342 |
-) |
|
| 342 |
+ // HTTPVerbs specifies which HTTP verbs should be matched. An empty list means "match all verbs". |
|
| 343 |
+ HTTPVerbs []string |
|
| 344 |
+} |
|
| 345 |
+ |
|
| 346 |
+// UserAgentDenyRule adds a rejection message that can be used to help a user figure out how to get an approved client |
|
| 347 |
+type UserAgentDenyRule struct {
|
|
| 348 |
+ UserAgentMatchRule |
|
| 349 |
+ |
|
| 350 |
+ // RejectionMessage is the message shown when rejecting a client. If it is not a set, the default message is used. |
|
| 351 |
+ RejectionMessage string |
|
| 352 |
+} |
|
| 343 | 353 |
|
| 344 | 354 |
// MasterNetworkConfig to be passed to the compiled in network plugin |
| 345 | 355 |
type MasterNetworkConfig struct {
|
| ... | ... |
@@ -65,14 +65,6 @@ func addDefaultingFuncs(scheme *runtime.Scheme) {
|
| 65 | 65 |
obj.PodEvictionTimeout = "5m" |
| 66 | 66 |
} |
| 67 | 67 |
}, |
| 68 |
- func(obj *LegacyClientPolicyConfig) {
|
|
| 69 |
- if len(obj.LegacyClientPolicy) == 0 {
|
|
| 70 |
- obj.LegacyClientPolicy = AllowAll |
|
| 71 |
- } |
|
| 72 |
- if obj.LegacyClientPolicy != AllowAll && len(obj.RestrictedHTTPVerbs) == 0 {
|
|
| 73 |
- obj.RestrictedHTTPVerbs = []string{"PUT", "POST"}
|
|
| 74 |
- } |
|
| 75 |
- }, |
|
| 76 | 68 |
func(obj *NodeConfig) {
|
| 77 | 69 |
// Defaults/migrations for NetworkConfig |
| 78 | 70 |
if len(obj.NetworkConfig.NetworkPluginName) == 0 {
|
| ... | ... |
@@ -362,16 +362,6 @@ func (LDAPSyncConfig) SwaggerDoc() map[string]string {
|
| 362 | 362 |
return map_LDAPSyncConfig |
| 363 | 363 |
} |
| 364 | 364 |
|
| 365 |
-var map_LegacyClientPolicyConfig = map[string]string{
|
|
| 366 |
- "": "LegacyClientPolicyConfig holds configuration options for preventing *opt-in* clients using some HTTP verbs when talking to the API", |
|
| 367 |
- "legacyClientPolicy": "LegacyClientPolicy controls how API calls from *voluntarily* identifying clients will be handled. THIS DOES NOT DEFEND AGAINST MALICIOUS CLIENTS! The default is AllowAll", |
|
| 368 |
- "restrictedHTTPVerbs": "RestrictedHTTPVerbs specifies which HTTP verbs are restricted. By default this is PUT and POST", |
|
| 369 |
-} |
|
| 370 |
- |
|
| 371 |
-func (LegacyClientPolicyConfig) SwaggerDoc() map[string]string {
|
|
| 372 |
- return map_LegacyClientPolicyConfig |
|
| 373 |
-} |
|
| 374 |
- |
|
| 375 | 365 |
var map_MasterClients = map[string]string{
|
| 376 | 366 |
"": "MasterClients holds references to `.kubeconfig` files that qualify master clients for OpenShift and Kubernetes", |
| 377 | 367 |
"openshiftLoopbackKubeConfig": "OpenShiftLoopbackKubeConfig is a .kubeconfig filename for system components to loopback to this master", |
| ... | ... |
@@ -565,7 +555,7 @@ var map_PolicyConfig = map[string]string{
|
| 565 | 565 |
"bootstrapPolicyFile": "BootstrapPolicyFile points to a template that contains roles and rolebindings that will be created if no policy object exists in the master namespace", |
| 566 | 566 |
"openshiftSharedResourcesNamespace": "OpenShiftSharedResourcesNamespace is the namespace where shared OpenShift resources live (like shared templates)", |
| 567 | 567 |
"openshiftInfrastructureNamespace": "OpenShiftInfrastructureNamespace is the namespace where OpenShift infrastructure resources live (like controller service accounts)", |
| 568 |
- "legacyClientPolicyConfig": "LegacyClientPolicyConfig controls how API calls from *voluntarily* identifying clients will be handled. THIS DOES NOT DEFEND AGAINST MALICIOUS CLIENTS!", |
|
| 568 |
+ "userAgentMatchingConfig": "UserAgentMatchingConfig controls how API calls from *voluntarily* identifying clients will be handled. THIS DOES NOT DEFEND AGAINST MALICIOUS CLIENTS!", |
|
| 569 | 569 |
} |
| 570 | 570 |
|
| 571 | 571 |
func (PolicyConfig) SwaggerDoc() map[string]string {
|
| ... | ... |
@@ -730,3 +720,33 @@ var map_TokenConfig = map[string]string{
|
| 730 | 730 |
func (TokenConfig) SwaggerDoc() map[string]string {
|
| 731 | 731 |
return map_TokenConfig |
| 732 | 732 |
} |
| 733 |
+ |
|
| 734 |
+var map_UserAgentDenyRule = map[string]string{
|
|
| 735 |
+ "": "UserAgentDenyRule adds a rejection message that can be used to help a user figure out how to get an approved client", |
|
| 736 |
+ "rejectionMessage": "RejectionMessage is the message shown when rejecting a client. If it is not a set, the default message is used.", |
|
| 737 |
+} |
|
| 738 |
+ |
|
| 739 |
+func (UserAgentDenyRule) SwaggerDoc() map[string]string {
|
|
| 740 |
+ return map_UserAgentDenyRule |
|
| 741 |
+} |
|
| 742 |
+ |
|
| 743 |
+var map_UserAgentMatchRule = map[string]string{
|
|
| 744 |
+ "": "UserAgentMatchRule describes how to match a given request based on User-Agent and HTTPVerb", |
|
| 745 |
+ "regex": "UserAgentRegex is a regex that is checked against the User-Agent. Known variants of oc clients 1. oc accessing kube resources: oc/v1.2.0 (linux/amd64) kubernetes/bc4550d 2. oc accessing openshift resources: oc/v1.1.3 (linux/amd64) openshift/b348c2f 3. openshift kubectl accessing kube resources: openshift/v1.2.0 (linux/amd64) kubernetes/bc4550d 4. openshit kubectl accessing openshift resources: openshift/v1.1.3 (linux/amd64) openshift/b348c2f 5. oadm accessing kube resources: oadm/v1.2.0 (linux/amd64) kubernetes/bc4550d 6. oadm accessing openshift resources: oadm/v1.1.3 (linux/amd64) openshift/b348c2f 7. openshift cli accessing kube resources: openshift/v1.2.0 (linux/amd64) kubernetes/bc4550d 8. openshift cli accessing openshift resources: openshift/v1.1.3 (linux/amd64) openshift/b348c2f", |
|
| 746 |
+ "httpVerbs": "HTTPVerbs specifies which HTTP verbs should be matched. An empty list means \"match all verbs\".", |
|
| 747 |
+} |
|
| 748 |
+ |
|
| 749 |
+func (UserAgentMatchRule) SwaggerDoc() map[string]string {
|
|
| 750 |
+ return map_UserAgentMatchRule |
|
| 751 |
+} |
|
| 752 |
+ |
|
| 753 |
+var map_UserAgentMatchingConfig = map[string]string{
|
|
| 754 |
+ "": "UserAgentMatchingConfig controls how API calls from *voluntarily* identifying clients will be handled. THIS DOES NOT DEFEND AGAINST MALICIOUS CLIENTS!", |
|
| 755 |
+ "requiredClients": "If this list is non-empty, then a User-Agent must match one of the UserAgentRegexes to be allowed", |
|
| 756 |
+ "deniedClients": "If this list is non-empty, then a User-Agent must not match any of the UserAgentRegexes", |
|
| 757 |
+ "defaultRejectionMessage": "DefaultRejectionMessage is the message shown when rejecting a client. If it is not a set, a generic message is given.", |
|
| 758 |
+} |
|
| 759 |
+ |
|
| 760 |
+func (UserAgentMatchingConfig) SwaggerDoc() map[string]string {
|
|
| 761 |
+ return map_UserAgentMatchingConfig |
|
| 762 |
+} |
| ... | ... |
@@ -270,29 +270,47 @@ type PolicyConfig struct {
|
| 270 | 270 |
// OpenShiftInfrastructureNamespace is the namespace where OpenShift infrastructure resources live (like controller service accounts) |
| 271 | 271 |
OpenShiftInfrastructureNamespace string `json:"openshiftInfrastructureNamespace"` |
| 272 | 272 |
|
| 273 |
- // LegacyClientPolicyConfig controls how API calls from *voluntarily* identifying clients will be handled. THIS DOES NOT DEFEND AGAINST MALICIOUS CLIENTS! |
|
| 274 |
- LegacyClientPolicyConfig LegacyClientPolicyConfig `json:"legacyClientPolicyConfig"` |
|
| 273 |
+ // UserAgentMatchingConfig controls how API calls from *voluntarily* identifying clients will be handled. THIS DOES NOT DEFEND AGAINST MALICIOUS CLIENTS! |
|
| 274 |
+ UserAgentMatchingConfig UserAgentMatchingConfig `json:"userAgentMatchingConfig"` |
|
| 275 | 275 |
} |
| 276 | 276 |
|
| 277 |
-// LegacyClientPolicyConfig holds configuration options for preventing *opt-in* clients using some HTTP verbs when talking to the API |
|
| 278 |
-type LegacyClientPolicyConfig struct {
|
|
| 279 |
- // LegacyClientPolicy controls how API calls from *voluntarily* identifying clients will be handled. THIS DOES NOT DEFEND AGAINST MALICIOUS CLIENTS! |
|
| 280 |
- // The default is AllowAll |
|
| 281 |
- LegacyClientPolicy LegacyClientPolicy `json:"legacyClientPolicy"` |
|
| 282 |
- // RestrictedHTTPVerbs specifies which HTTP verbs are restricted. By default this is PUT and POST |
|
| 283 |
- RestrictedHTTPVerbs []string `json:"restrictedHTTPVerbs"` |
|
| 277 |
+// UserAgentMatchingConfig controls how API calls from *voluntarily* identifying clients will be handled. THIS DOES NOT DEFEND AGAINST MALICIOUS CLIENTS! |
|
| 278 |
+type UserAgentMatchingConfig struct {
|
|
| 279 |
+ // If this list is non-empty, then a User-Agent must match one of the UserAgentRegexes to be allowed |
|
| 280 |
+ RequiredClients []UserAgentMatchRule `json:"requiredClients"` |
|
| 281 |
+ |
|
| 282 |
+ // If this list is non-empty, then a User-Agent must not match any of the UserAgentRegexes |
|
| 283 |
+ DeniedClients []UserAgentDenyRule `json:"deniedClients"` |
|
| 284 |
+ |
|
| 285 |
+ // DefaultRejectionMessage is the message shown when rejecting a client. If it is not a set, a generic message is given. |
|
| 286 |
+ DefaultRejectionMessage string `json:"defaultRejectionMessage"` |
|
| 287 |
+} |
|
| 288 |
+ |
|
| 289 |
+// UserAgentMatchRule describes how to match a given request based on User-Agent and HTTPVerb |
|
| 290 |
+type UserAgentMatchRule struct {
|
|
| 291 |
+ // UserAgentRegex is a regex that is checked against the User-Agent. |
|
| 292 |
+ // Known variants of oc clients |
|
| 293 |
+ // 1. oc accessing kube resources: oc/v1.2.0 (linux/amd64) kubernetes/bc4550d |
|
| 294 |
+ // 2. oc accessing openshift resources: oc/v1.1.3 (linux/amd64) openshift/b348c2f |
|
| 295 |
+ // 3. openshift kubectl accessing kube resources: openshift/v1.2.0 (linux/amd64) kubernetes/bc4550d |
|
| 296 |
+ // 4. openshit kubectl accessing openshift resources: openshift/v1.1.3 (linux/amd64) openshift/b348c2f |
|
| 297 |
+ // 5. oadm accessing kube resources: oadm/v1.2.0 (linux/amd64) kubernetes/bc4550d |
|
| 298 |
+ // 6. oadm accessing openshift resources: oadm/v1.1.3 (linux/amd64) openshift/b348c2f |
|
| 299 |
+ // 7. openshift cli accessing kube resources: openshift/v1.2.0 (linux/amd64) kubernetes/bc4550d |
|
| 300 |
+ // 8. openshift cli accessing openshift resources: openshift/v1.1.3 (linux/amd64) openshift/b348c2f |
|
| 301 |
+ Regex string `json:"regex"` |
|
| 302 |
+ |
|
| 303 |
+ // HTTPVerbs specifies which HTTP verbs should be matched. An empty list means "match all verbs". |
|
| 304 |
+ HTTPVerbs []string `json:"httpVerbs"` |
|
| 284 | 305 |
} |
| 285 | 306 |
|
| 286 |
-type LegacyClientPolicy string |
|
| 307 |
+// UserAgentDenyRule adds a rejection message that can be used to help a user figure out how to get an approved client |
|
| 308 |
+type UserAgentDenyRule struct {
|
|
| 309 |
+ UserAgentMatchRule `json:", inline"` |
|
| 287 | 310 |
|
| 288 |
-var ( |
|
| 289 |
- // AllowAll does not prevent any kinds of client version skew |
|
| 290 |
- AllowAll LegacyClientPolicy = "allow-all" |
|
| 291 |
- // DenyOldClients prevents older clients (but not newer ones) from issuing stomping requests |
|
| 292 |
- DenyOldClients LegacyClientPolicy = "deny-old-clients" |
|
| 293 |
- // DenySkewedClients prevents any non-matching client from issuing stomping requests |
|
| 294 |
- DenySkewedClients LegacyClientPolicy = "deny-skewed-clients" |
|
| 295 |
-) |
|
| 311 |
+ // RejectionMessage is the message shown when rejecting a client. If it is not a set, the default message is used. |
|
| 312 |
+ RejectionMessage string `json:"rejectionMessage"` |
|
| 313 |
+} |
|
| 296 | 314 |
|
| 297 | 315 |
// RoutingConfig holds the necessary configuration options for routing to subdomains |
| 298 | 316 |
type RoutingConfig struct {
|
| ... | ... |
@@ -421,11 +421,12 @@ oauthConfig: |
| 421 | 421 |
pauseControllers: false |
| 422 | 422 |
policyConfig: |
| 423 | 423 |
bootstrapPolicyFile: "" |
| 424 |
- legacyClientPolicyConfig: |
|
| 425 |
- legacyClientPolicy: "" |
|
| 426 |
- restrictedHTTPVerbs: null |
|
| 427 | 424 |
openshiftInfrastructureNamespace: "" |
| 428 | 425 |
openshiftSharedResourcesNamespace: "" |
| 426 |
+ userAgentMatchingConfig: |
|
| 427 |
+ defaultRejectionMessage: "" |
|
| 428 |
+ deniedClients: null |
|
| 429 |
+ requiredClients: null |
|
| 429 | 430 |
projectConfig: |
| 430 | 431 |
defaultNodeSelector: "" |
| 431 | 432 |
projectRequestMessage: "" |
| ... | ... |
@@ -497,6 +497,19 @@ func ValidatePolicyConfig(config api.PolicyConfig, fldPath *field.Path) field.Er |
| 497 | 497 |
allErrs = append(allErrs, ValidateNamespace(config.OpenShiftSharedResourcesNamespace, fldPath.Child("openShiftSharedResourcesNamespace"))...)
|
| 498 | 498 |
allErrs = append(allErrs, ValidateNamespace(config.OpenShiftInfrastructureNamespace, fldPath.Child("openShiftInfrastructureNamespace"))...)
|
| 499 | 499 |
|
| 500 |
+ for i, matchingRule := range config.UserAgentMatchingConfig.DeniedClients {
|
|
| 501 |
+ _, err := regexp.Compile(matchingRule.Regex) |
|
| 502 |
+ if err != nil {
|
|
| 503 |
+ allErrs = append(allErrs, field.Invalid(fldPath.Child("userAgentMatchingConfig", "deniedClients").Index(i), matchingRule.Regex, err.Error()))
|
|
| 504 |
+ } |
|
| 505 |
+ } |
|
| 506 |
+ for i, matchingRule := range config.UserAgentMatchingConfig.RequiredClients {
|
|
| 507 |
+ _, err := regexp.Compile(matchingRule.Regex) |
|
| 508 |
+ if err != nil {
|
|
| 509 |
+ allErrs = append(allErrs, field.Invalid(fldPath.Child("userAgentMatchingConfig", "requiredClients").Index(i), matchingRule.Regex, err.Error()))
|
|
| 510 |
+ } |
|
| 511 |
+ } |
|
| 512 |
+ |
|
| 500 | 513 |
return allErrs |
| 501 | 514 |
} |
| 502 | 515 |
|
| ... | ... |
@@ -8,10 +8,9 @@ import ( |
| 8 | 8 |
"net/http" |
| 9 | 9 |
"regexp" |
| 10 | 10 |
"sort" |
| 11 |
- "strings" |
|
| 12 | 11 |
|
| 13 |
- "github.com/coreos/go-semver/semver" |
|
| 14 | 12 |
restful "github.com/emicklei/go-restful" |
| 13 |
+ "github.com/golang/glog" |
|
| 15 | 14 |
|
| 16 | 15 |
kapi "k8s.io/kubernetes/pkg/api" |
| 17 | 16 |
kapierrors "k8s.io/kubernetes/pkg/api/errors" |
| ... | ... |
@@ -19,12 +18,10 @@ import ( |
| 19 | 19 |
"k8s.io/kubernetes/pkg/apiserver" |
| 20 | 20 |
"k8s.io/kubernetes/pkg/runtime" |
| 21 | 21 |
"k8s.io/kubernetes/pkg/util/sets" |
| 22 |
- kversion "k8s.io/kubernetes/pkg/version" |
|
| 23 | 22 |
|
| 24 | 23 |
"github.com/openshift/origin/pkg/authorization/authorizer" |
| 25 | 24 |
configapi "github.com/openshift/origin/pkg/cmd/server/api" |
| 26 | 25 |
"github.com/openshift/origin/pkg/util/httprequest" |
| 27 |
- "github.com/openshift/origin/pkg/version" |
|
| 28 | 26 |
) |
| 29 | 27 |
|
| 30 | 28 |
// TODO We would like to use the IndexHandler from k8s but we do not yet have a |
| ... | ... |
@@ -178,85 +175,100 @@ func namespacingFilter(handler http.Handler, contextMapper kapi.RequestContextMa |
| 178 | 178 |
}) |
| 179 | 179 |
} |
| 180 | 180 |
|
| 181 |
-// variants I know I have to worry about |
|
| 182 |
-// 1. oc kube resources: oc/v1.2.0 (linux/amd64) kubernetes/bc4550d |
|
| 183 |
-// 2. oc openshift resources: oc/v1.1.3 (linux/amd64) openshift/b348c2f |
|
| 184 |
-// 3. openshift kubectl kube resources: openshift/v1.2.0 (linux/amd64) kubernetes/bc4550d |
|
| 185 |
-// 4. openshit kubectl openshift resources: openshift/v1.1.3 (linux/amd64) openshift/b348c2f |
|
| 186 |
-// 5. oadm kube resources: oadm/v1.2.0 (linux/amd64) kubernetes/bc4550d |
|
| 187 |
-// 6. oadm openshift resources: oadm/v1.1.3 (linux/amd64) openshift/b348c2f |
|
| 188 |
-// 7. openshift cli kube resources: openshift/v1.2.0 (linux/amd64) kubernetes/bc4550d |
|
| 189 |
-// 8. openshift cli openshift resources: openshift/v1.1.3 (linux/amd64) openshift/b348c2f |
|
| 190 |
-var ( |
|
| 191 |
- kubeStyleUserAgent = regexp.MustCompile(`\w+/v([\w\.]+) \(.+/.+\) kubernetes/\w{7}`)
|
|
| 192 |
- openshiftStyleUserAgent = regexp.MustCompile(`\w+/v([\w\.]+) \(.+/.+\) openshift/\w{7}`)
|
|
| 193 |
-) |
|
| 181 |
+type userAgentFilter struct {
|
|
| 182 |
+ regex *regexp.Regexp |
|
| 183 |
+ message string |
|
| 184 |
+ verbs sets.String |
|
| 185 |
+} |
|
| 186 |
+ |
|
| 187 |
+func newUserAgentFilter(config configapi.UserAgentMatchRule) (userAgentFilter, error) {
|
|
| 188 |
+ regex, err := regexp.Compile(config.Regex) |
|
| 189 |
+ if err != nil {
|
|
| 190 |
+ return userAgentFilter{}, err
|
|
| 191 |
+ } |
|
| 192 |
+ userAgentFilter := userAgentFilter{regex: regex, verbs: sets.NewString(config.HTTPVerbs...)}
|
|
| 193 |
+ |
|
| 194 |
+ return userAgentFilter, nil |
|
| 195 |
+} |
|
| 196 |
+ |
|
| 197 |
+func (f *userAgentFilter) matches(verb, userAgent string) bool {
|
|
| 198 |
+ if len(f.verbs) > 0 && !f.verbs.Has(verb) {
|
|
| 199 |
+ return false |
|
| 200 |
+ } |
|
| 201 |
+ |
|
| 202 |
+ return f.regex.MatchString(userAgent) |
|
| 203 |
+} |
|
| 194 | 204 |
|
| 195 | 205 |
// versionSkewFilter adds a filter that may deny requests from skewed |
| 196 | 206 |
// oc clients, since we know that those clients will strip unknown fields which can lead to unexpected outcomes |
| 197 |
-func (c *MasterConfig) versionSkewFilter(openshiftBinaryInfo version.Info, kubeBinaryInfo kversion.Info, handler http.Handler) http.Handler {
|
|
| 198 |
- skewedClientPolicy := c.Options.PolicyConfig.LegacyClientPolicyConfig.LegacyClientPolicy |
|
| 199 |
- if skewedClientPolicy == configapi.AllowAll {
|
|
| 207 |
+func (c *MasterConfig) versionSkewFilter(handler http.Handler) http.Handler {
|
|
| 208 |
+ infoResolver := &apiserver.RequestInfoResolver{APIPrefixes: sets.NewString("api", "osapi", "oapi", "apis"), GrouplessAPIPrefixes: sets.NewString("api", "osapi", "oapi")}
|
|
| 209 |
+ |
|
| 210 |
+ filterConfig := c.Options.PolicyConfig.UserAgentMatchingConfig |
|
| 211 |
+ if len(filterConfig.RequiredClients) == 0 && len(filterConfig.DeniedClients) == 0 {
|
|
| 200 | 212 |
return handler |
| 201 | 213 |
} |
| 202 |
- seg := strings.SplitN(openshiftBinaryInfo.GitVersion, "-", 2) |
|
| 203 |
- openshiftServerVersion := seg[0][1:] |
|
| 204 |
- seg = strings.SplitN(kubeBinaryInfo.GitVersion, "-", 2) |
|
| 205 |
- kubeServerVersion := seg[0][1:] |
|
| 206 | 214 |
|
| 207 |
- restrictedVerbs := sets.NewString(c.Options.PolicyConfig.LegacyClientPolicyConfig.RestrictedHTTPVerbs...) |
|
| 208 |
- |
|
| 209 |
- return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
| 210 |
- if !restrictedVerbs.Has(req.Method) {
|
|
| 211 |
- handler.ServeHTTP(w, req) |
|
| 212 |
- return |
|
| 213 |
- } |
|
| 215 |
+ defaultMessage := filterConfig.DefaultRejectionMessage |
|
| 216 |
+ if len(defaultMessage) == 0 {
|
|
| 217 |
+ defaultMessage = "the cluster administrator has disabled access for this client, please upgrade or consult your administrator" |
|
| 218 |
+ } |
|
| 214 | 219 |
|
| 215 |
- userAgent := req.Header.Get("User-Agent")
|
|
| 216 |
- if len(userAgent) == 0 {
|
|
| 217 |
- handler.ServeHTTP(w, req) |
|
| 218 |
- return |
|
| 220 |
+ // the structure of the legacyClientPolicyConfig is pretty easy to write, but its inefficient to use at runtime |
|
| 221 |
+ // pre-process the config elements to make a more efficicent structure. |
|
| 222 |
+ allowedFilters := []userAgentFilter{}
|
|
| 223 |
+ deniedFilters := []userAgentFilter{}
|
|
| 224 |
+ for _, config := range filterConfig.RequiredClients {
|
|
| 225 |
+ userAgentFilter, err := newUserAgentFilter(config) |
|
| 226 |
+ if err != nil {
|
|
| 227 |
+ glog.Errorf("Failure to compile User-Agent regex %v: %v", config.Regex, err)
|
|
| 228 |
+ continue |
|
| 219 | 229 |
} |
| 220 | 230 |
|
| 221 |
- clientVersion := "" |
|
| 222 |
- serverVersion := "" |
|
| 223 |
- if submatches := kubeStyleUserAgent.FindStringSubmatch(userAgent); len(submatches) == 2 {
|
|
| 224 |
- clientVersion = submatches[1] |
|
| 225 |
- serverVersion = kubeServerVersion |
|
| 231 |
+ allowedFilters = append(allowedFilters, userAgentFilter) |
|
| 232 |
+ } |
|
| 233 |
+ for _, config := range filterConfig.DeniedClients {
|
|
| 234 |
+ userAgentFilter, err := newUserAgentFilter(config.UserAgentMatchRule) |
|
| 235 |
+ if err != nil {
|
|
| 236 |
+ glog.Errorf("Failure to compile User-Agent regex %v: %v", config.Regex, err)
|
|
| 237 |
+ continue |
|
| 226 | 238 |
} |
| 227 |
- if submatches := openshiftStyleUserAgent.FindStringSubmatch(userAgent); len(submatches) == 2 {
|
|
| 228 |
- clientVersion = submatches[1] |
|
| 229 |
- serverVersion = openshiftServerVersion |
|
| 239 |
+ userAgentFilter.message = config.RejectionMessage |
|
| 240 |
+ if len(userAgentFilter.message) == 0 {
|
|
| 241 |
+ userAgentFilter.message = defaultMessage |
|
| 230 | 242 |
} |
| 231 |
- if len(clientVersion) == 0 {
|
|
| 243 |
+ |
|
| 244 |
+ deniedFilters = append(deniedFilters, userAgentFilter) |
|
| 245 |
+ } |
|
| 246 |
+ |
|
| 247 |
+ return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
| 248 |
+ if requestInfo, err := infoResolver.GetRequestInfo(req); err == nil && !requestInfo.IsResourceRequest {
|
|
| 232 | 249 |
handler.ServeHTTP(w, req) |
| 233 | 250 |
return |
| 234 | 251 |
} |
| 235 | 252 |
|
| 236 |
- switch skewedClientPolicy {
|
|
| 237 |
- case configapi.DenyOldClients: |
|
| 238 |
- serverSemVer, err := semver.NewVersion(serverVersion) |
|
| 239 |
- if err != nil {
|
|
| 240 |
- handler.ServeHTTP(w, req) |
|
| 241 |
- return |
|
| 242 |
- } |
|
| 243 |
- clientSemVer, err := semver.NewVersion(clientVersion) |
|
| 244 |
- if err != nil {
|
|
| 245 |
- handler.ServeHTTP(w, req) |
|
| 246 |
- return |
|
| 253 |
+ userAgent := req.Header.Get("User-Agent")
|
|
| 254 |
+ |
|
| 255 |
+ if len(allowedFilters) > 0 {
|
|
| 256 |
+ foundMatch := false |
|
| 257 |
+ for _, filter := range allowedFilters {
|
|
| 258 |
+ if filter.matches(req.Method, userAgent) {
|
|
| 259 |
+ foundMatch = true |
|
| 260 |
+ break |
|
| 261 |
+ } |
|
| 247 | 262 |
} |
| 248 | 263 |
|
| 249 |
- if clientSemVer.LessThan(*serverSemVer) {
|
|
| 250 |
- forbidden(fmt.Sprintf("userVersion %v is older than the server version %v; mutation is denied", clientVersion, serverVersion), nil, w, req)
|
|
| 264 |
+ if !foundMatch {
|
|
| 265 |
+ forbidden(defaultMessage, nil, w, req) |
|
| 251 | 266 |
return |
| 252 | 267 |
} |
| 268 |
+ } |
|
| 253 | 269 |
|
| 254 |
- case configapi.DenySkewedClients: |
|
| 255 |
- if clientVersion != serverVersion {
|
|
| 256 |
- forbidden(fmt.Sprintf("userVersion %v is different than the server version %v; mutation is denied", clientVersion, serverVersion), nil, w, req)
|
|
| 270 |
+ for _, filter := range deniedFilters {
|
|
| 271 |
+ if filter.matches(req.Method, userAgent) {
|
|
| 272 |
+ forbidden(filter.message, nil, w, req) |
|
| 257 | 273 |
return |
| 258 | 274 |
} |
| 259 |
- |
|
| 260 | 275 |
} |
| 261 | 276 |
|
| 262 | 277 |
handler.ServeHTTP(w, req) |
| ... | ... |
@@ -7,10 +7,7 @@ import ( |
| 7 | 7 |
"strings" |
| 8 | 8 |
"testing" |
| 9 | 9 |
|
| 10 |
- kversion "k8s.io/kubernetes/pkg/version" |
|
| 11 |
- |
|
| 12 | 10 |
configapi "github.com/openshift/origin/pkg/cmd/server/api" |
| 13 |
- "github.com/openshift/origin/pkg/version" |
|
| 14 | 11 |
) |
| 15 | 12 |
|
| 16 | 13 |
var ( |
| ... | ... |
@@ -25,12 +22,13 @@ var ( |
| 25 | 25 |
|
| 26 | 26 |
olderOCKubeResources = "oc/v1.1.10 (linux/amd64) kubernetes/bc4550d" |
| 27 | 27 |
olderOCOriginResources = "oc/v1.1.1 (linux/amd64) openshift/b348c2f" |
| 28 |
+ oldestOCOriginResources = "oc/v1.0.1 (linux/amd64) openshift/b348c2f" |
|
| 28 | 29 |
olderOpenshiftKubectlKubeResources = "openshift/v1.1.10 (linux/amd64) kubernetes/bc4550d" |
| 29 | 30 |
olderOpenshiftKubectlOriginResources = "openshift/v1.1.1 (linux/amd64) openshift/b348c2f" |
| 30 | 31 |
olderOADMKubeResources = "oadm/v1.1.10 (linux/amd64) kubernetes/bc4550d" |
| 31 | 32 |
olderOADMOriginResources = "oadm/v1.1.1 (linux/amd64) openshift/b348c2f" |
| 32 | 33 |
olderVersionUserAgents = []string{
|
| 33 |
- olderOCKubeResources, olderOCOriginResources, olderOpenshiftKubectlKubeResources, olderOpenshiftKubectlOriginResources, olderOADMKubeResources, olderOADMOriginResources} |
|
| 34 |
+ olderOCKubeResources, olderOCOriginResources, oldestOCOriginResources, olderOpenshiftKubectlKubeResources, olderOpenshiftKubectlOriginResources, olderOADMKubeResources, olderOADMOriginResources} |
|
| 34 | 35 |
|
| 35 | 36 |
newerOCKubeResources = "oc/v1.2.1 (linux/amd64) kubernetes/bc4550d" |
| 36 | 37 |
newerOCOriginResources = "oc/v1.1.4 (linux/amd64) openshift/b348c2f" |
| ... | ... |
@@ -43,10 +41,24 @@ var ( |
| 43 | 43 |
|
| 44 | 44 |
notOCVersion = "something else" |
| 45 | 45 |
|
| 46 |
- openshiftServerVersion = version.Info{GitVersion: "v1.1.3"}
|
|
| 47 |
- kubeServerVersion = kversion.Info{GitVersion: "v1.2.0"}
|
|
| 46 |
+ openshiftServerVersion = `v1\.1\.3` |
|
| 47 |
+ kubeServerVersion = `v1\.2\.0` |
|
| 48 | 48 |
) |
| 49 | 49 |
|
| 50 |
+// variants I know I have to worry about |
|
| 51 |
+// 1. oc kube resources: oc/v1.2.0 (linux/amd64) kubernetes/bc4550d |
|
| 52 |
+// 2. oc openshift resources: oc/v1.1.3 (linux/amd64) openshift/b348c2f |
|
| 53 |
+// 3. openshift kubectl kube resources: openshift/v1.2.0 (linux/amd64) kubernetes/bc4550d |
|
| 54 |
+// 4. openshit kubectl openshift resources: openshift/v1.1.3 (linux/amd64) openshift/b348c2f |
|
| 55 |
+// 5. oadm kube resources: oadm/v1.2.0 (linux/amd64) kubernetes/bc4550d |
|
| 56 |
+// 6. oadm openshift resources: oadm/v1.1.3 (linux/amd64) openshift/b348c2f |
|
| 57 |
+// 7. openshift cli kube resources: openshift/v1.2.0 (linux/amd64) kubernetes/bc4550d |
|
| 58 |
+// 8. openshift cli openshift resources: openshift/v1.1.3 (linux/amd64) openshift/b348c2f |
|
| 59 |
+// var ( |
|
| 60 |
+// kubeStyleUserAgent = regexp.MustCompile(`\w+/v([\w\.]+) \(.+/.+\) kubernetes/\w{7}`)
|
|
| 61 |
+// openshiftStyleUserAgent = regexp.MustCompile(`\w+/v([\w\.]+) \(.+/.+\) openshift/\w{7}`)
|
|
| 62 |
+// ) |
|
| 63 |
+ |
|
| 50 | 64 |
type versionSkewTestCase struct {
|
| 51 | 65 |
name string |
| 52 | 66 |
userAgents []string |
| ... | ... |
@@ -55,25 +67,6 @@ type versionSkewTestCase struct {
|
| 55 | 55 |
} |
| 56 | 56 |
|
| 57 | 57 |
func (tc versionSkewTestCase) Run(url string, t *testing.T) {
|
| 58 |
- // gets always succeed |
|
| 59 |
- for _, userAgent := range tc.userAgents {
|
|
| 60 |
- req, err := http.NewRequest("GET", url, nil)
|
|
| 61 |
- if err != nil {
|
|
| 62 |
- t.Errorf("%s: unexpected error: %v", tc.name, err)
|
|
| 63 |
- return |
|
| 64 |
- } |
|
| 65 |
- req.Header.Add("User-Agent", userAgent)
|
|
| 66 |
- resp, err := http.DefaultClient.Do(req) |
|
| 67 |
- if err != nil {
|
|
| 68 |
- t.Errorf("%s: unexpected error: %v", tc.name, err)
|
|
| 69 |
- return |
|
| 70 |
- } |
|
| 71 |
- if resp.StatusCode != http.StatusOK {
|
|
| 72 |
- t.Errorf("%s: unexpected status: %v", tc.name, resp.StatusCode)
|
|
| 73 |
- return |
|
| 74 |
- } |
|
| 75 |
- } |
|
| 76 |
- |
|
| 77 | 58 |
for _, method := range tc.methods {
|
| 78 | 59 |
for _, userAgent := range tc.userAgents {
|
| 79 | 60 |
req, err := http.NewRequest(method, url, nil) |
| ... | ... |
@@ -89,13 +82,13 @@ func (tc versionSkewTestCase) Run(url string, t *testing.T) {
|
| 89 | 89 |
} |
| 90 | 90 |
if len(tc.failureMessage) == 0 {
|
| 91 | 91 |
if resp.StatusCode != http.StatusOK {
|
| 92 |
- t.Errorf("%s: unexpected status: %v", tc.name, resp.StatusCode)
|
|
| 92 |
+ t.Errorf("%s: %s: unexpected status: %v", tc.name, userAgent, resp.StatusCode)
|
|
| 93 | 93 |
return |
| 94 | 94 |
} |
| 95 | 95 |
|
| 96 | 96 |
} else {
|
| 97 | 97 |
if resp.StatusCode != http.StatusForbidden {
|
| 98 |
- t.Errorf("%s: unexpected status: %v", tc.name, resp.StatusCode)
|
|
| 98 |
+ t.Errorf("%s: %s: unexpected status: %v", tc.name, userAgent, resp.StatusCode)
|
|
| 99 | 99 |
return |
| 100 | 100 |
} |
| 101 | 101 |
|
| ... | ... |
@@ -115,14 +108,16 @@ func (tc versionSkewTestCase) Run(url string, t *testing.T) {
|
| 115 | 115 |
|
| 116 | 116 |
} |
| 117 | 117 |
|
| 118 |
-func TestVersionSkewFilterAllowAll(t *testing.T) {
|
|
| 119 |
- verbs := []string{"PUT", "POST"}
|
|
| 118 |
+func TestVersionSkewFilterDenyOld(t *testing.T) {
|
|
| 119 |
+ verbs := []string{"PATCH", "POST"}
|
|
| 120 | 120 |
doNothingHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
| 121 | 121 |
}) |
| 122 | 122 |
config := MasterConfig{}
|
| 123 |
- config.Options.PolicyConfig.LegacyClientPolicyConfig.LegacyClientPolicy = configapi.AllowAll |
|
| 124 |
- config.Options.PolicyConfig.LegacyClientPolicyConfig.RestrictedHTTPVerbs = verbs |
|
| 125 |
- server := httptest.NewServer(config.versionSkewFilter(openshiftServerVersion, kubeServerVersion, doNothingHandler)) |
|
| 123 |
+ config.Options.PolicyConfig.UserAgentMatchingConfig.DeniedClients = []configapi.UserAgentDenyRule{
|
|
| 124 |
+ {UserAgentMatchRule: configapi.UserAgentMatchRule{Regex: `\w+/v1\.1\.10 \(.+/.+\) kubernetes/\w{7}`, HTTPVerbs: verbs}, RejectionMessage: "rejected for reasons!"},
|
|
| 125 |
+ {UserAgentMatchRule: configapi.UserAgentMatchRule{Regex: `\w+/v(?:(?:1\.1\.1)|(?:1\.0\.1)) \(.+/.+\) openshift/\w{7}`, HTTPVerbs: verbs}, RejectionMessage: "rejected for reasons!"},
|
|
| 126 |
+ } |
|
| 127 |
+ server := httptest.NewServer(config.versionSkewFilter(doNothingHandler)) |
|
| 126 | 128 |
defer server.Close() |
| 127 | 129 |
|
| 128 | 130 |
testCases := []versionSkewTestCase{
|
| ... | ... |
@@ -137,9 +132,10 @@ func TestVersionSkewFilterAllowAll(t *testing.T) {
|
| 137 | 137 |
methods: verbs, |
| 138 | 138 |
}, |
| 139 | 139 |
{
|
| 140 |
- name: "older", |
|
| 141 |
- userAgents: olderVersionUserAgents, |
|
| 142 |
- methods: verbs, |
|
| 140 |
+ name: "older", |
|
| 141 |
+ userAgents: olderVersionUserAgents, |
|
| 142 |
+ failureMessage: "rejected for reasons!", |
|
| 143 |
+ methods: verbs, |
|
| 143 | 144 |
}, |
| 144 | 145 |
{
|
| 145 | 146 |
name: "newer", |
| ... | ... |
@@ -154,62 +150,71 @@ func TestVersionSkewFilterAllowAll(t *testing.T) {
|
| 154 | 154 |
} |
| 155 | 155 |
|
| 156 | 156 |
for _, tc := range testCases {
|
| 157 |
- tc.Run(server.URL, t) |
|
| 157 |
+ tc.Run(server.URL+"/api/v1/namespaces", t) |
|
| 158 | 158 |
} |
| 159 | 159 |
} |
| 160 | 160 |
|
| 161 |
-func TestVersionSkewFilterDenyOld(t *testing.T) {
|
|
| 162 |
- verbs := []string{"PATCH", "POST"}
|
|
| 161 |
+func TestVersionSkewFilterDenySkewed(t *testing.T) {
|
|
| 162 |
+ verbs := []string{"PUT", "DELETE"}
|
|
| 163 | 163 |
doNothingHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
| 164 | 164 |
}) |
| 165 | 165 |
config := MasterConfig{}
|
| 166 |
- config.Options.PolicyConfig.LegacyClientPolicyConfig.LegacyClientPolicy = configapi.DenyOldClients |
|
| 167 |
- config.Options.PolicyConfig.LegacyClientPolicyConfig.RestrictedHTTPVerbs = verbs |
|
| 168 |
- server := httptest.NewServer(config.versionSkewFilter(openshiftServerVersion, kubeServerVersion, doNothingHandler)) |
|
| 166 |
+ config.Options.PolicyConfig.UserAgentMatchingConfig.RequiredClients = []configapi.UserAgentMatchRule{
|
|
| 167 |
+ {Regex: `\w+/` + kubeServerVersion + ` \(.+/.+\) kubernetes/\w{7}`, HTTPVerbs: verbs},
|
|
| 168 |
+ {Regex: `\w+/` + openshiftServerVersion + ` \(.+/.+\) openshift/\w{7}`, HTTPVerbs: verbs},
|
|
| 169 |
+ } |
|
| 170 |
+ config.Options.PolicyConfig.UserAgentMatchingConfig.DefaultRejectionMessage = "rejected for reasons!" |
|
| 171 |
+ server := httptest.NewServer(config.versionSkewFilter(doNothingHandler)) |
|
| 169 | 172 |
defer server.Close() |
| 170 | 173 |
|
| 171 | 174 |
testCases := []versionSkewTestCase{
|
| 172 | 175 |
{
|
| 173 |
- name: "missing", |
|
| 174 |
- userAgents: []string{""},
|
|
| 175 |
- methods: verbs, |
|
| 176 |
+ name: "missing", |
|
| 177 |
+ userAgents: []string{""},
|
|
| 178 |
+ failureMessage: "rejected for reasons!", |
|
| 179 |
+ methods: verbs, |
|
| 176 | 180 |
}, |
| 177 | 181 |
{
|
| 178 |
- name: "not oc", |
|
| 179 |
- userAgents: []string{notOCVersion},
|
|
| 180 |
- methods: verbs, |
|
| 182 |
+ name: "not oc", |
|
| 183 |
+ userAgents: []string{notOCVersion},
|
|
| 184 |
+ failureMessage: "rejected for reasons!", |
|
| 185 |
+ methods: verbs, |
|
| 181 | 186 |
}, |
| 182 | 187 |
{
|
| 183 | 188 |
name: "older", |
| 184 | 189 |
userAgents: olderVersionUserAgents, |
| 185 |
- failureMessage: " is older than the server version", |
|
| 190 |
+ failureMessage: "rejected for reasons!", |
|
| 186 | 191 |
methods: verbs, |
| 187 | 192 |
}, |
| 188 | 193 |
{
|
| 189 |
- name: "newer", |
|
| 190 |
- userAgents: newerVersionUserAgents, |
|
| 191 |
- methods: verbs, |
|
| 194 |
+ name: "newer", |
|
| 195 |
+ userAgents: newerVersionUserAgents, |
|
| 196 |
+ failureMessage: "rejected for reasons!", |
|
| 197 |
+ methods: verbs, |
|
| 192 | 198 |
}, |
| 193 | 199 |
{
|
| 194 |
- name: "exact", |
|
| 200 |
+ name: "current", |
|
| 195 | 201 |
userAgents: currentVersionUserAgents, |
| 196 | 202 |
methods: verbs, |
| 197 | 203 |
}, |
| 198 | 204 |
} |
| 199 | 205 |
|
| 200 | 206 |
for _, tc := range testCases {
|
| 201 |
- tc.Run(server.URL, t) |
|
| 207 |
+ tc.Run(server.URL+"/api/v1/namespaces", t) |
|
| 202 | 208 |
} |
| 203 | 209 |
} |
| 204 | 210 |
|
| 205 |
-func TestVersionSkewFilterDenySkewed(t *testing.T) {
|
|
| 211 |
+func TestVersionSkewFilterSkippedOnNonAPIRequest(t *testing.T) {
|
|
| 206 | 212 |
verbs := []string{"PUT", "DELETE"}
|
| 207 | 213 |
doNothingHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
| 208 | 214 |
}) |
| 209 | 215 |
config := MasterConfig{}
|
| 210 |
- config.Options.PolicyConfig.LegacyClientPolicyConfig.LegacyClientPolicy = configapi.DenySkewedClients |
|
| 211 |
- config.Options.PolicyConfig.LegacyClientPolicyConfig.RestrictedHTTPVerbs = verbs |
|
| 212 |
- server := httptest.NewServer(config.versionSkewFilter(openshiftServerVersion, kubeServerVersion, doNothingHandler)) |
|
| 216 |
+ config.Options.PolicyConfig.UserAgentMatchingConfig.RequiredClients = []configapi.UserAgentMatchRule{
|
|
| 217 |
+ {Regex: `\w+/` + kubeServerVersion + ` \(.+/.+\) kubernetes/\w{7}`, HTTPVerbs: verbs},
|
|
| 218 |
+ {Regex: `\w+/` + openshiftServerVersion + ` \(.+/.+\) openshift/\w{7}`, HTTPVerbs: verbs},
|
|
| 219 |
+ } |
|
| 220 |
+ config.Options.PolicyConfig.UserAgentMatchingConfig.DefaultRejectionMessage = "rejected for reasons!" |
|
| 221 |
+ server := httptest.NewServer(config.versionSkewFilter(doNothingHandler)) |
|
| 213 | 222 |
defer server.Close() |
| 214 | 223 |
|
| 215 | 224 |
testCases := []versionSkewTestCase{
|
| ... | ... |
@@ -224,16 +229,14 @@ func TestVersionSkewFilterDenySkewed(t *testing.T) {
|
| 224 | 224 |
methods: verbs, |
| 225 | 225 |
}, |
| 226 | 226 |
{
|
| 227 |
- name: "older", |
|
| 228 |
- userAgents: olderVersionUserAgents, |
|
| 229 |
- failureMessage: "is different than the server version", |
|
| 230 |
- methods: verbs, |
|
| 227 |
+ name: "older", |
|
| 228 |
+ userAgents: olderVersionUserAgents, |
|
| 229 |
+ methods: verbs, |
|
| 231 | 230 |
}, |
| 232 | 231 |
{
|
| 233 |
- name: "newer", |
|
| 234 |
- userAgents: newerVersionUserAgents, |
|
| 235 |
- failureMessage: "is different than the server version", |
|
| 236 |
- methods: verbs, |
|
| 232 |
+ name: "newer", |
|
| 233 |
+ userAgents: newerVersionUserAgents, |
|
| 234 |
+ methods: verbs, |
|
| 237 | 235 |
}, |
| 238 | 236 |
{
|
| 239 | 237 |
name: "current", |
| ... | ... |
@@ -243,6 +246,6 @@ func TestVersionSkewFilterDenySkewed(t *testing.T) {
|
| 243 | 243 |
} |
| 244 | 244 |
|
| 245 | 245 |
for _, tc := range testCases {
|
| 246 |
- tc.Run(server.URL, t) |
|
| 246 |
+ tc.Run(server.URL+"/api/v1", t) |
|
| 247 | 247 |
} |
| 248 | 248 |
} |
| ... | ... |
@@ -29,7 +29,6 @@ import ( |
| 29 | 29 |
"k8s.io/kubernetes/pkg/util" |
| 30 | 30 |
"k8s.io/kubernetes/pkg/util/sets" |
| 31 | 31 |
utilwait "k8s.io/kubernetes/pkg/util/wait" |
| 32 |
- kversion "k8s.io/kubernetes/pkg/version" |
|
| 33 | 32 |
|
| 34 | 33 |
"github.com/openshift/origin/pkg/api/v1" |
| 35 | 34 |
"github.com/openshift/origin/pkg/api/v1beta3" |
| ... | ... |
@@ -105,7 +104,6 @@ import ( |
| 105 | 105 |
"github.com/openshift/origin/pkg/authorization/rulevalidation" |
| 106 | 106 |
configapi "github.com/openshift/origin/pkg/cmd/server/api" |
| 107 | 107 |
routeplugin "github.com/openshift/origin/pkg/route/allocation/simple" |
| 108 |
- "github.com/openshift/origin/pkg/version" |
|
| 109 | 108 |
) |
| 110 | 109 |
|
| 111 | 110 |
const ( |
| ... | ... |
@@ -161,7 +159,7 @@ func (c *MasterConfig) Run(protected []APIInstaller, unprotected []APIInstaller) |
| 161 | 161 |
} |
| 162 | 162 |
extra = append(extra, msgs...) |
| 163 | 163 |
} |
| 164 |
- handler := c.versionSkewFilter(version.Get(), kversion.Get(), safe) |
|
| 164 |
+ handler := c.versionSkewFilter(safe) |
|
| 165 | 165 |
handler = c.authorizationFilter(handler) |
| 166 | 166 |
handler = authenticationHandlerFilter(handler, c.Authenticator, c.getRequestContextMapper()) |
| 167 | 167 |
handler = namespacingFilter(handler, c.getRequestContextMapper()) |