Skip to content
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

Dynamic webhook admission control plugin #46388

Conversation

lavalamp
Copy link
Member

@lavalamp lavalamp commented May 24, 2017

Unit tests pass.

Needs plumbing:

  • service resolver (depends on @wfender PR)
  • client cert (depends on ????)
  • hook source (depends on @caesarxuchao PR)

Also at least one thing will need to be renamed after Chao's PR merges.

Allow remote admission controllers to be dynamically added and removed by administrators.  External admission controllers make an HTTP POST containing details of the requested action which the service can approve or reject.

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label May 24, 2017
@k8s-github-robot k8s-github-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. release-note-label-needed labels May 24, 2017
wg.Wait()

if failCount > 0 {
return ErrWebhookRejected
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this descriptive enough? An API caller has no idea why it was rejected and the only possible way to figure that out is by accessing the API server logs, which is likely not an option. Is there any good way to display the error(s) back to the user? (To me, it would be nice if all webhook responses with Status.Result.Reason were returned to the user that way they could possibly remedy the issue.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I can fix that, sure.

// TODO: set KeyData/CertData
},
UserAgent: "kube-apiserver-admission",
Timeout: 30 * time.Second,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason we cannot make this configurable? Might not be necessary for 1.0 but I can see this being useful in the future.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future. not needed for mvp I think.

@@ -115,4 +132,12 @@ func (i pluginInitializer) Initialize(plugin admission.Interface) {
if wants, ok := plugin.(WantsQuotaRegistry); ok {
wants.SetQuotaRegistry(i.quotaRegistry)
}

if wants, ok := plugin.(WantsServiceResolver); ok {
wants.SetQuotaRegistry(i.serviceResolver)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed without running :)

@k8s-github-robot k8s-github-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 26, 2017
@lavalamp lavalamp force-pushed the whitlockjc-generic-webhook-admission branch from 61cbce5 to 374b5b7 Compare May 26, 2017 21:08
@k8s-github-robot k8s-github-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 26, 2017
"k8s.io/kubernetes/pkg/api"
admissionv1alpha1 "k8s.io/kubernetes/pkg/apis/admission/v1alpha1"

// install the clientgo admission API for use with api registry
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/clientgo//

defer testServer.Close()
serverURL, err := url.ParseRequestURI(testServer.URL)
if err != nil {
t.Fatalf("???? %v", err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the "????"

rootCAs.AppendCertsFromPEM(caCert)
testServer := httptest.NewUnstartedServer(http.HandlerFunc(webhookHandler))
testServer.TLS = &tls.Config{
Certificates: []tls.Certificate{cert},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it correct to let the server use a cert generated from cleintCert and clientKey?

Z0gPepfIFptDMl5wKWyw4o2XVSZ69Ur8tQQynoNyX/FTIx6tQ//hzg==
-----END CERTIFICATE-----`)

var badCAKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forget to add a test that uses badCAKey?

"wildcard": {
rule: apiserver.RuleWithOperations{
Rule: apiserver.Rule{
APIGroups: []string{"*"},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation rule requires the APIGroups/APIVersions/Resources/Operations to be non-empty. Can you update these rules to be valid?

@k8s-github-robot k8s-github-robot added the kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API label May 26, 2017
fs.StringVar(&s.ProxyClientKeyFile, "proxy-client-key-file", s.ProxyClientKeyFile,
"client certificate key used to prove the identity of the aggragator or kube-apiserver when it proxies requests to a user api-server")
fs.StringVar(&s.ProxyClientCertFile, "proxy-client-cert-file", s.ProxyClientCertFile, ""+
"Client certificate used to prove the identity of the aggragator or kube-apiserver "+
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

cloudConfig []byte
restMapper meta.RESTMapper
quotaRegistry quota.Registry
type WantsServiceResolver interface {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick godoc on each

@k8s-github-robot k8s-github-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 30, 2017
if e.Reason != "" {
return fmt.Sprintf("rejected by webhook %q: %v", e.WebhookName, e.Reason)
}
return fmt.Sprintf("rejected by webhook %q without explanation", e.WebhookName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rejected by admission webhook ... for both

"k8s.io/kubernetes/pkg/api"
admissionv1alpha1 "k8s.io/kubernetes/pkg/apis/admission/v1alpha1"
"k8s.io/kubernetes/pkg/apis/admissionregistration"
adinit "k8s.io/kubernetes/pkg/kubeapiserver/admission"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird prefix, I don't care that much but should be admissioninit

defer wg.Done()
allowed, reason, err := a.callHook(hook, attr)
if err != nil {
glog.Warningf("Failed calling webhook %v: %v", hook.Name, err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utilruntime.HandleError()

wg.Wait()
close(errCh)

errs := []error{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var errs []error avoids allocating if errors is empty.

return fmt.Errorf("failed listing hooks: %v", err)
}

errCh := make(chan error, len(hooks))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wire a context through here so we can add cancelation in the future. context.TODO is fine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

file a follow up issue on admission that we need to be passing a context down into the admission chain.

}

var statusCode int
if response.StatusCode(&statusCode); statusCode < 200 || statusCode >= 300 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary and already handled by response.Error().

return false, "", fmt.Errorf("error contacting webhook %q: %d", h.Name, statusCode)
}

if err := response.Into(&request); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fold this into 172.


if !request.Status.Allowed {
if request.Status.Result != nil {
reason = string(request.Status.Result.Reason)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be returning the actual status back, and then converting it to an error. We shouldn't be transforming status -> string -> error.

I.e. the status field should be passed (if specified) otherwise we need to create a stub one which is generic admission failure. That status should then be wrapped in StatusErr{}. I think you could just get away with returning the error here - reason doesn't need to be separately split.

}

// TODO: cache these instead of constructing one each time
cfg := &rest.Config{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going to be really expensive to do this on every single admission call. Certainly can't afford to do it at scale. How high scale are you planning on using this at? I would say open a bug for this and we can fix it post dcut.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is alpha. So I think high scale isn't super important. If this is too limiting then we can fix it as a bug.

@smarterclayton
Copy link
Contributor

For e2e test we really need a way to start an image that has embedded code to act as a server. Do we have a small image we use in e2e that has go installed in it (so we can go run a file provided via env / shell arg)?

@lavalamp lavalamp force-pushed the whitlockjc-generic-webhook-admission branch from 23e3a52 to 0ab9415 Compare May 30, 2017 18:30
To properly register the types in the admission API group we need to
create an "install" package and wire it up.  This is required by the
webhook admission controller being developed as part of
kubernetes/community#132
As part of kubernetes/community#132, thsi commit
adds a generic webhook admission controller.  This plugin allows for a
completely declarative approach for filtering/matching admission requests
and for matching admission requests, calls out to an external webhook for
handling admission requests.
@lavalamp lavalamp force-pushed the whitlockjc-generic-webhook-admission branch from 5d12dc1 to 04a7269 Compare May 31, 2017 18:42
@lavalamp
Copy link
Member Author

@k8s-bot pull-kubernetes-e2e-gce-etcd3 test this

1 similar comment
@lavalamp
Copy link
Member Author

@k8s-bot pull-kubernetes-e2e-gce-etcd3 test this

Copy link
Member

@caesarxuchao caesarxuchao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm. One nit.

limitations under the License.
*/

// Package webhook checks a webhook for configured operation admission
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/checks a webhook/checks webhooks

@lavalamp
Copy link
Member Author

if the etcd3 test fails again I will fix the nit, otherwise I'll fix in a followup.

@lavalamp lavalamp force-pushed the whitlockjc-generic-webhook-admission branch from 04a7269 to c46e231 Compare May 31, 2017 23:38
@smarterclayton
Copy link
Contributor

/lgtm

May god have mercy on our souls

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label May 31, 2017
@k8s-ci-robot
Copy link
Contributor

k8s-ci-robot commented Jun 1, 2017

@lavalamp: The following test(s) failed:

Test name Commit Details Rerun command
pull-kubernetes-cross c46e231 link @k8s-bot pull-kubernetes-cross test this

Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

@k8s-github-robot
Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: lavalamp, smarterclayton

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these OWNERS Files:

You can indicate your approval by writing /approve in a comment
You can cancel your approval by writing /approve cancel in a comment

@k8s-github-robot k8s-github-robot added the do-not-merge DEPRECATED. Indicates that a PR should not merge. Label can only be manually applied/removed. label Jun 1, 2017
@smarterclayton
Copy link
Contributor

@k8s-bot pull-kubernetes-e2e-gce-etcd3 test this

@smarterclayton smarterclayton added release-note Denotes a PR that will be considered when it comes time to generate release notes. and removed do-not-merge DEPRECATED. Indicates that a PR should not merge. Label can only be manually applied/removed. release-note-label-needed labels Jun 1, 2017
@smarterclayton smarterclayton added this to the v1.7 milestone Jun 1, 2017

// SetWebhookSource sets the webhook source-- admittedly this is probably
// specific to the external admission hook plugin.
func (i *PluginInitializer) SetWebhookSource(w WebhookSource) *PluginInitializer {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to remove SetWebhookSource. This should be a SetExternalClient, and we should initialize a webhookconfiguration manager in the method, like what Clayton did in b75238f#diff-3551f205184f7273b78e802da8fdc72fR93.

@k8s-github-robot
Copy link

Automatic merge from submit-queue (batch tested with PRs 46239, 46627, 46346, 46388, 46524)

@k8s-github-robot k8s-github-robot merged commit e837c3b into kubernetes:master Jun 3, 2017
k8s-github-robot pushed a commit that referenced this pull request Jun 15, 2017
Automatic merge from submit-queue (batch tested with PRs 47204, 46808, 47432, 47400, 47099)

Make the generic webhook admission controller use the dynamic webhook config manager

Based on #46672 and #46388.

Only the last commit is unique.

* removed `SetWebhookSource` from the PluginInitializer
* implemented `SetExternalClientset` for the generic webhook admisson controller, initializing an ExternalWebhookConfigurationManager in the method.
perotinus pushed a commit to kubernetes-retired/cluster-registry that referenced this pull request Sep 2, 2017
Automatic merge from submit-queue (batch tested with PRs 46076, 43879, 44897, 46556, 46654)

Use meta.v1 GroupVersionKind with json tags to generate OpenAPI spec

We are using two different GVK struct in generation of OpenAPI extensions. This PR unify that and also add json tags to meta.v1 GVK to comply with json naming system in other serializations. Also the value of Action extension is now lowercase.

ref: kubernetes/kubernetes#46388
akhilerm pushed a commit to akhilerm/apimachinery that referenced this pull request Sep 20, 2022
Automatic merge from submit-queue (batch tested with PRs 46076, 43879, 44897, 46556, 46654)

Use meta.v1 GroupVersionKind with json tags to generate OpenAPI spec

We are using two different GVK struct in generation of OpenAPI extensions. This PR unify that and also add json tags to meta.v1 GVK to comply with json naming system in other serializations. Also the value of Action extension is now lowercase.

ref: kubernetes/kubernetes#46388

Kubernetes-commit: e97b72296f36f0282fc9453fe288d249d906667b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API lgtm "Looks good to me", indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants