{"id":51108383,"url":"https://github.com/pneff93/cfk-clients-oauth","last_synced_at":"2026-06-24T15:31:58.867Z","repository":{"id":242670824,"uuid":"809898337","full_name":"pneff93/cfk-clients-oauth","owner":"pneff93","description":"Repository for OAuth client authentication in Confluent for Kubernetes on Azure Kubernetes Service","archived":false,"fork":false,"pushed_at":"2024-08-19T13:40:47.000Z","size":51363,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-08-19T19:58:51.775Z","etag":null,"topics":["azure-kubernetes-service","confluent-for-kubernetes","kafka","oauth2","oidc"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pneff93.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-03T16:57:15.000Z","updated_at":"2024-08-19T13:40:50.000Z","dependencies_parsed_at":"2024-06-04T11:12:31.405Z","dependency_job_id":null,"html_url":"https://github.com/pneff93/cfk-clients-oauth","commit_stats":null,"previous_names":["pneff93/cfk-aks"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pneff93/cfk-clients-oauth","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pneff93%2Fcfk-clients-oauth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pneff93%2Fcfk-clients-oauth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pneff93%2Fcfk-clients-oauth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pneff93%2Fcfk-clients-oauth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pneff93","download_url":"https://codeload.github.com/pneff93/cfk-clients-oauth/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pneff93%2Fcfk-clients-oauth/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34739426,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-24T02:00:07.484Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azure-kubernetes-service","confluent-for-kubernetes","kafka","oauth2","oidc"],"created_at":"2026-06-24T15:31:58.801Z","updated_at":"2026-06-24T15:31:58.858Z","avatar_url":"https://github.com/pneff93.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OAuth for CFK with Azure\n\n[Confluent Platform 7.7](https://docs.confluent.io/platform/current/release-notes/index.html) and [CFK 2.9.0](https://docs.confluent.io/operator/current/release-notes.html) released OAuth support.\nThis repository sets up a basic CP cluster via CFK running on Azure Kubernetes Service (AKS) enforcing\nexternal clients to use OAuth for authentication with Azure AD (Entra ID) as the identity provider.\n\nIn technical detail it deploys:\n* 1 KraftController\n* 3 Kafka brokers\n* 1 Producer application (client)\n* 1 Control Center\n\nGeneral resources:\n* [Quickstart: Deploy an Azure Kubernetes Service (AKS) cluster using Azure portal](https://learn.microsoft.com/en-us/azure/aks/learn/quick-kubernetes-deploy-portal?tabs=azure-cli)\n* [Confluent for Kubernetes Quick Start](https://docs.confluent.io/operator/current/co-quickstart.html)\n* [CP OAuth documentation](https://docs.confluent.io/platform/current/security/authentication/sasl/oauthbearer/overview.html#sasl-oauthbearer-authentication-overview)\n\n\u003e [!NOTE]\n\u003e This repositry only focusses on Confluent Platform, not Confluent Cloud.\n\u003e For an example for OAuth with Confluent Cloud check out [https://github.com/pneff93/ccloud-clients-oauth](https://github.com/pneff93/ccloud-clients-oauth).\n\n\n## Azure AD endpoints\n\nFor the later configuration we need to set the `token_endpoint`, the `jwks_uri`, and the `issuer`.\nWe can obtain all information via\n\n```shell\ncurl https://login.microsoftonline.com/\u003ctenant-id\u003e/v2.0/.well-known/openid-configuration | jq\n```\n\nGenerally, those are\n```\ntoken_endpoint = https://login.microsoftonline.com/\u003ctenant-id\u003e/oauth2/v2.0/token\njwks_uri = https://login.microsoftonline.com/\u003ctenant-id\u003e/discovery/v2.0/keys\nissuer = https://login.microsoftonline.com/\u003ctenant-id\u003e/v2.0\n```\n\n## Azure AD applications\n\nTo retrieve the JWT token, CP is using the client credentials grant flow. So, we need to register an application in Azure AD\nand create a secret. \nWe can get a JWT token via: \n```\ncurl -X POST -H \"Content-Type: application/x-www-form-urlencoded\" \\\n-d 'client_id=[client_id]\u0026client_secret=[client_secret value]\u0026grant_type=client_credentials' \\\nhttps://login.microsoftonline.com/[tenant_id]/oauth2/token\n```\n\n\u003e [!NOTE]\n\u003e In this example, we only register one application in Azure AD. Consider different applications with its secret per CP component\n\u003e and client.\n\n\n\n## CFK cluster\n\n* [CFK server-side OAuth/OIDC authentication](https://docs.confluent.io/operator/current/co-authenticate-kafka.html#server-side-oauth-oidc-authentication-for-ak-and-kraft)\n\nStore the clientId and secret in a file and deploy it as a k8s secret. \n```shell\nkubectl create -n confluent secret generic oauth-jass --from-file=oauth.txt=client-credentials.txt\n```\n\nAfterwards, we configure the Kafka CR\n```yaml\nlisteners:\n  external:\n    authentication:\n      type: oauth\n      jaasConfig:\n        secretRef: oauth-jass\n      oauthSettings:\n        groupsClaimName: groups\n        subClaimName: sub\n        audience: \u003cclient-id\u003e\n        expectedIssuer: see above\n        jwksEndpointUri: see above\n        tokenEndpointUri: see above\nconfigOverrides:\n  server:\n    - listener.name.external.oauthbearer.sasl.server.callback.handler.class=org.apache.kafka.common.security.oauthbearer.secured.OAuthBearerValidatorCallbackHandler\n    - listener.name.external.oauthbearer.sasl.jaas.config=org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required;\n```\n\nOnce the `confluent-operator` is running, we deploy the cluster with \n\n```\nkubectl apply -f ./cluster.yaml -n confluent\n```\n\n\n## Producer Application\n\nWe develop a simple producer application producing events in a for loop.\nWe set the configuration to:\n\n```kotlin\nsettings.setProperty(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, \"SASL_PLAINTEXT\")\nsettings.setProperty(SaslConfigs.SASL_MECHANISM, \"OAUTHBEARER\")\nsettings.setProperty(SaslConfigs.SASL_LOGIN_CONNECT_TIMEOUT_MS, \"15000\")\nsettings.setProperty(SaslConfigs.SASL_OAUTHBEARER_TOKEN_ENDPOINT_URL, \"https://login.microsoftonline.com/\u003ctenant-id\u003e/oauth2/v2.0/token\")\nsettings.setProperty(SaslConfigs.SASL_LOGIN_CALLBACK_HANDLER_CLASS, \"org.apache.kafka.common.security.oauthbearer.secured.OAuthBearerLoginCallbackHandler\")\nsettings.setProperty(SaslConfigs.SASL_JAAS_CONFIG, \"org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required clientId='\u003cclient-id\u003e' clientSecret='\u003cclient-secret' scope='\u003cAzure client id of the broker application\u003e/.default';\")\n```\nNote, that we need to add the scope to the `sasl.jaas.config` which is `\u003cAzure client id of the broker application\u003e/.default`.\n\n\n### Azure Container Registry\n\n* [Quickstart: Create an Azure container registry using the Azure portal](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-get-started-portal?tabs=azure-cli)\n\nTo deploy the Producer application in the AKS cluster, we need to build and push an image to the Azure Container Registry (ACR) and integrate\nit with the AKS cluster.\n\n\n```\n# Login to Container Registry\naz login\naz acr login --name \u003cacr-name\u003e\n\n# Attach Container Registry to AKS cluster\naz aks update --name \u003caks-name\u003e --resource-group \u003crg-group\u003e --attach-acr \u003caks-name\u003e\n\n# Check if the attachment was successful\naz aks check-acr --resource-group \u003crg-group\u003e --name \u003caks-name\u003e --acr \u003caks-name\u003e.azurecr.io\n```\n\n### Deploy Producer application\n\nWe build the image via\n```\n# Build fatJar \n./gradlew fatJar\n\n# Build image (fatJar needs to be located in main folder)\ndocker build -t kafkaproducer .\n\n# Tag the built image\ndocker tag kafkaproducer \u003caks-name\u003e.azurecr.io/kafkaproducer:0.1.0\n\n# Push the image to the registry via \ndocker push \u003caks-name\u003e.azurecr.io/kafkaproducer:0.1.0\n```\n\n![](./images/containerregistry.png)\n\n\nDeploy the Kafka Producer via\n```\nkubectl apply -f ./KafkaProducer/Deployment.yaml -n confluent\n```\n\nIf everything runs successfully we should obtain similar logs\n\n```\n16:44:18.015 [Thread-0] INFO  org.apache.kafka.common.security.oauthbearer.internals.expiring.ExpiringCredentialRefreshingLogin - Successfully logged in.\n16:44:18.042 [kafka-expiring-relogin-thread-4113761a-d187-402f-a48a-8ae0e86f78dd] INFO  org.apache.kafka.common.security.oauthbearer.internals.expiring.ExpiringCredentialRefreshingLogin - [Principal=:4113761a-d187-402f-a48a-8ae0e86f78dd]: Expiring credential re-login thread started.\n16:44:18.042 [kafka-expiring-relogin-thread-4113761a-d187-402f-a48a-8ae0e86f78dd] INFO  org.apache.kafka.common.security.oauthbearer.internals.expiring.ExpiringCredentialRefreshingLogin - [Principal=4113761a-d187-402f-a48a-8ae0e86f78dd]: Expiring credential valid from 2024-08-18T16:39:17.000+0000 to 2024-08-18T17:44:17.000+0000\n16:44:18.042 [kafka-expiring-relogin-thread-4113761a-d187-402f-a48a-8ae0e86f78dd] INFO  org.apache.kafka.common.security.oauthbearer.internals.expiring.ExpiringCredentialRefreshingLogin - [Principal=:4113761a-d187-402f-a48a-8ae0e86f78dd]: Expiring credential re-login sleeping until: 2024-08-18T17:34:15.583+0000\n16:44:18.066 [Thread-0] INFO  org.apache.kafka.common.utils.AppInfoParser - Kafka version: 3.7.0\n16:44:18.067 [Thread-0] INFO  org.apache.kafka.common.utils.AppInfoParser - Kafka commitId: 2ae524ed625438c5\n16:44:18.067 [Thread-0] INFO  org.apache.kafka.common.utils.AppInfoParser - Kafka startTimeMs: 1723999458064\n16:44:18.326 [kafka-producer-network-thread | producer-1] INFO  org.apache.kafka.clients.Metadata - [Producer clientId=producer-1] Cluster ID: 3b658def-2b27-4765-b0a\n16:44:18.440 [kafka-producer-network-thread | producer-1] INFO  org.apache.kafka.clients.producer.internals.TransactionManager - [Producer clientId=producer-1] ProducerId set to 3000 with epoch 0\n16:44:28.071 [Thread-0] INFO  KafkaProducer - Kafka Producer started\n16:44:28.115 [kafka-producer-network-thread | producer-1] INFO  KafkaProducer - event produced to test-topic\n```\n\n## Control Center\n\n* [CFK client-side OAuth/OIDC authentication](https://docs.confluent.io/operator/current/co-authenticate-kafka.html#client-side-oauth-oidc-authentication-for-ak-and-kraft)\n\nFinally, we would like to see the produced events also in C3.\nWe need to add OAuth configurations as well to authenticate to the Kafka brokers.\n\n```yaml\ndependencies:\n  kafka:\n    bootstrapEndpoint: broker.confluent.svc.cluster.local:9092\n    authentication:\n      type: oauth\n      jaasConfig:\n        secretRef: oauth-jass\n      oauthSettings:\n        tokenEndpointUri: see above\n        scope: \u003cAzure client id of the broker application\u003e/.default\u003e\n```\n\n```\n# Update cluster\nkubectl apply -f ./cluster.yaml -n confluent\n\n# Port forward C3\nkubectl port-forward controlcenter-0 9021:9021\n```\nWe access C3 via `localhost:9021` and see the produced events:\n\n![](./images/c3.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpneff93%2Fcfk-clients-oauth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpneff93%2Fcfk-clients-oauth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpneff93%2Fcfk-clients-oauth/lists"}