-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Option to customize NamespaceTransformer role binding subject handling #4704
Option to customize NamespaceTransformer role binding subject handling #4704
Conversation
Skipping CI for Draft Pull Request. |
cecdf24
to
7e2312d
Compare
// objects will have their namespace fields set. Overrides field specs provided for these types, if any. | ||
// - defaultOnly (default): namespace will be set only on subjects named "default". | ||
// - all: namespace will be set on all subjects | ||
// - none: all subjects will be skipped. |
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.
This is an interesting idea, and I really like it!
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.
One complication I just realized is the meaning of "all". Some options:
- Support the value, and drive it with
create: false
fieldspecs. This means all subject namespaces with any value will be overwritten, allowing the user to effectively tell us which subjects are namespaced by setting dummy values in them. Has a weird interaction whereskipExisting: true, setRoleBindingSubjects: all
sets nothing. - Support the value, and drive it with
create: true
fieldspecs. I think this is unacceptable, because it will add namespaces to subjects with cluster-scoped kinds. - Don't support that value, but stop stripping the role binding fieldspecs so that users can do one of the above themselves (not any more elegantly).
- Don't support that value, and continue stripping the role binding fieldspecs.
- Support the value, and drive it with openAPI-aware and/or bespoke code (I could be wrong don't think User and Group are part of openapi, since they're not real kinds). Much the same as we do for metadata.namespace, except only do it if the "all" option is specified or the fieldspecs are given.
This PR currently does the first one. But I'm leaning towards one of the last two after typing this out.
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.
I update the PR to do option 5. Confirmed that the OpenAPI does not identify User or Group as cluster-scoped, so was not usable for this purpose.
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.
Sorry for the late response. I agree that the last two options are best, and am happy with the choice of option 5.
7e2312d
to
df42626
Compare
@KnVerey: This PR has multiple commits, and the default merge method is: merge. 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. |
6375d3b
to
feb93be
Compare
api/filters/filtersutil/setters.go
Outdated
func SetEntry(key, value, tag string) SetFn { | ||
// SetEntry returns a SetFn to set a field or a map entry to a value. | ||
// It can be used with an empty name to set both a value and a tag on a scalar node. | ||
// When setting only a value on a scalar node, use SetScalar instead. |
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.
These new sentences were already true, but since the comment said it "set an entry in a map" I was initially confused, thinking NamespaceTransformer was doing the wrong thing / relying on an unintentional behaviour. But no, FieldSetter is documented to handle both scalars and maps, so SetEntry
does too (even though "entry" sounds like it targets a sequence, which is not handled 😕 ).
api/filters/filtersutil/setters.go
Outdated
return func(node *yaml.RNode) error { | ||
return node.PipeE(yaml.FieldSetter{StringValue: value}) | ||
} | ||
return SetEntry("", value, yaml.NodeTagEmpty) |
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.
Since yaml.FieldSetter
with an empty Name
and populated StringValue
creates a NewScalarRNode internally, this is exactly the same thing.
api/filters/filtersutil/setters.go
Outdated
n := &yaml.Node{ | ||
Kind: yaml.ScalarNode, | ||
Value: value, | ||
Tag: tag, | ||
} | ||
return func(node *yaml.RNode) error { | ||
return node.PipeE(yaml.FieldSetter{ | ||
Name: key, | ||
Name: name, |
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.
as with the other changes, this is to make it more clear that it's perfectly fine to use SetEntry with scalars (which don't have keys)
kind: RoleBinding | ||
- path: subjects | ||
- path: subjects/namespace |
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.
These were incorrect and previously unused. While subjects
is a valid fieldspec, it returns a map that includes the namespace field. The name reference transformer uses specs like as a signal to modify multiple fields at once (name and namespace), but this one expects scalars. I take it the pre-kyaml version of the transformer used these, and it must have been written differently.
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.
The subjects
is a slice of object which can have namespace
field. Using subjects/namespace
here seems to indicate kustomize deals with slice type in jsonpath this way (compared to the replacement transformer syntax []
, like subjects[].namespace
).
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.
Correct, it isn't JsonPath syntax. For better or for worse, these older transformers use Kustomize's own field path syntax in their fieldSpec
fields.
@@ -6,14 +6,12 @@ package builtinpluginconsts | |||
const ( | |||
namespaceFieldSpecs = ` | |||
namespace: | |||
- path: metadata/namespace | |||
create: true |
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.
We could leave this in, or not. It's ignored either way... in fact it is actively stripped out when the defaults or user-provided specs include it.
// objects will have their namespace fields set. Overrides field specs provided for these types, if any. | ||
// - defaultOnly (default): namespace will be set only on subjects named "default". | ||
// - all: namespace will be set on all subjects | ||
// - none: all subjects will be skipped. |
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.
One complication I just realized is the meaning of "all". Some options:
- Support the value, and drive it with
create: false
fieldspecs. This means all subject namespaces with any value will be overwritten, allowing the user to effectively tell us which subjects are namespaced by setting dummy values in them. Has a weird interaction whereskipExisting: true, setRoleBindingSubjects: all
sets nothing. - Support the value, and drive it with
create: true
fieldspecs. I think this is unacceptable, because it will add namespaces to subjects with cluster-scoped kinds. - Don't support that value, but stop stripping the role binding fieldspecs so that users can do one of the above themselves (not any more elegantly).
- Don't support that value, and continue stripping the role binding fieldspecs.
- Support the value, and drive it with openAPI-aware and/or bespoke code (I could be wrong don't think User and Group are part of openapi, since they're not real kinds). Much the same as we do for metadata.namespace, except only do it if the "all" option is specified or the fieldspecs are given.
This PR currently does the first one. But I'm leaning towards one of the last two after typing this out.
/test all |
feb93be
to
16f83e1
Compare
e9ea157
to
2091c22
Compare
2091c22
to
fda85ca
Compare
- path: metadata/name | ||
kind: Namespace | ||
create: true | ||
- path: subjects | ||
- path: subjects/namespace |
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.
These are also stripped. Should we fix them (as this is doing) or just remove them?
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.
Is there any purpose of keeping them in here? I see why we need to strip them for user provided fieldspecs but I'm not sure I understand the purpose of keeping stripped values in our builtin fieldspecs.
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.
It would just be to show that the transformer affects these fields, I guess. In theory we could use it as a signal of whether or not we should (manually) modify them, but in practice that could be a breaking change for people who have existing manually configured transformers. I'm definitely fine with removing them.
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.
I have a slight preference for removing them, but don't feel too strongly either way.
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.
removed
group: rbac.authorization.k8s.io | ||
- path: subjects/namespace | ||
kind: ClusterRoleBinding | ||
group: rbac.authorization.k8s.io |
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.
in the tests, I'm keeping both the old invalid paths and the valid paths to prove they all get stripped. If we stop stripping the old invalid ones, that could cause an error for someone who has customized their transformer by copying the default specs.
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.
Can we emit a warning if we see an old invalid fieldspec? I imagine we'll eventually want to remove the code that handles the legacy fieldspecs
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.
We can, but another option is to improve the error message for all cases where we're given a path that leads to a non-sequence node, and allow this case to fall through to that (hopefully helpful) error message. Plus make sure to have a release note stating that we fixed a bug where certain invalid fieldspecs were being ignored in the advanced configuration of the namespace transformer. #4727 takes that approach. It includes a dep change, so is a bigger risk for the kubectl update. I suggest we should merge this one (which continues to ignore the invalid fieldspec) and then make a decision on the invalid fieldspec in the other PR.
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.
Apart from removing the unnecessary fieldspecs and a couple other minor comments, this LGTM
case namespace.SubjectModeUnspecified: | ||
p.SetRoleBindingSubjects = namespace.DefaultSubjectsOnly | ||
default: | ||
return errors.Errorf("invalid value %s for setRoleBindingSubjects", p.SetRoleBindingSubjects) |
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.
nit: suggest listing the valid values here to help users fix the issue (and quoting the values)
i.e. errors.Errorf("invalid value %q for setRoleBindingSubjects, must be one of %q or %q", p.SetRoleBindingSubjects, namespace.AllServiceAccountSubjects, namespace.DefaultSubjectsOnly)
fda85ca
to
92e86ac
Compare
92e86ac
to
0c37ee8
Compare
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: KnVerey, natasha41575 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 |
Configure consistent RBAC in all project-robbie namespaces: - project-robbie-6f75ac - project-robbie-8dd79e - project-robbie-b4784c These changes included custom configuration for the Kustomize namespace transformer so that it will update the namespace for all subjects listed in the RoleBindings. See [1] for an example configuration, and [2] for what passes for documentation. [1]: kubernetes-sigs/kustomize#629 (comment) [2]: kubernetes-sigs/kustomize#4704
Resolves #1599
Closes #4301 and #4302, which are alternative solutions to the same issue.
We can't change the default, since that would be enormously disruptive to our users. Instead, this PR proposes a new option for the transformer to enable it to behave in the desired manner. This option are exposed explicitly via the transformer's configuration resource, which can be used in the
transformers
field. While using resource-specific annotations to configure transformers is an interesting idea that may be appropriate in some cases, my opinion is that transformer-level is better granularity for these particular options. I also considered a selection-base solution as suggested here, but at that point I think folks should reach for replacements instead, now that they exist.Originally, this PR had
all
instead ofallServiceAccounts
. However, the other two documented kinds are not namespaced, so setting all of them / using fieldspecs for these will never make sense. I'm not sure from the docs whether it is possible to have auth plugins with their own bespoke kinds. If that is possible, and those kinds are namespaced, they will not be handled by this transformer.