Replies: 2 comments
-
|
Ping @roryqi , please take a look at this. |
Beta Was this translation helpful? Give feedback.
0 replies
-
|
For the target We don't need to do this target now. It depends on user requirement. If there is a user requirement, we can finish it in the future. We can finish this feature both Gravitino server and Iceberg server side. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Research Spike — Client-Side HTTPS / mTLS Authentication as a Foundation for RBAC & FGAC
Hi — Jerry asked me to look into this. I put this doc together to capture the current state and prime discussion. Let's align on the direction forward; I'm happy to own the implementation.
We need client-side mTLS / HTTPS as a foundation for Role-Based and Fine-Grained Access Control. Authorization is only as trustworthy as the identity it keys on — so establishing a strong, non-spoofable identity is the critical prerequisite for RBAC/FGAC. This spike scopes what that takes in Gravitino: where we stand, what's missing, and the key open decisions. For how TLS/mTLS actually works, see Appendix A.
1. Where we stand today
AuthenticationFilter— derives thePrincipalonly from theAuthorizationheader.1 Schemes:NONE, SIMPLE, BASIC, OAUTH, KERBEROS.2enableHttps) — shipped Dec 2023.3enableClientAuth+ truststore) — but the validated cert identity is thrown away; it never reaches the auth layer.4SimpleAuthenticatortrusts the username from a Base64 header with no validation — the default identity is trivially spoofable. This is the crux for FGAC (§4).52. Key Use Cases / Product CUJs + Status in Gravitino
"Client-side HTTPS auth" spans three escalating layers:
byte[]-onlyProduct CUJs
Decision (this spike): we are building RBAC/FGAC, so we target UC3 → layer (c). Strong, non-spoofable identity is the point (§4). Layer (b)/PR #10975 becomes a prerequisite building block, not the deliverable.
3. Mermaid Diagrams — per use case
3.1 Baseline — what works today (token over one-way HTTPS)
3.2 UC1 — mTLS transport gate, and where it breaks
3.3 UC3 — the full chain the cert must travel to drive RBAC/FGAC
4. Why We Need This — establishing identity for RBAC + FGAC
FGAC/RBAC is only as trustworthy as the identity it keys on. Today Gravitino's
SimpleAuthenticatortakes the username from a Base64 header and trusts it with no validation — anyone can claim to bealice. Building row/column masking and fine-grained privileges on top of a spoofable principal is security theater: a perfect policy engine is still bypassed by setting a header. mTLS cert-as-identity delivers a non-repudiable principal proven by possession of a private key — that is why client-cert auth is a foundation, not a feature.Open question — who does FGAC govern?
→ If FGAC is primarily service/machine identity, certs are the foundation (layer c). If human end-users, certs are a hardening layer alongside OIDC. (Open question — see §D.)
Recommended design seam
Follow the Kafka model: the cert supplies identity only; roles/privileges stay in Gravitino's RBAC store. Do not encode roles in cert OUs — that couples authz to PKI and forces cert re-issuance on every role change. Cert = who; Gravitino RBAC = what.
5. Prior Art & Related Work
5.1 Gravitino issues & PRs
All related work found in
apache/gravitino, grouped by how directly it bears on client-cert / mTLS identity. Layer refs are (a) server TLS, (b) client presents cert, (c) cert-as-identity.Core thread — client-side certificate / mTLS
tlsConfigurerso trusted clients are issued/present SSL certs and "only authorized clients can access the service." Cites iceberg#13190.TLSConfigurer+.withTlsConfigurer()on the client, wired into the HC5 connection manager; config template +TestHTTPClient.Foundation — server-side TLS (shipped)
enableHttps+ keystore, plusenableClientAuth+ truststore (setNeedClientAuth).Adjacent — authentication / identity design (context for layer c)
Authenticator/AuthenticatorTypesurface a cert authenticator (Gap 3) would extendAuthorizationheader verbatim, supporting OAuth2 Bearer + simpleBasic; adds per-request authorization + audit.Peripheral — security docs & downstream transport
gravitino.bypass.).#10975 in detail (the active implementation): contributors first concluded mTLS was already supported server-side (Jetty validates client certs) and initially submitted only tests proving that; the work was then redirected to the client side — "You need to modify the client code" — citing iceberg#13190. They added the
TLSConfigurer+.withTlsConfigurer()builder,gravitino.conf.templateentries, andTestHTTPClientcases. Delivers layer (b) / BREAK 1 (Java only); does not touch BREAK 2 / layer (c). Currently needs conflict resolution + review.5.2 External reference implementations (cert → principal → authz)
Not Gravitino work — mature designs to borrow from for layer (c).
ssl.principal.mapping.rulesCN= user,O= group(s)authentication.type=CERTIFICATEcertauth +pg_hba/ident mapsSSLContext/ TLS configurer6. Gap Analysis (code-grounded)
6.1 What already exists (do not rebuild)
enableHttps+ keystore.JettyServerConfig.java(123–167),JettyServer.java(391–425).enableClientAuth→setNeedClientAuth(true)+ truststore.JettyServerConfig.java:183,190–207;JettyServer.java:427–430.Principal— users/groups, roles, privileges on securable objects, a REST permission API, request-time authorization filters, and a pluggable authorizer (incl. an Apache Ranger plugin). It consumes whatever principal auth produces.66.2 What is missing (the real gaps)
Gap 1 — Client cannot source a cert to present in the handshake (TLS layer / BREAK 1).
A client-side config gap, not a missing server endpoint: no API to point the client at a keystore, build an
SSLContextwith aKeyManager, and hand it to the TLS stack.HTTPClient.javabuilds the HC5 client with noSSLContext(~123, conn-mgr748–761);GravitinoClientConfigurationhas no TLS keys. Pythonhttp_client.py:182usesbuild_opener()with nossl.SSLContext. → Partially addressed for Java by #10975; Python uncovered.Gap 2 — Server discards the validated cert (app layer / BREAK 2).
AuthenticationFilterreads only theAuthorizationheader (83–101) and never touches the request'sX509Certificateattribute. Repo-wide: zeroX509Certificatereferences inserver/,server-common/,core/,common/,clients/. → even withenableClientAuth=true, a request with noAuthorizationheader is rejected (401). Not addressed by #10975.Gap 3 — The
AuthenticatorSPI cannot express cert auth.AuthenticatorisauthenticateToken(byte[]) → Principalonly — no access to the request or TLS peer certs.AuthenticatorType(common/.../auth/AuthenticatorType.java:23) has noCERTIFICATE;AuthenticatorFactory:40has no mapping. → a request/peer-cert-aware auth path is required (core architectural change). Not addressed by #10975.Gap 4 — No cert → principal mapping.
Nothing maps a cert subject (
DN/CN/SAN) to a Gravitino user. Required for cert-as-identity; needs configurable rules (Kafka-style). Not addressed by #10975.Gap 5 — Weak default identity undermines FGAC.
SimpleAuthenticatortrusts the header username with no validation — why FGAC needs a strong, verifiable principal (§4).6.3 Accurate one-line status
Appendix
A. How TLS / mTLS works (reference)
One-way vs mutual. Normal HTTPS = only the server presents a cert; the client verifies it against a CA and stays anonymous at the TLS layer (what Gravitino has today). mTLS = the client also presents a cert, validated by the server — both ends identified before any HTTP flows.
Why the whole connection stays trusted. The cert is presented once, in the TLS handshake, which does two things at once: (1) authenticates the peer — the client signs part of the handshake with its private key; the server checks the cert is signed by a CA in its truststore and that the peer holds the private key (validated locally — no CA call per request); (2) derives session keys via a key exchange signed with that private key, so the keys are bound to the authenticated identity. Every later record is AEAD-encrypted with those keys, so any record that verifies provably came from the handshake peer. → identity is sticky to the connection: no token, nothing re-signed per request.
It's all the TLS layer — HTTP never sees the cert. Only two places leave pure TLS, neither HTTP-native: the server consuming the validated cert is an app-layer step (Gap 2); and the
X-SSL-Client-Subjectheader only appears in the proxy case, when TLS terminates upstream at a load balancer. (One connection = one identity — a proxy multiplexing many users over one TLS connection needs app-layer identity per request.)PKI trust material — who holds what:
keystore = "certs I present to prove myself." truststore = "the CA I trust to vouch for the other side."
B. Glossary
C. Scope of work if layer (c) is chosen
TLSConfigurer; prerequisite; extend to Python).AuthenticationFilter(Gap 2).CN/SAN → user, configurable rules (Gap 4).D. Open decisions to resolve
O=groupin cert)?Footnotes
AuthenticationFilter.doFilterreads the credential solely from theAuthorizationheader (server-common/.../authentication/AuthenticationFilter.java:83), converts it tobyte[], and derives thePrincipalonly viaauthenticator.authenticateToken(authData)(:91–95). A null principal is rejected asUnauthorizedException(:100–101). No other request state (TLS session, client cert) is consulted. ↩ ↩2The scheme set is a closed enum — exactly
NONE, SIMPLE, BASIC, OAUTH, KERBEROS— atcommon/.../auth/AuthenticatorType.java:25–37. ↩Commit
68af8d674, 2023-12-04 — "[[Improvement] Add https support for Jetty Server #41] feat(server): Add https support for Jetty server ([#41] feat(server): Add https support for Jetty server #860)" (#41 / PR #860).enableHttpsatJettyServerConfig.java:123plus keystore keys. ↩enableClientAuth(JettyServerConfig.java:183) + truststore keys (:190–207), loaded only whenenableHttps && enableClientAuth(:400–402);JettyServer.java:427callssslContextFactory.setNeedClientAuth(true)withsetTrustStore*(:428–430) — so Jetty validates the client cert at the handshake. But a repo-wide search finds zeroX509Certificatereferences in non-testserver/ server-common/ core/ common/ clients/, andAuthenticationFilternever reads the cert (see 1) — the validated identity is discarded. (Introduced in the same 2023 commit as HTTPS.) ↩SimpleAuthenticator's own class javadoc: "SimpleAuthenticator will use the identifier provided by the user without any validation" (server-common/.../authentication/SimpleAuthenticator.java:32–34); it Base64-decodes the Basic header and returnsnew UserPrincipal(userInformation[0], authData)(:66) with no credential check. ↩Gravitino already ships an RBAC subsystem: a model of users, groups, roles, and privileges on securable objects (
api/.../authorization/—Role,Privilege/Privilegesincl.USE_CATALOG,CREATE_TABLE,MODIFY_TABLE,SELECT_TABLE;SecurableObject,User,Group); core managers (core/.../authorization/AccessControlManager.java,PermissionManager.java,UserGroupManager.java); a REST permission API (server/.../web/rest/PermissionOperations.java); request-time authorization filters (server/.../web/filter/authorization/*Executor.java); and a pluggable authorizer with an Apache Ranger plugin (authorizations/authorization-ranger/). Authorization keys on the authenticated principal viaPrincipalUtils.getCurrentPrincipal()— the exact input cert-as-identity would supply. ↩Beta Was this translation helpful? Give feedback.
All reactions