-
Notifications
You must be signed in to change notification settings - Fork 38.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement basic admission control framework #3248
Merged
erictune
merged 6 commits into
kubernetes:master
from
derekwaynecarr:admission_control_hooks
Jan 8, 2015
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
520ae3e
Implement basic admission control framework
derekwaynecarr 1e2b995
Fix admission control in tests
derekwaynecarr 74d2ee6
Fix boilerplate and make stub controller
derekwaynecarr 5ceffe2
Add tests to ensure resthandler invokes admission control
derekwaynecarr 2820c2c
Add plugin tests
derekwaynecarr a56087c
Remove client from attributes, remove admission control interface, fi…
derekwaynecarr File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* | ||
Copyright 2014 Google Inc. All rights reserved. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package admission | ||
|
||
import ( | ||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" | ||
) | ||
|
||
type attributesRecord struct { | ||
namespace string | ||
kind string | ||
operation string | ||
object runtime.Object | ||
} | ||
|
||
func NewAttributesRecord(object runtime.Object, namespace, kind, operation string) Attributes { | ||
return &attributesRecord{ | ||
namespace: namespace, | ||
kind: kind, | ||
operation: operation, | ||
object: object, | ||
} | ||
} | ||
|
||
func (record *attributesRecord) GetNamespace() string { | ||
return record.namespace | ||
} | ||
|
||
func (record *attributesRecord) GetKind() string { | ||
return record.kind | ||
} | ||
|
||
func (record *attributesRecord) GetOperation() string { | ||
return record.operation | ||
} | ||
|
||
func (record *attributesRecord) GetObject() runtime.Object { | ||
return record.object | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
Copyright 2014 Google Inc. All rights reserved. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package admission | ||
|
||
import ( | ||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" | ||
) | ||
|
||
// chainAdmissionHandler is an instance of admission.Interface that performs admission control using a chain of admission handlers | ||
type chainAdmissionHandler []Interface | ||
|
||
// New returns an admission.Interface that will enforce admission control decisions | ||
func NewFromPlugins(client client.Interface, pluginNames []string, configFilePath string) Interface { | ||
plugins := []Interface{} | ||
for _, pluginName := range pluginNames { | ||
plugin := InitPlugin(pluginName, client, configFilePath) | ||
if plugin != nil { | ||
plugins = append(plugins, plugin) | ||
} | ||
} | ||
return chainAdmissionHandler(plugins) | ||
} | ||
|
||
// Admit performs an admission control check using a chain of handlers, and returns immediately on first error | ||
func (admissionHandler chainAdmissionHandler) Admit(a Attributes) (err error) { | ||
for _, handler := range admissionHandler { | ||
err := handler.Admit(a) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
Copyright 2014 Google Inc. All rights reserved. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package admission | ||
|
||
import ( | ||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" | ||
) | ||
|
||
// Attributes is an interface used by AdmissionController to get information about a request | ||
// that is used to make an admission decision. | ||
type Attributes interface { | ||
GetNamespace() string | ||
GetKind() string | ||
GetOperation() string | ||
GetObject() runtime.Object | ||
} | ||
|
||
// Interface is an abstract, pluggable interface for Admission Control decisions. | ||
type Interface interface { | ||
// Admit makes an admission decision based on the request attributes | ||
Admit(a Attributes) (err error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/* | ||
Copyright 2014 Google Inc. All rights reserved. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package admission | ||
|
||
import ( | ||
"io" | ||
"os" | ||
"sync" | ||
|
||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" | ||
"github.com/golang/glog" | ||
) | ||
|
||
// Factory is a function that returns a Interface for admission decisions. | ||
// The config parameter provides an io.Reader handler to the factory in | ||
// order to load specific configurations. If no configuration is provided | ||
// the parameter is nil. | ||
type Factory func(client client.Interface, config io.Reader) (Interface, error) | ||
|
||
// All registered admission options. | ||
var pluginsMutex sync.Mutex | ||
var plugins = make(map[string]Factory) | ||
|
||
// GetPlugins enumerates the | ||
func GetPlugins() []string { | ||
pluginsMutex.Lock() | ||
defer pluginsMutex.Unlock() | ||
keys := []string{} | ||
for k := range plugins { | ||
keys = append(keys, k) | ||
} | ||
return keys | ||
} | ||
|
||
// RegisterPlugin registers a plugin Factory by name. This | ||
// is expected to happen during app startup. | ||
func RegisterPlugin(name string, plugin Factory) { | ||
pluginsMutex.Lock() | ||
defer pluginsMutex.Unlock() | ||
_, found := plugins[name] | ||
if found { | ||
glog.Fatalf("Admission plugin %q was registered twice", name) | ||
} | ||
glog.V(1).Infof("Registered admission plugin %q", name) | ||
plugins[name] = plugin | ||
} | ||
|
||
// GetInterface creates an instance of the named plugin, or nil if | ||
// the name is not known. The error return is only used if the named provider | ||
// was known but failed to initialize. The config parameter specifies the | ||
// io.Reader handler of the configuration file for the cloud provider, or nil | ||
// for no configuration. | ||
func GetPlugin(name string, client client.Interface, config io.Reader) (Interface, error) { | ||
pluginsMutex.Lock() | ||
defer pluginsMutex.Unlock() | ||
f, found := plugins[name] | ||
if !found { | ||
return nil, nil | ||
} | ||
return f(client, config) | ||
} | ||
|
||
// InitPlugin creates an instance of the named interface | ||
func InitPlugin(name string, client client.Interface, configFilePath string) Interface { | ||
var config *os.File | ||
|
||
if name == "" { | ||
glog.Info("No admission plugin specified.") | ||
return nil | ||
} | ||
|
||
if configFilePath != "" { | ||
var err error | ||
|
||
config, err = os.Open(configFilePath) | ||
if err != nil { | ||
glog.Fatalf("Couldn't open admission plugin configuration %s: %#v", | ||
configFilePath, err) | ||
} | ||
|
||
defer config.Close() | ||
} | ||
|
||
plugin, err := GetPlugin(name, client, config) | ||
if err != nil { | ||
glog.Fatalf("Couldn't init admission plugin %q: %v", name, err) | ||
} | ||
if plugin == nil { | ||
glog.Fatalf("Unknown admission plugin: %s", name) | ||
} | ||
|
||
return plugin | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -92,6 +92,20 @@ func NewAlreadyExists(kind, name string) error { | |
}} | ||
} | ||
|
||
// NewForbidden returns an error indicating the requested action was forbidden | ||
func NewForbidden(kind, name string, err error) error { | ||
return &StatusError{api.Status{ | ||
Status: api.StatusFailure, | ||
Code: http.StatusForbidden, | ||
Reason: api.StatusReasonForbidden, | ||
Details: &api.StatusDetails{ | ||
Kind: kind, | ||
ID: name, | ||
}, | ||
Message: fmt.Sprintf("%s %q is forbidden", kind, name), | ||
}} | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The authorizer returns forbidden but it doesn't use NewForbidden. Not sure if that is a problem? |
||
// NewConflict returns an error indicating the item can't be updated as provided. | ||
func NewConflict(kind, name string, err error) error { | ||
return &StatusError{api.Status{ | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this need an else clause like some other options have above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. Absence of a value will just cause kube-apiserver to take the default "AlwaysAdmit"