kafbat / kafka-ui

Open-Source Web UI for managing Apache Kafka clusters
http://ui.docs.kafbat.io
Apache License 2.0
510 stars 51 forks source link

RBAC: 403 when viewing audit topic messages #266

Closed chris7532 closed 5 months ago

chris7532 commented 5 months ago

Issue submitter TODO list

Describe the bug (actual behavior)

  1. There's error popping up in the browser console about Google OAuth and the manifest.json is being blocked by CORS. It seems like it doesn't really mess things up too much. But, there's this weird thing where, after I log in to Google successfully, it doesn't redirect me like it should. I end up stuck on the login page and have to hit the login button myself to actually get in. It only happens once, though.
  2. Main bug: When I view the page of audit topic's message, I got the toastrs : 403 and something went wrong and it will keep fetching the topic api continuously until I close the tab.

This figure can describe the above two bugs, 2024-04-03_6 22 47

Expected behavior

  1. It should not have such error message, it may have other potential issue that I didn't find yet.
  2. It should be available when user view the message page of the audit topic.

Your installation details

  1. 2956664
  2. v1.0.0
  3. Use AWS EKS to deploy and the ingress is alb, and this is how I set the ingress:

    # Annotations for the Ingress
    annotations: 
    alb.ingress.kubernetes.io/backend-protocol: HTTP
    alb.ingress.kubernetes.io/certificate-arn: >-
      {{ .Values.aws.certificateManager }}
    alb.ingress.kubernetes.io/healthcheck-path: /actuator/health
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80},{"HTTPS":443}]'
    alb.ingress.kubernetes.io/group.name: {{ .Values.envPhase }}-http
    alb.ingress.kubernetes.io/load-balancer-name: {{ .Values.envPhase }}-http
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-Ext2-2021-06
    alb.ingress.kubernetes.io/subnets: {{ join "," .Values.aws.albSubnets }}
    alb.ingress.kubernetes.io/inbound-cidrs: "{{ join "," .Values.aws.albInboundCidrs }}"
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/ssl-redirect: '443'

    for kafka config:

    kafka:
    {{ range .Values.yamlApplicationConfig.kafka.clusters }}
    clusters:
    - name: {{ .name }}
      bootstrapServers: {{ .bootstrapServers }}
      audit:
        topic-audit-enabled: true
        console-audit-enabled: true
        topic: "kui-audit-log" # default name
        audit-topic-properties:
          retention.ms: 43200000
        audit-topics-partitions: 1
        level: ALTER_ONLY # either ALL or ALTER_ONLY (default). ALL will log all read operations.
    {{- end }}
    spring:
    security:
      oauth2:
    rbac:
    roles:
      - name: "admin_sre"
        {{- with index .Values.yamlApplicationConfig.kafka.clusters 0 }}
        clusters: 
          - {{ .name | quote }}
        {{- end }}
        subjects:
          - provider: oauth_google
            type: user
            value: "xxx@xxx.com"
    
        permissions:         
        - resource: audit
          actions: [ view ]
    
        - resource: applicationconfig
          actions: all
    
        - resource: clusterconfig
          actions: all
    
        - resource: topic
          value: ".*"
          actions: all 
    
        - resource: consumer
          value: ".*"
          actions: all
    
        - resource: schema
          value: ".*"
          actions: all
    
        - resource: connect
          value: ".*"
          actions: all
    
        - resource: ksql
          actions: all
    
        - resource: acl
          actions: [ view ]
    auth:
    type: OAUTH2
    oauth2:
      client:
        google:
          clientId: "{{ .Values.yamlApplicationConfig.auth.oauth2.client.google.clientId }}"
          clientSecret: "{{ .Values.yamlApplicationConfig.auth.oauth2.client.google.clientSecret }}"
          provider: google
          user-name-attribute: email
          custom-params:
            type: google
            allowDomain: "xxx.com"

Steps to reproduce

  1. Set Google OAuth for RBAC
  2. Set auditTopic config
  3. Use any deploy method, for my case : HELM
  4. Go to the message page of the audit topic

Screenshots

No response

Logs

pod log:

2024-04-03 17:35:22,579 ERROR [reactor-http-epoll-3] o.s.b.a.w.r.e.AbstractErrorWebExceptionHandler: [cb883a0f-9826] 500 Server Error for HTTP GET "/api/clusters/bf-shared-test-msk-001/topics/kui-audit-log/messages/v2?limit=100&mode=" java.lang.NullPointerException: null at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:903) Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Error has been observed at the following site(s): __checkpoint ⇢ io.kafbat.ui.config.CorsGlobalConfiguration$$Lambda$1244/0x00007fc751733e48 [DefaultWebFilterChain] checkpoint ⇢ io.kafbat.ui.config.CustomWebFilter [DefaultWebFilterChain] *checkpoint ⇢ io.kafbat.ui.config.ReadOnlyModeFilter [DefaultWebFilterChain] __checkpoint ⇢ AuthorizationWebFilter [DefaultWebFilterChain] checkpoint ⇢ ExceptionTranslationWebFilter [DefaultWebFilterChain] *checkpoint ⇢ LogoutWebFilter [DefaultWebFilterChain] __checkpoint ⇢ ServerRequestCacheWebFilter [DefaultWebFilterChain] checkpoint ⇢ SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain] *checkpoint ⇢ LogoutPageGeneratingWebFilter [DefaultWebFilterChain] __checkpoint ⇢ LoginPageGeneratingWebFilter [DefaultWebFilterChain] checkpoint ⇢ OAuth2LoginAuthenticationWebFilter [DefaultWebFilterChain] *checkpoint ⇢ OAuth2AuthorizationRequestRedirectWebFilter [DefaultWebFilterChain] __checkpoint ⇢ ReactorContextWebFilter [DefaultWebFilterChain] checkpoint ⇢ HttpHeaderWriterWebFilter [DefaultWebFilterChain] *checkpoint ⇢ ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain] __checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain] checkpoint ⇢ org.springframework.web.filter.reactive.ServerHttpObservationFilter [DefaultWebFilterChain] *checkpoint ⇢ HTTP GET "/api/clusters/bf-shared-test-msk-001/topics/kui-audit-log/messages/v2?limit=100&mode=" [ExceptionHandlingWebHandler] Original Stack Trace: at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:903) at io.kafbat.ui.controller.MessagesController.getTopicMessagesV2(MessagesController.java:124) at jdk.internal.reflect.GeneratedMethodAccessor48.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:141) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:751) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) at io.kafbat.ui.controller.MessagesController$$SpringCGLIB$$0.getTopicMessagesV2() at jdk.internal.reflect.GeneratedMethodAccessor48.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.springframework.web.reactive.result.method.InvocableHandlerMethod.lambda$invoke$0(InvocableHandlerMethod.java:145) at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:132) at reactor.core.publisher.MonoZip$ZipCoordinator.signal(MonoZip.java:293) at reactor.core.publisher.MonoZip$ZipInner.onNext(MonoZip.java:474) at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180) at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545) at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.request(MonoPeekTerminal.java:139) at reactor.core.publisher.MonoZip$ZipInner.onSubscribe(MonoZip.java:466) at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onSubscribe(MonoPeekTerminal.java:152) at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55) at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) at reactor.core.publisher.MonoZip$ZipCoordinator.request(MonoZip.java:216) at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194) at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onSubscribe(MonoIgnoreThen.java:134) at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117) at reactor.core.publisher.MonoZip.subscribe(MonoZip.java:125) at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:240) at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:203) at reactor.core.publisher.MonoFlatMap$FlatMapMain.onComplete(MonoFlatMap.java:189) at reactor.core.publisher.Operators.complete(Operators.java:137) at reactor.core.publisher.MonoZip.subscribe(MonoZip.java:121) at reactor.core.publisher.Mono.subscribe(Mono.java:4495) at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263) at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74) at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.innerNext(FluxConcatMapNoPrefetch.java:258) at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:863) at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180) at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545) at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.request(MonoPeekTerminal.java:139) at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171) at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2305) at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.request(FluxConcatMapNoPrefetch.java:338) at reactor.core.publisher.MonoNext$NextSubscriber.request(MonoNext.java:108) at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2341) at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2215) at reactor.core.publisher.MonoNext$NextSubscriber.onSubscribe(MonoNext.java:70) at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onSubscribe(FluxConcatMapNoPrefetch.java:164) at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:201) at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:83) at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55) at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) at reactor.core.publisher.Mono.subscribe(Mono.java:4495)

Additional context

No response

github-actions[bot] commented 5 months ago

Hello there chris7532! 👋

Thank you and congratulations 🎉 for opening your very first issue in this project! 💖

In case you want to claim this issue, please comment down below! We will try to get back to you as soon as we can. 👀