Allow Access Operator deploy to a single Namespace or multiple Namespaces#112
Allow Access Operator deploy to a single Namespace or multiple Namespaces#112OwenCorrigan76 wants to merge 9 commits intostrimzi:mainfrom
Conversation
2f7d88d to
ba9f2cb
Compare
| Set<String> namespaces = | ||
| strimziNamespace == null ? Set.of() : | ||
| Arrays.stream(strimziNamespace.split(",")) | ||
| .map(String::trim) | ||
| .collect(Collectors.toSet()); | ||
|
|
||
| operator.register(new KafkaAccessReconciler(operator.getKubernetesClient()), | ||
| o -> o.settingNamespaces(namespaces)); |
There was a problem hiding this comment.
Will this work when we configure to watch all (or any) Namespace? That means when you configure STRIMZI_NAMESPACE to *
I think you will need in that case o.watchingAllNamespaces().
There was a problem hiding this comment.
Thanks for the comment @im-konge. That makes sense. Will implement this.
There was a problem hiding this comment.
FMPOV you should not have multiple files containing RoleBinding for each Namespace - similarly to the Cluster Operator (and what we have in docs) you can just have one and if needed, it can be created in every Namespace the operator will watch.
b74bb48 to
96bb8fb
Compare
| operator.register(new KafkaAccessReconciler(operator.getKubernetesClient())); | ||
|
|
||
| String strimziNamespace = System.getenv("STRIMZI_NAMESPACE"); | ||
| if (strimziNamespace != null && strimziNamespace.matches("\\*")) { |
There was a problem hiding this comment.
| if (strimziNamespace != null && strimziNamespace.matches("\\*")) { | |
| if (strimziNamespace != null && strimziNamespace.equals("*")) { |
I think this will be better than the regex stuff.
There was a problem hiding this comment.
Actually, as Jakub mentioned couple of times even before, this is the best thing:
| if (strimziNamespace != null && strimziNamespace.matches("\\*")) { | |
| if ("*".equals(strimziNamespace)) { |
and you don't need the null check.
| .withUseSSAToPatchPrimaryResource(false)); | ||
| operator.register(new KafkaAccessReconciler(operator.getKubernetesClient())); | ||
|
|
||
| String strimziNamespace = System.getenv("STRIMZI_NAMESPACE"); |
There was a problem hiding this comment.
I wonder if having something like this:
| String strimziNamespace = System.getenv("STRIMZI_NAMESPACE"); | |
| String strimziNamespace = System.getenv().getOrDefault("STRIMZI_NAMESPACE", "*"); |
would be better.
TBH it would be better to have some configuration class that would check everything and return configuration for the operator, but I don't think it's scope of this PR.
That way you would keep the current behavior of the operator -> in case that you didn't configure this env variable, the operator will watch all Namespaces. Otherwise it will watch the set of Namespaces configured inside the STRIMZI_NAMESPACE env variable.
There was a problem hiding this comment.
Default added.
| Set<String> namespaces = | ||
| strimziNamespace == null ? Set.of() : | ||
| Arrays.stream(strimziNamespace.split(",")) | ||
| .map(String::trim) | ||
| .collect(Collectors.toSet()); |
There was a problem hiding this comment.
So I think that this is not the correct way. What will happen when you pass the empty list of Namespaces into the settingNamespaces() method?
I would change the if-else here:
- check if the
strimziNamespaceis null or empty (thenullshouldn't happen here, but it's better to be safe) - then check if it's wildcard (you should cover also cases when you have space there - so using
trim()) - I think you should cover case when you have wildcard and Namespace there (so something like -
*,namespace-0) - then you can split it by the
, - if there is something wrong, you should throw exception and not pass there empty Set
You can check how it's done in cluster-operator: https://github.com/strimzi/strimzi-kafka-operator/blob/main/operator-common/src/main/java/io/strimzi/operator/common/config/ConfigParameterParser.java#L179-L195
There was a problem hiding this comment.
Is it better now with the latest changes?
| assertThat(currentKafkaAccess).isNotNull(); | ||
| currentKafkaAccess.getSpec().setSecretName(NEW_USER_PROVIDED_SECRET_NAME); | ||
| client.resources(KafkaAccess.class).resource(currentKafkaAccess).update(); | ||
| updated = true; |
There was a problem hiding this comment.
Wouldn't break be better than having another boolean value?
Also, if you would like to keep it, I would use different loop type - like while, which you can break and then fail inside it.
However what I saw as the cleanest solution is to use the edit:
client.resources(KafkaAccess.class).resource(currentKafkaAccess).edit(ka -> {
ka.getSpec().setSecretName(NEW_USER_PROVIDED_SECRET_NAME);
return ka;
});
or
client.resources(KafkaAccess.class).resource(currentKafkaAccess).edit(ka -> new KafkaAccessBuilder(ka)
.editOrNewSpec()
.withSecretName(NEW_USER_PROVIDED_SECRET_NAME)
.endSpec()
.build()
);
it should handle the conflict IIRC.
Signed-off-by: OwenCorrigan76 <owencorrigan76@gmail.com>
Signed-off-by: ocorriga <ocorriga@redhat.com>
Signed-off-by: ocorriga <ocorriga@redhat.com>
Signed-off-by: ocorriga <ocorriga@redhat.com>
Signed-off-by: ocorriga <ocorriga@redhat.com>
7292fef to
43dd26b
Compare
Signed-off-by: ocorriga <ocorriga@redhat.com>
43dd26b to
b2ce8a1
Compare
Signed-off-by: ocorriga <ocorriga@redhat.com>
Signed-off-by: ocorriga <ocorriga@redhat.com>
You should check what is happening in AZPs, it seems to be related to your changes. If there is nothing useful in the logs, you need to check the STs locally, debug the things. Also it doesn't fail just on AZP, but also GHA, that means there is something wrong in your changes. |
Signed-off-by: ocorriga <ocorriga@redhat.com>
scholzj
left a comment
There was a problem hiding this comment.
I think the main issue with this is that it is breaking compatibility. AFAIU, the AO was watching all namespaces by default before. So it should probably continue to do so now? Otherwise, the upgrade likely breaks it for almost everyone.
| {{- if .Values.watchAnyNamespace }} | ||
| --- | ||
| apiVersion: rbac.authorization.k8s.io/v1 | ||
| kind: ClusterRoleBinding |
There was a problem hiding this comment.
Why is the file named RoleBinding when it contains a ClusterRoleBinding?
Or at least I think that was not the intended way this should have been done. My understanding is that all it should have done was to add support for single namespace. Not switch to it. |
Yes I think I mentioned it in one of the comments, that the which (from what I saw in the documentation) works fine for single/multiple Namespaces, but doesn't work with the all Namespaces configuration and you should use I mean the code where you checked if the namespaces is just the |
|
By watching all namespaces as default, we need to bring back the ClusterRoleBinding.yaml or? |
I think it depends. When you take a look on Strimzi Cluster Operator, we have there RoleBindings (for single/multiple Namespace deployment) and ClusterRole -> in case that you want to watch all Namespaces, you are creating the ClusterRoleBindings by command - you can anyway check the documentation how it's done: https://strimzi.io/docs/operators/latest/deploying#deploying-cluster-operator-to-watch-whole-cluster-str However, if you would like to do it same way, you would have to have the change as you did with I think that during the upgrade users will anyway have the CRB already created, so we will have to mention it in the release notes for sure that there was this change. From my side, I think having it consistent across repositories is a good thing. It will just be a bit of breaking change and users will need to change the way how they are installing the operator. But I will leave others to say what they think about it. |
|
Thanks a mil @im-konge for the useful comments. Myself and @katheris discussed having compatibility with how it's done in the Cluster Operator and agreed that is was the best way to proceed. Also having the changes documented in the docs (that premature PR I opened a couple of weeks ago) but maybe others will disagree? |
I wonder if it would make sense to have documentation stuff here as we have for Bridge - and I'm sure there was some discussion in the past. But in the operators, it was premature because there could be still some changes and you don't have new release of KAO yet (and then you have to add it to operators repo). That's why I think having the documentation here would help in these cases when you have some change, you want to have it prepared and then you can just use it in case that there is new release. However, I'm not sure what were the points why it's not here. |
You agreed on what? To change the default installation mode? (I mean, I'm not really sure what exactly you agreed on) |
| Set<String> namespaces = parseNamespaces(strimziNamespace); | ||
|
|
||
| operator.register(new KafkaAccessReconciler(operator.getKubernetesClient()), | ||
| configuration -> configuration.settingNamespaces(namespaces)); |
There was a problem hiding this comment.
Does called configuration.settingNamespaces("*") really work?
There was a problem hiding this comment.
No, that's why I had previous comment(s) about adding the watchingAllNamespaces().
|
@im-konge @scholzj just to be clear on what Owen and I discussed here's my take. So today in the Access Operator by default we have a ClusterRoleBinding and the operator is watching all namespaces and is being granted access to all namespaces. However, I don't think that was something that was properly thought through and in hindsight was a mistake and as noted is different to what we have in the cluster-operator. To be more secure by default I think the Access Operator installation files should be updated so that by default it is only granted access to a single namespace, and then we should document how to expand that to a set of namespaces or all namespaces. This may cause a breaking change to users, however I think it provides a better experience both security wise and in terms of consistency, so as long as we properly document what users should do to maintain the old behaviour then I think this is acceptable. Owen and I should have been clearer about this discussion and the change in direction from the original issue so I apologise for that. I'm happy to open a separate issue to be triaged formally if you would prefer to get input from the wider set of maintainers. |
|
Thanks for clarifying @katheris |
|
@katheris Thanks for the explanation. To be honest, I disagree with it.
I wonder if we can make it more secure and more usable out of the box. For example by breaking the configuration:
Then you can, for example, have some default to pull the credentials from namespace A to namespace B that would make the purpose of the tool a bit more obvious. You would still break the compatibility. But the default would be somehow useful. And it will be more secure with a purpose. Instead of being more secure just to force everyone to reconfigure it to make it less secure and useful. If this is something we want to do ... then it is really important to think about what Lukas mentioned with the documentation. You cannot release a breaking change with the idea that the docs will be released later with the next operator release. You need to document all of it here. For example in the README.md. You should ale make sure these things are super clear in the Helm Chart README.md (which I guess should have been updated in the first place). |
|
PS: I do not want to constantly be the one breaking people's plans for Access Operator. So if you wanna do whatever you want with it, be my guest. But stop asking for my reviews 😜. |
|
@scholzj thanks, I think you do have valid points (which is why I ask for your reviews 😄 ) so we'll have a think |
By default, the Kafka Access Operator watches all namespaces. This PR allows deployment of a KafkaAccess resource in a defined namespace or namespaces, by using the Optional env
STRIMZI_NAMESPACE.For example:
This PR fixes:
#106