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

Fully support generation of K8s RBAC resources #31797

Merged
merged 1 commit into from
Mar 21, 2023
Merged

Conversation

Sgitario
Copy link
Contributor

These changes address a long-time issue regarding K8s RBAC resources (see related issues).

These changes allow generating the Roles, ClusterRoles, ServiceAccount, and RoleBindings resources. Plus, it will enable the Kubernetes Client and Kubernetes Config extensions to configure the role binding to generate.

Fix #16612
Fix #19286
Fix #15422

@github-actions
Copy link

github-actions bot commented Mar 13, 2023

🙈 The PR is closed and the preview is expired.

@iocanel
Copy link
Contributor

iocanel commented Mar 13, 2023

There was an old abandoned pull request: #21595 that was related this.
With a quick glance the PR seems to be aligned with the views expressed while reviewing that pr and that is a good sign 😄

I will come back with a detailed review later today.

@quarkus-bot

This comment has been minimized.

@iocanel
Copy link
Contributor

iocanel commented Mar 13, 2023

The configuration feels more verbose than it needs to.

To deal with the listed issues all we have to do is allow customization of the actual permission the application has.

  • We don't need to support multiple service accounts, as the application can't have more than one.
  • We don't need to bind users to roles, as it's not in our scope.
  • We don't need support multiple namespaces
    and so on.

So what do we need?

  • A way to tell what verbs are allowed per group of resources and if this relationship has cluster wide effect or not.
  • A way to specify existing roles that would be bound to the application.

Note: I don't intend to veto those changes, as it is a step forward over what we have and honestly last time I did in #21595 resulted in 18 months of doing nothing, but I am leaving this comment just to express my view.

@Sgitario
Copy link
Contributor Author

The configuration feels more verbose than it needs to.

To deal with the listed issues all we have to do is allow customization of the actual permission the application has.

  • We don't need to support multiple service accounts, as the application can't have more than one.
  • We don't need to bind users to roles, as it's not in our scope.
  • We don't need support multiple namespaces
    and so on.

So what do we need?

  • A way to tell what verbs are allowed per group of resources and if this relationship has cluster wide effect or not.
  • A way to specify existing roles that would be bound to the application.

Note: I don't intend to veto those changes, as it is a step forward over what we have and honestly last time I did in #21595 resulted in 18 months of doing nothing, but I am leaving this comment just to express my view.

Probably, it's more verbose than it needs to be, but it also gives much more freedom to generate complex RBAC resources (for example: for operator generation). So, it's up to the user to generate as many resources as they desire.

@Sgitario
Copy link
Contributor Author

@iocanel are you ok with the changes part of this pull request as they are? I don't think we lose anything if we allow users generating as many RBAC resources as they need.

@iocanel
Copy link
Contributor

iocanel commented Mar 14, 2023

@iocanel are you ok with the changes part of this pull request as they are? I don't think we lose anything if we allow users generating as many RBAC resources as they need.

We do loose simplicity and ease of use.

Anyway, this is clearly an improvement over what we have so yeah I am ok with it.

Copy link
Contributor

@iocanel iocanel left a comment

Choose a reason for hiding this comment

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

This needs to be documented.

@Sgitario
Copy link
Contributor Author

This needs to be documented.

+1

@Sgitario
Copy link
Contributor Author

PR updated with updates on the documentation.

@quarkus-bot

This comment has been minimized.

Copy link
Contributor

@iocanel iocanel left a comment

Choose a reason for hiding this comment

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

The implementation overall looks good with some minor improvements that have been marked on the documentation. These are changes I'd like us to introduce to make things slightly less verbose (but without altering the nature of the pull request).

Also added some change requests on the structure of documentation, so that it's less intimidating and easier to digest.

docs/src/main/asciidoc/deploying-to-kubernetes.adoc Outdated Show resolved Hide resolved
docs/src/main/asciidoc/deploying-to-kubernetes.adoc Outdated Show resolved Hide resolved
quarkus.kubernetes.rbac.role-bindings.my-role-binding.cluster-wide=false

# Use the service account "my-service-account" in the application
quarkus.kubernetes.service-account=my-service-account <3>
Copy link
Contributor

Choose a reason for hiding this comment

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

I am wondering if this could be inferred.

We could possibly generated namespace when a namespace has been defined for the deployment or is referred by the rules.

The only challenge is what happens, if we want to refer to an externally created ServiceAccount. However, this is not our job and on top of that what we generate should be standalone.

TLDR: This should be optional.

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 would actually avoid the "inferred" configuration, so it should be up to the user to use one service account or another.

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 always use the application service account, unless explicitly specified.
There is absolutely no reason specifying 2 full lines of configuration for something that should be the application service account for most of the cases.

docs/src/main/asciidoc/deploying-to-kubernetes.adoc Outdated Show resolved Hide resolved
@Sgitario
Copy link
Contributor Author

@iocanel I've updated the changes you suggested and making fully optional to configure the role binding:

  • if one role is set, it will generate the role binding using the default service account

Also, I've created a logic that detects the cluster-wide flag when configuring the role binding.

Please, have another round to review again the changes.

@Sgitario Sgitario force-pushed the 19286 branch 2 times, most recently from 01ba465 to e253425 Compare March 15, 2023 15:09
@quarkus-bot

This comment has been minimized.

@Sgitario
Copy link
Contributor Author

@iocanel PR updated with:

  • Removed RBAC configuration from the Kubernetes Client extension. Now, the role binding will be only generated if and only if the user didn't provide any and the quarkus.kubernetes-client.generate-rbac is true (note that this is a breaking change, so I will note it in the migration guide after merging this pull request).

@iocanel
Copy link
Contributor

iocanel commented Mar 16, 2023

  • Now, the role binding will be only generated if and only if the user didn't provide any and the quarkus.kubernetes-client.generate-rbac is true (note that this is a breaking change, so I will note it in the migration guide after merging this pull request).

Why do we have this change?

edit: I mean why do we change the behavior of quarkus.kubernetes-client.generate-rbac?

@Sgitario
Copy link
Contributor Author

  • Now, the role binding will be only generated if and only if the user didn't provide any and the quarkus.kubernetes-client.generate-rbac is true (note that this is a breaking change, so I will note it in the migration guide after merging this pull request).

Why do we have this change?

edit: I mean why do we change the behavior of quarkus.kubernetes-client.generate-rbac?

The behavior change is that regardless of the value in quarkus.kubernetes-client.generate-rbac, the role binding with role "view" won't be generated if users provide their own role-binding from config (this config is new, so it should not be a problem).

However, when using the extension quarkus-kubernetes-config, this is also adding a role binding "view-secrets" (this is the default name), so in this scenario, the role binding from the kubernetes client won't be generated. (See the Kubernetes config tests that I had to modify). Note that we can change this if you think this is not correct).

@iocanel
Copy link
Contributor

iocanel commented Mar 16, 2023

The behavior change is that regardless of the value in quarkus.kubernetes-client.generate-rbac, the role binding with role "view" won't be generated if users provide their own role-binding from config.

This is something I totally agree!

@iocanel
Copy link
Contributor

iocanel commented Mar 16, 2023

However, when using the extension quarkus-kubernetes-config, this is also adding a role binding "view-secrets" (this is the default name), so in this scenario, the role binding from the kubernetes client won't be generated. (See the Kubernetes config tests that I had to modify). Note that we can change this if you think this is not correct).

I would approach it the other way around given that the kubernetes-client default rbac setup is less restrictive.

So, here's how I think that it should work:

  • kubernetes-client with no custom rbac config: generate the rbac we do today
  • kubernetes-client with custom rbac config or resources: generate what has been configured (no addtional things for kubernetes-client).
  • kubernetes-client with kubernetes-config: Generate the kubernetes-client staff (as if kubernetes-config was not even there).
  • kubenretes-client with kubenretes-config and custom rbac config: generate what has been configured (no addtional things for kubernetes-client or kubenretes-config).
  • kubernetes-config with no rbac: generate the rbac we do today (for kubernetes-config)
  • kubenretes-client with rbac config: generate what has been configured (no addtional things for kubenretes-config).

@Sgitario
Copy link
Contributor Author

PR updated again by avoiding the breaking change between kubernetes-config and kubernetes-client extensions, this will keep working as before.

The only think to note in the migration guide is:

The behavior change is that regardless of the value in quarkus.kubernetes-client.generate-rbac, the role binding with role "view" won't be generated if users provide their own role-binding from config.

@Sgitario Sgitario force-pushed the 19286 branch 2 times, most recently from fa406aa to adc7c1d Compare March 17, 2023 10:56
Copy link
Contributor

@iocanel iocanel left a comment

Choose a reason for hiding this comment

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

lgtm

@quarkus-bot

This comment has been minimized.

@quarkus-bot

This comment has been minimized.

These changes address a long-time issue in regards of K8s RBAC resources (see related issues).

These changes allow to generate custom Roles, ClusterRoles, ServiceAccount, and RoleBindings.
Plus, it allows the Kubernetes Client and Kubernetes Config extensions to configure the role binding to generate.

Fix quarkusio#16612
Fix quarkusio#19286
Fix quarkusio#15422
@Sgitario Sgitario added the triage/waiting-for-ci Ready to merge when CI successfully finishes label Mar 21, 2023
@quarkus-bot
Copy link

quarkus-bot bot commented Mar 21, 2023

Failing Jobs - Building ea9425b

Status Name Step Failures Logs Raw logs
JVM Tests - JDK 11 Build Failures Logs Raw logs
✔️ JVM Tests - JDK 17
✔️ JVM Tests - JDK 19

Full information is available in the Build summary check run.

Failures

⚙️ JVM Tests - JDK 11 #

- Failing: integration-tests/opentelemetry-jdbc-instrumentation 

📦 integration-tests/opentelemetry-jdbc-instrumentation

io.quarkus.it.opentelemetry.OracleOpenTelemetryJdbcInstrumentationTest.testOracleQueryTraced line 14 - More details - Source on GitHub

org.opentest4j.AssertionFailedError: JDBC insert statement was not traced. ==> expected: <true> but was: <false>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)

@Sgitario
Copy link
Contributor Author

The failure is unrelated. Merging.

@Sgitario Sgitario merged commit 187ca4b into quarkusio:main Mar 21, 2023
@Sgitario Sgitario deleted the 19286 branch March 21, 2023 11:38
@quarkus-bot quarkus-bot bot added kind/bugfix kind/enhancement New feature or request and removed triage/waiting-for-ci Ready to merge when CI successfully finishes labels Mar 21, 2023
@quarkus-bot quarkus-bot bot added this to the 3.0 - main milestone Mar 21, 2023
@zZHorizonZz
Copy link

zZHorizonZz commented Apr 5, 2023

I'm currently experimenting with cluster role generation through the .properties config but, I can't get my head around how to specify the core API group for the cluster role. Because if I just left it blank the API group fields don't get generated at all and I get this:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: conductor-role
rules:
    resources:
      - pods
      - namespaces
    verbs:
      - get
      - watch
      - list
      - create
      - update
      - patch
      - delete

If I specify this '' as per official K8s documentation I get this:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: conductor-role
rules:
  - apiGroups:
      - ''''''
    resources:
      - pods
      - namespaces
    verbs:
      - get
      - watch
      - list
      - create
      - update
      - patch

And if I try "" then I get this:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: conductor-role
rules:
  - apiGroups:
      - '""'
    resources:
      - pods
      - namespaces
    verbs:
      - get
      - watch
      - list
      - create
      - update
      - patch

I also tried just not specifying it at all but that resulted (Same error occurs for example 1 as well) in k8s error:

ClusterRole.rbac.authorization.k8s.io "test-role" is invalid: rules[0].apiGroups: Required value: resource rules must supply at least one api group

@Sgitario
Copy link
Contributor Author

I'm currently experimenting with cluster role generation through the .properties config but, I can't get my head around how to specify the core API group for the cluster role. Because if I just left it blank the API group fields don't get generated at all and I get this:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: conductor-role
rules:
    resources:
      - pods
      - namespaces
    verbs:
      - get
      - watch
      - list
      - create
      - update
      - patch
      - delete

If I specify this '' as per official K8s documentation I get this:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: conductor-role
rules:
  - apiGroups:
      - ''''''
    resources:
      - pods
      - namespaces
    verbs:
      - get
      - watch
      - list
      - create
      - update
      - patch

And if I try "" then I get this:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: conductor-role
rules:
  - apiGroups:
      - '""'
    resources:
      - pods
      - namespaces
    verbs:
      - get
      - watch
      - list
      - create
      - update
      - patch

I also tried just not specifying it at all but that resulted (Same error occurs for example 1 as well) in k8s error:

ClusterRole.rbac.authorization.k8s.io "test-role" is invalid: rules[0].apiGroups: Required value: resource rules must supply at least one api group

Thanks for spotting. This is indeed an issue. I've reported it in #32519.

@zZHorizonZz
Copy link

zZHorizonZz commented Apr 11, 2023

I'm currently experimenting with cluster role generation through the .properties config but, I can't get my head around how to specify the core API group for the cluster role. Because if I just left it blank the API group fields don't get generated at all and I get this:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: conductor-role
rules:
    resources:
      - pods
      - namespaces
    verbs:
      - get
      - watch
      - list
      - create
      - update
      - patch
      - delete

If I specify this '' as per official K8s documentation I get this:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: conductor-role
rules:
  - apiGroups:
      - ''''''
    resources:
      - pods
      - namespaces
    verbs:
      - get
      - watch
      - list
      - create
      - update
      - patch

And if I try "" then I get this:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: conductor-role
rules:
  - apiGroups:
      - '""'
    resources:
      - pods
      - namespaces
    verbs:
      - get
      - watch
      - list
      - create
      - update
      - patch

I also tried just not specifying it at all but that resulted (Same error occurs for example 1 as well) in k8s error:

ClusterRole.rbac.authorization.k8s.io "test-role" is invalid: rules[0].apiGroups: Required value: resource rules must supply at least one api group

Thanks for spotting. This is indeed an issue. I've reported it in #32519.

Also, I have noticed something which I don't know if it's intended or not but I have been testing cluster role generation in kubernetes config it generated RoleBinging instead of ClusterRoleBinding, and because of that when I was using the k8s client it didn't seem like I had the role bound because I didn't have access to resources which I should have if that role was assigned.

Edit: After reading k8s documentation I came to the conclusion that this isn't probably a bug. Since you can bind via RoleBinging but it will make that role available for that specific namespace. But since I have been trying to create a new namespace that probably counts as accessing a new namespace so RoleBinging doesn't cover that.
But it would be nice to have a probably similar system to that of ClusterRole which would determine if it should generate ClusterRoleBinding or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment