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

KEP-4601: authorize with field and label selectors #4600

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

deads2k
Copy link
Contributor

@deads2k deads2k commented Apr 26, 2024

Still in progress, but the bones are here.

/assign @liggitt
/assign @micahhausler
/cc @enj

  • One-line PR description:
  • Issue link:
  • Other comments:

@k8s-ci-robot k8s-ci-robot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Apr 26, 2024
@k8s-ci-robot k8s-ci-robot requested a review from enj April 26, 2024 20:26
@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. approved Indicates a PR has been approved by an approver from all required OWNERS files. kind/kep Categorizes KEP tracking issues and PRs modifying the KEP directory sig/auth Categorizes an issue or PR as relevant to SIG Auth. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Apr 26, 2024
@deads2k deads2k changed the title [wip] authorize with field and label selectors KEP-4601: authorize with field and label selectors Apr 26, 2024
@k8s-ci-robot k8s-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Apr 26, 2024
keps/sig-auth/4601-authorize-with-selectors/README.md Outdated Show resolved Hide resolved
keps/sig-auth/4601-authorize-with-selectors/README.md Outdated Show resolved Hide resolved
keps/sig-auth/4601-authorize-with-selectors/README.md Outdated Show resolved Hide resolved
keps/sig-auth/4601-authorize-with-selectors/README.md Outdated Show resolved Hide resolved
keps/sig-auth/4601-authorize-with-selectors/README.md Outdated Show resolved Hide resolved
keps/sig-auth/4601-authorize-with-selectors/README.md Outdated Show resolved Hide resolved
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: deads2k

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

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Comment on lines 145 to 156
#### Future-proofing your authentication webhook for future verbs

As of 1.31, the only verbs with field and label selectors are List, Watch, and DeleteCollection.
<<[UNRESOLVED deads2k, liggitt, jpbetz, sttts: this is a future promise for the kube-apiserver behavior if we add it ]>>
In the future, the kube-apiserver may add field and label selectors to Create, Update, and Delete.
<<[/UNRESOLVED]>>
* For Create, this means that the resource after all mutation is complete (finalObject) must match the field and label selector.
* For Update, this means that the finalNewObject and oldObject must match the field and label selector.
* For Delete, this means that the oldObject must match the field and label selector.

We do not expand field and label selectors for Get, because if a client is specifying a selector, they can add a `.metadata.name`
field selector and use a List to get equivalent functionality.
Copy link
Contributor Author

@deads2k deads2k May 7, 2024

Choose a reason for hiding this comment

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

@jpbetz @sttts If we add field and label selectors, I'd like to provide advice to the authorization webhook authors about what the semantics will be. This is not a proposal to make those changes.

My intent is that if a field and/or label selector are specified on a mutation request, the object being mutated (both old and new) are guaranteed to match the selectors. If the object (old or new) does not match the selector, the storage layer rejects the request.

Copy link
Member

Choose a reason for hiding this comment

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

Do we need to define meaning of selectors if/when included for subresources in the future?

The main question I'd have is whether a distinction is made for subresources which do and do not see the full object in question (admission defines objectSelector to only work for subresources which see the full object)

  • examples of ones which see the full object: pods/status
  • examples of ones which do not see the full object: pods/{exec,attach,log,proxy,binding}, deployments/scale

Copy link
Contributor

Choose a reason for hiding this comment

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

My intent is that if a field and/or label selector are specified on a mutation request, the object being mutated (both old and new) are guaranteed to match the selectors. If the object (old or new) does not match the selector, the storage layer rejects the request.

This intuitively makes sense to me. This implies that updating a label or field matching the selector is only possible if there is another matching selector for the new label or field value? Am I reading this right that it will be possible to authorize multiple field and label selectors?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The main question I'd have is whether a distinction is made for subresources which do and do not see the full object in question (admission defines objectSelector to only work for subresources which see the full object)

I'm nearly in agreement. But I think that the storage layer of deployments/scale has the entire object. Versus admission which does not have the entire object. store *genericregistry.Store appears to be shared between spec, status, and scale.

Subresources that are not stored into etcd would not be able to enforce as uniformally. We could select specific subresources that we know end up in storage like status and scale. pods/binding and eviction would both be useful, but far narrower.

Copy link
Member

@liggitt liggitt left a comment

Choose a reason for hiding this comment

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

update looks pretty good to me, a couple more questions / some maybe-stale docs

In the future, the kube-apiserver may add field and label selectors to Create, Update, and Delete.
<<[/UNRESOLVED]>>
* For Create, this means that the resource after all mutation is complete (finalObject) must match the field and label selector.
* For Update, this means that the finalNewObject and oldObject must match the field and label selector.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* For Update, this means that the finalNewObject and oldObject must match the field and label selector.
* For Update/Patch, this means that the finalNewObject and oldObject must match the field and label selector.


As of 1.31, the only verbs with field and label selectors are List, Watch, and DeleteCollection.
<<[UNRESOLVED deads2k, liggitt, jpbetz, sttts: this is a future promise for the kube-apiserver behavior if we add it ]>>
In the future, the kube-apiserver may add field and label selectors to Create, Update, and Delete.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
In the future, the kube-apiserver may add field and label selectors to Create, Update, and Delete.
In the future, the kube-apiserver may add field and label selectors to Create, Update, Patch, and Delete.

Comment on lines 145 to 156
#### Future-proofing your authentication webhook for future verbs

As of 1.31, the only verbs with field and label selectors are List, Watch, and DeleteCollection.
<<[UNRESOLVED deads2k, liggitt, jpbetz, sttts: this is a future promise for the kube-apiserver behavior if we add it ]>>
In the future, the kube-apiserver may add field and label selectors to Create, Update, and Delete.
<<[/UNRESOLVED]>>
* For Create, this means that the resource after all mutation is complete (finalObject) must match the field and label selector.
* For Update, this means that the finalNewObject and oldObject must match the field and label selector.
* For Delete, this means that the oldObject must match the field and label selector.

We do not expand field and label selectors for Get, because if a client is specifying a selector, they can add a `.metadata.name`
field selector and use a List to get equivalent functionality.
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to define meaning of selectors if/when included for subresources in the future?

The main question I'd have is whether a distinction is made for subresources which do and do not see the full object in question (admission defines objectSelector to only work for subresources which see the full object)

  • examples of ones which see the full object: pods/status
  • examples of ones which do not see the full object: pods/{exec,attach,log,proxy,binding}, deployments/scale

Comment on lines 170 to 172
FieldSelector *FieldSelectorAttributes

LabelSelector *LabelSelectorAttributes
Copy link
Member

Choose a reason for hiding this comment

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

would these go under ResourceAttributes rather than directly under the SubjectAccessReviewSpec?

// If rawSelector is present and requirements are present, the request is invalid.
type FieldSelectorAttributes struct {
// rawSelector is the serialization of a field selector that would be included in a List query parameter.
// Webhook implementations must handle malformed rawSelectors.
Copy link
Member

Choose a reason for hiding this comment

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

// Webhook implementations must handle malformed rawSelectors.

Must they? A lot of the docs seem leftover from the first draft where the fields were not mutually exclusive

I'd encourage general webhook authors to:

  1. ensure rawSelector and requirements are not both set
  2. consider the requirements field if set
  3. not try to parse or consider the rawSelector field if set

similar questions on the other docs and other selector type

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Must they? A lot of the docs seem leftover from the first draft where the fields were not mutually exclusive

I'd encourage general webhook authors to:

how would you like to phrase: "clients can send you data that is invalid that a kube-apiserver will never send you. Think about it advance and don't crash"?

Copy link
Member

Choose a reason for hiding this comment

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

I think this covers it?

I'd encourage general webhook authors to:

  • ensure rawSelector and requirements are not both set
  • consider the requirements field if set
  • not try to parse or consider the rawSelector field if set

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok, willing to update.

Trying to decide how much carries to actual API documentation that appears on the SAR endpoint. I haven't checked docs to see if we have a separate place yet.

// If rawSelector is empty and requirements are present, the requirements should be honored
// If rawSelector is present and requirements are present, the request is invalid.
type FieldSelectorAttributes struct {
// rawSelector is the serialization of a field selector that would be included in a List query parameter.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// rawSelector is the serialization of a field selector that would be included in a List query parameter.
// rawSelector is the serialization of a field selector that would be included in a query parameter.

// Webhook implementations must handle malformed rawSelectors.
RawSelector string

// requirements is the parsed interpretation of the rawSelector.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// requirements is the parsed interpretation of the rawSelector.
// requirements is the parsed interpretation of a field selector.

Comment on lines 177 to 186
// The kube-apiserver will never send a request with rawSelector set, but we cannot control what other clients directly send.
// If rawSelector is empty and requirements are empty, the request is not limited.
// If rawSelector is present and requirements are empty, the request is not limited.
// If rawSelector is empty and requirements are present, the requirements should be honored
// If rawSelector is present and requirements are present, the request is invalid.
// For the kube-apiserver:
// If rawSelector is empty and requirements are empty, the request is not limited.
// If rawSelector is present and requirements are empty, the rawSelector will be parsed and limited if the parsing succeeds.
// If rawSelector is empty and requirements are present, the requirements should be honored
// If rawSelector is present and requirements are present, the request is invalid.
Copy link
Member

Choose a reason for hiding this comment

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

could these be simplified to:

* If `rawSelector` and `requirements` are both present, the request is invalid.
* For kube-apiserver: if `rawSelector` is present, the rawSelector will be parsed and honored if the parsing succeeds and the verb supports selectors.
* For kube-apiserver and webhooks: if requirements are present, the requirements should be honored if the verb supports selectors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the requirements should be honored if the verb supports selectors.

How and why would an authorizer make a decision about whether the client that called it supports selectors for a particular verb? If we make this a webhook responsibility, would this mean that the webhook needs to predict when the kube-apiserver will honor selectors for verb and subresource tuples?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I find the fully separation much easier to find what I'm looking for. Your feel strongly about simplifying? Do you want the change the to webhook semantics from what I proposed? I don't see how it's possible.

Key string `json:"key" protobuf:"bytes,1,opt,name=key"`
// operator represents a key's relationship to a set of values.
// Valid operators are In, NotIn, Exists, DoesNotExist
Operator LabelSelectorOperator `json:"operator" protobuf:"bytes,2,opt,name=operator,casttype=LabelSelectorOperator"`
Copy link
Member

Choose a reason for hiding this comment

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

since this is essentially an enum field, should describe how clients should handle unrecognized operators if we ever want the ability to expand this in the future

easiest way is to ignore entries with unrecognized operators and assume they don't limit the request


As of 1.31, the only verbs with field and label selectors are List, Watch, and DeleteCollection.
<<[UNRESOLVED deads2k, liggitt, jpbetz, sttts: this is a future promise for the kube-apiserver behavior if we add it ]>>
In the future, the kube-apiserver may add field and label selectors to Create, Update, and Delete.
Copy link
Contributor

@jpbetz jpbetz May 8, 2024

Choose a reason for hiding this comment

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

If, in the future, we add field/label selectors to Create/Update/Patch/Delete, is Get the only remaining unsupported CRUD operation? Should we support it in the future too?

Copy link
Contributor

Choose a reason for hiding this comment

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

Thinking about this more? Is an explicit selector ever needed for single resource operations? Is the actual value of the labels and fields sufficient for any authz checks that would need to be made?

Copy link
Member

Choose a reason for hiding this comment

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

authz doesn't have access to the body of the incoming object or the persisted content of the existing object

The query here would be like a self-attesting precondition the writer could optionally add that would be visible to authz and would have to be verified/blocking at the storage layer for the write to succeed.

The opt-in nature and the duplication with the body content is… a little weird, so I'm not sure if this is a direction we'd ever go, but defining how the precondition would be treated if we did is important.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, this explains it. I was wondering if this might be the motivation. Including this background in the KEP about why we could consider passing a field selector alongside a single resource operation that redundantly states information already in the resource seems valuable here.

Copy link
Member

@luxas luxas left a comment

Choose a reason for hiding this comment

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

Thanks @deads2k for writing this!

Very excited to get this going, happy to help out on some of the implementation as well 👍

I'm concerned about the sprawl of having two almost-identical representations, but not really in the SAR body. I'm all for making good, canonical client-/server-side libraries instead that wrap the complexity, and contain it there. Just such a thing as anding all requirements together into something that is equivalent but easily comparable/understandable is non-trivial unless one thinks a little bit deeper about the set theoretics.

## Summary

The authorization attributes will be extended to include field selectors and label selectors from
List, Watch, and Deletecollection.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
List, Watch, and Deletecollection.
List, Watch, and DeleteCollection.

sorry for the nit, but this would please my eye 😄


* Add field and label selectors to authorization attributes for List, Watch, and DeleteCollection verbs.
* Add field and label selectors to webhook authorization types.
* Add field and label selectors to SelfSubjectAccessReview (SSAR) and SubjectAccessReview (SAR).
Copy link
Member

Choose a reason for hiding this comment

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

field or label selectors since that will authorize using a wider permission (field and label selectors can only reduce access).

```go
type Attributes interface {
Copy link
Member

Choose a reason for hiding this comment

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

Are we concerned that if we add these two methods to the authorizer.Attributes interface now, implementers of the interface won't satisfy it on a go.mod update without manually adding those methods? We don't make promises AFAIK for stuff like that, but just asking.

Another alternative is to make another interface that can only be casted to if label/field selectors are available, but I don't like that alternative so much either.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are we concerned that if we add these two methods to the authorizer.Attributes interface now, implementers of the interface won't satisfy it on a go.mod update without manually adding those methods? We don't make promises AFAIK for stuff like that, but just asking.

I'm ok breaking people that integrated at this level. They should be aware of the semantic change and this is an easy way to force it.

* For Update/Patch, this means that the finalNewObject and oldObject must match the field and label selector.
* For Delete, this means that the oldObject must match the field and label selector.

We do not expand field and label selectors for Get, because if a client is specifying a selector, they can add a `.metadata.name`
Copy link
Member

Choose a reason for hiding this comment

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

what do you mean with "expand" here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

clarified

SubjectAccessReview is used for two purposes:
1. Authorization webhook calls from the kube-apiserver to a webhook.
This usage likely benefits from a serialization with `[]Requirement`.
2. Authorization checks from a client (often a server process using in-cluster authorization like kube-rbac-proxy)
Copy link
Member

Choose a reason for hiding this comment

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

Is parsing the URI into requirements really that bad that we have to add two modes, and make the matrix of parsing the SAR much much harder? I would think the opposite, if we have a canonical way (in a Go library) to encode/decode the Requirements into a string, and define strong semantics for the Requirements (e.g. how they can be simplified and such), I would believe that makes it easier for the SAR client to introspect what is happening.

That reduces the burden of the API server and webhooks to understand/parse arbitrary strings. That complexity has to live somewhere, but it seems most fair to put that where it is ultimately needed, the SAR client which serves the http request.

I would really really like to avoid having two modes that expand the matrix significantly.

If we have a good codec for Requirements <-> string, that could even over time start supporting (opt-in) new, canonical functionality, such as set In/NotIn semantics instead of only Equal/NotEqual we have today, without the SAR client even noticing.

We anyways need that codec easily accessible for webhooks, and other places. Why expand the surface unnecessarily? And isn't adding rawSelector something that is a net-add in the future, if we later saw it was absolutely necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is parsing the URI into requirements really that bad that we have to add two modes, and make the matrix of parsing the SAR much much harder? I would think the opposite

It's non-trivial and not all webhook implementations are in go, so providing a golang library (note that we already include parsers in apimachinery) falls well short.

SAR to the kube-apiserver will parse the RawSelector for convenience.

Copy link
Member

Choose a reason for hiding this comment

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


type FieldSelectorRequirement struct {
// key is the label key that the selector applies to.
Key string `json:"key" protobuf:"bytes,1,opt,name=key"`
Copy link
Member

Choose a reason for hiding this comment

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

What format is this? JSONPath? I know it exists already but how strictly is it defined today, and do we feel that is a strong and secure enough set of semantics. How does this react to e.g. sth like .spec.containers[*].name? We now have CEL as well, which we did not have in k8s infancy when labelSelectors were created.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What format is this?

Arbitrary string with no semantic meaning attached. That's the meaning today and I don't propose to change it. CRs are slightly more strict.


This type of usage probably finds the stringified serialization format used in the query parameters the
most convenient format to build their request with.
Providing the query parameter serialization format avoids the need for a client to grow a decently complex lexer/parser.
Copy link
Member

Choose a reason for hiding this comment

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

See my comment above. Someone always have to parse the rawQuery at the end of the day, and I'd like to do that in the place where it doesn't blow up the complexity for others, i.e. in this SAR client. (with well-defined Go libraries to handle this easily, of course).

I expect the SAR client to be interested in what it is forwarding as well, and maybe even through introspection be able to deny or allow certain requests without sending the SAR altogether.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Someone always have to parse the rawQuery at the end of the day,

In this proposal, that someone is the kube-apiserver (or aggregated apiserver).

Providing the parsed value avoids the need for every consumer to grow a decently complex lexer/parser.

### Notes/Constraints/Caveats (Optional)

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Remember to update these places in existing code:

// Valid operators are In, NotIn, Exists, DoesNotExist
// The list of operators may grow in the future.
// Webhook authors are encouraged to ignore unrecognized operators and assume they don't limit the request.
// The semantics of "all requirements are AND'd will not change, so other requirements can continue to be enforced.
Copy link
Member

Choose a reason for hiding this comment

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

I believe we should provide a function to "simplify" the requirements into a "canonical representation". For example, if there are multiple rules for the same key, one can apply the following rules:

  1. Simplify Equals/NotEquals to In/NotIn (this already happens in the rawSelector parsing layer essentially)
    Equals foo => In [foo]
    NotEquals foo => NotIn [foo]

  2. Simplify In/NotIn separately

In [a,b] && In [b,c] => In [b] (intersection)
NotIn [a,b] && NotIn [b,c] => NotIn [a,b,c] (union)

By this stage, we have at most one In and one NotIn requirement per key (plus any possible Exists/NotExist, handled later)

  1. Simplify In/NotIn together

In [a,b] && NotIn [b,c] => In [a] (subtraction)

Note: this must be done last (as far as I can see), as the previous union/intersection operations are commutative, but subtraction is not.

In the end of this process we have at most one requirement with operator In or NotIn (not both), plus any possible Exists/NotExist, handled later.

  1. Simplify Exists/NotExists

Exists && Exists => Exists
NotExists && NotExists => NotExists
Exists && NotExists => ∅ (a label cannot both be defined and not for the same object, unsatisfiable)

At this point, we have at most one (In or NotIn) and one (Exists or NotExists).
Of course, we can short-circuit earlier if we get an empty set before, as then the requirements are unsatisfiable by any object.

  1. Combine one (In or NotIn) and one (Exists or NotExists)

In [a,b] && Exists => In [a,b] (if foo=a or foo=b is true, foo does exist)
NotIn [a,b] && Exists => NotIn [a,b] && Exists (no simplification possible)
In [a,b] && NotExists => ∅ (if the label must both be set and not set, req is unsatisfiable)
NotIn [a,b] && NotExists => NotExists (a label not existing certainly is not set to a given value)

At this point, of all possible requirements, we have at most the following requirements for each key:
In [a,b]
NotIn [a,b]
Exists
NotExists
∅ (unsatisfiable, which makes the whole requirements list for any object unsatisfiable)
NotIn [a,b] && Exists

This "simplified/parsed" requirements set could provide a dedicated interface, which can answer e.g. ObjectMatches(obj), Unsatisfiable(), Equal(otherRequirements), GreaterThan(otherRequirements, etc., such that one can semantically compare varying requirements sets with each other (a use case that will be very much needed).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe we should provide a function to "simplify" the requirements into a "canonical representation". For example, if there are multiple rules for the same key, one can apply the following rules:

I don't see a reason to do this at the moment.

Copy link
Member

Choose a reason for hiding this comment

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

Those are interesting ideas. Simplifying / making canonical could be useful, but I agree it isn't needed for the bits proposed by this KEP.

Places where it could be useful in the future:

  1. Optimizing the thing satisfying the list / watch (no point in querying for an unsatisfiable filter, collapsing multiple requirements to a single requirement could make list evaluation more efficient)
  2. Determining "covers" checks to see if one selector covers another

A transformer / wrapper that does those simplifications could be implemented as standalone (even out-of-tree) functions if you wanted to do that.

// rawSelector is the serialization of a field selector that would be included in a query parameter.
// Webhook implementations are encouraged to ignore rawSelector.
// The kube-apiserver's SubjectAccessReview will parse the rawSelector.
RawSelector string
Copy link
Member

Choose a reason for hiding this comment

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

Talking about RawSelector, at the moment we only support Equals/NotEquals/Exists/NotExists in the url encoding, right? As we're looking into this, how do we feel about adding In/NotIn semantics like labelSelector=foo=a|b|c? I guess it's kind of impossible at this point, because we don't limit the content set on label values, so we cannot choose a character that can act as the separator.

Another thing I was thinking is labelSelector=foo=a,foo=b,foo=c, but that ends up being three different requirements, which ANDed together becomes an unsatisfiable requirements set (see the logic below).

I don't know, but it feels like if we start expanding the scope of these selectors, that's a practical issue that instantly arises for consumers.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently every discrete requirement is AND'd when evaluated server-side. I don't see a need to change that behavior.

Copy link
Member

Choose a reason for hiding this comment

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

Currently every discrete requirement is AND'd when evaluated server-side. I don't see a need to change that behavior.

Agreed. In fact if we do change it from AND we break the ability to expand operators in the future safely.

With AND semantics, a webhook can check for restrictions they understand, short-circuit when they find a limiting one they are satisfied by, ignore ones with operators they don't recognize and treat them as non-limiting, and fail in a safe direction in the presence of unrecognized operators.

it feels like if we start expanding the scope of these selectors, that's a practical issue that instantly arises for consumers.

Given selectors are already part of our API, both in string and structured form, I don't think plumbing the current semantics into authz really expands their scope, especially if we give explicit instructions for how to treat unrecognized operators that makes it safe to accommodate operator expansion in the future.

Comment on lines 111 to 112
* Expand the admission surface area (admission.Attributes, AdmissionReview, CEL authorizer implementation available to admission)
since admission verbs don't support field/label selectors
Copy link
Member

Choose a reason for hiding this comment

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

What if a CEL authz call wants to check list with selectors?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What if a CEL authz call wants to check list with selectors?

Interesting thought. I'll have a think on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree this should be addressed and that it's an API change, so it must be done during the alpha stage. As I recall, CEL library modifications take two releases to roll out.


```go
type Attributes interface {
// ParseLabelSelector is lazy, thread-safe, and stores the parsed result and error.
Copy link
Member

Choose a reason for hiding this comment

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

Does it actually have to be thread safe?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does it actually have to be thread safe?

Yes. I don't want to constrain future due to not adding a sync.Once.

Comment on lines +155 to +156
We do not allow field and label selectors for Get, because if a client is specifying a selector, they can add a `.metadata.name`
field selector and use a List to get equivalent functionality.
Copy link
Member

Choose a reason for hiding this comment

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

Are we sure this is good enough?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are we sure this is good enough?

I can't think of what else Get is beyond a single-item list.

### Non-Goals

* Create a generic in-tree authorizer that manages field or label selectors.
* Expand the audit surface area, since requestURI is already included
Copy link
Member

Choose a reason for hiding this comment

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

How do I, as a cluster admin/operator, know exactly what SAR a request was authorized for?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How do I, as a cluster admin/operator, know exactly what SAR a request was authorized for?

given a request URI, you know the field and label selectors used.

Comment on lines 189 to 192
// Webhook authors are encouraged to
// * ensure rawSelector and requirements are not both set
// * consider the requirements field if set
// * not try to parse or consider the rawSelector field if set
Copy link
Member

Choose a reason for hiding this comment

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

We should mention that this is to avoid another CVE-2022-2880 (i.e. getting different systems to agree on how exactly to parse a query is not something we want), see https://www.oxeye.io/resources/golang-parameter-smuggling-attack for more details.

Requirements []FieldSelectorRequirement
}

// LabelSelectorAttributes indicates a field limited access.
Copy link
Member

Choose a reason for hiding this comment

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

?

Suggested change
// LabelSelectorAttributes indicates a field limited access.
// LabelSelectorAttributes indicates a label limited access.

* Add field and label selectors to authorization attributes for List, Watch, and DeleteCollection verbs.
* Add field and label selectors to webhook authorization types.
* Add field and label selectors to SelfSubjectAccessReview (SSAR), SubjectAccessReview (SAR), and LocalSubjectAccessReview.
* Update node authorizer to restrict on nodeName field selector.
Copy link
Member

Choose a reason for hiding this comment

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

I feel like this doc should include more details on the node authz part.

@k8s-ci-robot
Copy link
Contributor

@deads2k: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
pull-enhancements-verify 936e914 link true /test pull-enhancements-verify

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-sigs/prow repository. I understand the commands that are listed here.

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/kep Categorizes KEP tracking issues and PRs modifying the KEP directory sig/auth Categorizes an issue or PR as relevant to SIG Auth. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.
Projects
Status: In Review
Development

Successfully merging this pull request may close these issues.

None yet

8 participants