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

REST proxy SASL OIDC authentication #731

Merged
merged 3 commits into from
Oct 13, 2023

Conversation

matyaskuti
Copy link
Contributor

@matyaskuti matyaskuti commented Oct 4, 2023

About this change - What it does

OAuth credentials pass-through:

  • Allow passing through OAuth2 credentials to the underlying Kafka service
  • In case the incoming HTTP request's Authorization header has a Bearer token, will create Kafka clients with the OAUTHBEARER SASL mechanism and pass the token through to them
  • Basic SASL authentication behaviour is unchanged
  • Changes and the addition of the OAuth2 possibility only apply to the REST proxy

Proxy janitor extension:

  • The user proxy janitor is extended to clean up proxies with soon-to-be-expired tokens to avoid Kafka clients going into a connection retry-loop until they are cleaned up by existing janitor logic
  • Extracting the expiry time from the token doesn't include signature verification - even if the token has been tampered with, Kafka verifies the token and requests are rejected if it's invalid
  • pyjwt is used over python-jose due to its smaller footprint - any future switch (eg. due to the need to actually verify credentials and use JWK) is trivial (switch dependencies, modify imports) due to python-jose building on pyjwt and having identical interfaces for the features added now

Why this way

Preserve the current auth behaviour without duplicating the client creation, make the decision purely based on the incoming HTTP requests.

@matyaskuti matyaskuti changed the title Matyaskuti/rest proxy sasl OIDC authentication REST proxy SASL OIDC authentication Oct 4, 2023
@matyaskuti matyaskuti force-pushed the matyaskuti/rest_proxy_sasl_oidc_authentication branch 10 times, most recently from c4bd613 to f1bfc7e Compare October 5, 2023 11:57
@matyaskuti matyaskuti marked this pull request as ready for review October 5, 2023 13:27
@matyaskuti matyaskuti requested review from a team as code owners October 5, 2023 13:27
Copy link
Contributor

@jjaakola-aiven jjaakola-aiven left a comment

Choose a reason for hiding this comment

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

What happens to producer/consumer when token expires?

karapace/kafka_rest_apis/auth_utils.py Outdated Show resolved Hide resolved
karapace/kafka_rest_apis/auth_utils.py Outdated Show resolved Hide resolved
karapace/config.py Show resolved Hide resolved
Handle OAuth/OIDC (Bearer token) auth headers, and use them when
instantiating Kafka clients (with the exception of backups for now).
Basic authentication behaviour is unchanged, just extracted and
unittested.
@matyaskuti matyaskuti force-pushed the matyaskuti/rest_proxy_sasl_oidc_authentication branch from f1bfc7e to b19cf19 Compare October 6, 2023 13:17
@matyaskuti
Copy link
Contributor Author

@jjaakola-aiven

What happens to producer/consumer when token expires?

Potentially producer and consumer clients could go into a retry-loop until the idle proxy janitor cleans up the UserProxy associated with the current Bearer token.

As discussed offline, I'll modify the current idle_proxy_janitor to take into account token expiry in a "preemptive" way, cleaning up soon-to-be-expired proxies before the token actually becomes invalid.

@matyaskuti matyaskuti force-pushed the matyaskuti/rest_proxy_sasl_oidc_authentication branch 4 times, most recently from 9029b14 to b191fb0 Compare October 12, 2023 10:07
@matyaskuti matyaskuti force-pushed the matyaskuti/rest_proxy_sasl_oidc_authentication branch 2 times, most recently from 1db9235 to 662078f Compare October 12, 2023 14:06
jjaakola-aiven
jjaakola-aiven previously approved these changes Oct 13, 2023
Due to the behaviour of the Kafka clients, we want to avoid them going
into a retry loop in case of an expired OAuth token. The current proxy
janitor _would_ clean them up eventually but this is behaviour to be
avoided.

Thus the proxy janitor is extended to clean up proxies that have auth
tokens expiring within a "tolerance" amount of time.

To extract the expiry time (`exp` claim) from an OAuth token, the
`pyjwt` library is used. With this action we do not verify the token
signature (which would not be possible without knowing the signing
public key). Normally this would present the issue of tokens that have
been tampered with and not re-signed. However, when using a token for
the first time, the Karapace REST proxy instantiates a Kafka admin
client, which results in immediate verification of the token by Kafka.
So even if the expiration time has been maliciously changed, the
connection will be refused by Kafka, resulting in an Unauthorized
response from Karapace to its client.
@matyaskuti matyaskuti force-pushed the matyaskuti/rest_proxy_sasl_oidc_authentication branch from 5de666d to c350775 Compare October 13, 2023 06:58
@tvainika tvainika merged commit 018e1d2 into main Oct 13, 2023
8 checks passed
@tvainika tvainika deleted the matyaskuti/rest_proxy_sasl_oidc_authentication branch October 13, 2023 08:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants