Share via


Een toepassing migreren om verbindingen zonder wachtwoord te gebruiken met Azure Event Hubs voor Kafka

In dit artikel wordt uitgelegd hoe u migreert van traditionele verificatiemethoden naar veiligere, wachtwoordloze verbindingen met Azure Event Hubs voor Kafka.

Toepassingsaanvragen voor Azure Event Hubs voor Kafka moeten worden geverifieerd. Azure Event Hubs voor Kafka biedt verschillende manieren om veilig verbinding te maken met apps. Een van de manieren is om een verbindingsreeks te gebruiken. U moet echter waar mogelijk prioriteit geven aan verbindingen zonder wachtwoord in uw toepassingen.

Verbindingen zonder wachtwoord worden ondersteund sinds Spring Cloud Azure 4.3.0. Dit artikel is een migratiehandleiding voor het verwijderen van referenties uit Spring Cloud Stream Kafka-toepassingen.

Verificatieopties vergelijken

Wanneer de toepassing wordt geverifieerd met Azure Event Hubs voor Kafka, biedt deze een geautoriseerde entiteit om verbinding te maken met de Event Hubs-naamruimte. Apache Kafka-protocollen bieden meerdere SASL-mechanismen (Simple Authentication and Security Layer) voor verificatie. Volgens de SASL-mechanismen zijn er twee verificatieopties die u kunt gebruiken om toegang tot uw beveiligde resources te autoriseren: Microsoft Entra-verificatie en SAS-verificatie (Shared Access Signature).

Microsoft Entra-verificatie

Microsoft Entra-verificatie is een mechanisme voor het maken van verbinding met Azure Event Hubs voor Kafka met behulp van identiteiten die zijn gedefinieerd in Microsoft Entra-id. Met Microsoft Entra-verificatie kunt u service-principal-identiteiten en andere Microsoft-services beheren op een centrale locatie, wat het beheer van machtigingen vereenvoudigt.

Het gebruik van Microsoft Entra ID voor verificatie biedt de volgende voordelen:

  • Verificatie van gebruikers in Azure-services op een uniforme manier.
  • Beheer van wachtwoordbeleid en wachtwoordrotatie op één plaats.
  • Meerdere vormen van verificatie die worden ondersteund door Microsoft Entra ID, waardoor wachtwoorden niet meer hoeven op te slaan.
  • Klanten kunnen Event Hubs-machtigingen beheren met behulp van externe (Microsoft Entra ID)-groepen.
  • Ondersteuning voor verificatie op basis van tokens voor toepassingen die verbinding maken met Azure Event Hubs voor Kafka.

SAS-verificatie

Event Hubs biedt ook Shared Access Signatures (SAS) voor gedelegeerde toegang tot Event Hubs voor Kafka-resources.

Hoewel het mogelijk is om verbinding te maken met Azure Event Hubs voor Kafka met SAS, moet dit met voorzichtigheid worden gebruikt. U moet ijverig zijn om de verbindingsreeks s nooit zichtbaar te maken op een onbeveiligde locatie. Iedereen die toegang krijgt tot de verbindingsreeks s kan zich verifiëren. Er bestaat bijvoorbeeld een risico dat een kwaadwillende gebruiker toegang heeft tot de toepassing als een verbindingsreeks per ongeluk wordt ingecheckt bij broncodebeheer, wordt verzonden via een onbeveiligde e-mail, geplakt in de verkeerde chat of wordt bekeken door iemand die niet gemachtigd mag zijn. In plaats daarvan biedt het autoriseren van toegang met behulp van het op OAuth 2.0-token gebaseerde mechanisme superieure beveiliging en gebruiksgemak via SAS. Overweeg om uw toepassing bij te werken voor het gebruik van verbindingen zonder wachtwoord.

Introductie van verbindingen zonder wachtwoord

Met een verbinding zonder wachtwoord kunt u verbinding maken met Azure-services zonder referenties op te slaan in de toepassingscode, de configuratiebestanden of in omgevingsvariabelen.

Veel Azure-services ondersteunen verbindingen zonder wachtwoord, bijvoorbeeld via Azure Managed Identity. Deze technieken bieden robuuste beveiligingsfuncties die u kunt implementeren met behulp van DefaultAzureCredential vanuit de Azure Identity-clientbibliotheken. In deze zelfstudie leert u hoe u een bestaande toepassing bijwerkt voor gebruik DefaultAzureCredential in plaats van alternatieven zoals verbindingsreeks s.

DefaultAzureCredential ondersteunt meerdere verificatiemethoden en bepaalt automatisch welke tijdens runtime moet worden gebruikt. Met deze aanpak kan uw app verschillende verificatiemethoden gebruiken in verschillende omgevingen (lokale ontwikkelomgeving versus productie) zonder omgevingsspecifieke code te implementeren.

De volgorde en locaties waarin DefaultAzureCredential wordt gezocht naar referenties, vindt u in het overzicht van de Azure Identity-bibliotheek. Wanneer u bijvoorbeeld lokaal werkt, DefaultAzureCredential wordt doorgaans geverifieerd met het account dat de ontwikkelaar heeft gebruikt om zich aan te melden bij Visual Studio. Wanneer de app wordt geïmplementeerd in Azure, DefaultAzureCredential wordt automatisch overgeschakeld naar het gebruik van een beheerde identiteit. Er zijn geen codewijzigingen vereist voor deze overgang.

Om ervoor te zorgen dat verbindingen zonder wachtwoord zijn, moet u rekening houden met zowel lokale ontwikkeling als de productieomgeving. Als een verbindingsreeks op beide plaatsen is vereist, is de toepassing niet wachtwoordloos.

In uw lokale ontwikkelomgeving kunt u zich verifiëren met Azure CLI, Azure PowerShell, Visual Studio of Azure-invoegtoepassingen voor Visual Studio Code of IntelliJ. In dit geval kunt u deze referentie in uw toepassing gebruiken in plaats van eigenschappen te configureren.

Wanneer u toepassingen implementeert in een Azure-hostingomgeving, zoals een virtuele machine, kunt u beheerde identiteit in die omgeving toewijzen. Vervolgens hoeft u geen referenties op te geven om verbinding te maken met Azure-services.

Notitie

Een beheerde identiteit biedt een beveiligingsidentiteit die een app of service vertegenwoordigt. De identiteit wordt beheerd door het Azure-platform en u hoeft geen geheimen in te richten of te draaien. Meer informatie over beheerde identiteiten vindt u in de overzichtsdocumentatie .

Een bestaande toepassing migreren om verbindingen zonder wachtwoord te gebruiken

In de volgende stappen wordt uitgelegd hoe u een bestaande toepassing migreert om verbindingen zonder wachtwoord te gebruiken in plaats van een SAS-oplossing.

0) De werkomgeving voorbereiden voor lokale ontwikkelingsverificatie

Gebruik eerst de volgende opdracht om enkele omgevingsvariabelen in te stellen.

export AZ_RESOURCE_GROUP=<YOUR_RESOURCE_GROUP>
export AZ_EVENTHUBS_NAMESPACE_NAME=<YOUR_EVENTHUBS_NAMESPACE_NAME>
export AZ_EVENTHUB_NAME=<YOUR_EVENTHUB_NAME>

Vervang de tijdelijke aanduidingen door de volgende waarden, die overal in dit artikel worden gebruikt:

  • <YOUR_RESOURCE_GROUP>: De naam van de resourcegroep die u gaat gebruiken.
  • <YOUR_EVENTHUBS_NAMESPACE_NAME>: De naam van de Azure Event Hubs-naamruimte die u gaat gebruiken.
  • <YOUR_EVENTHUB_NAME>: De naam van de Event Hub die u gaat gebruiken.

1) Machtigingen verlenen voor Azure Event Hubs

Als u dit voorbeeld lokaal wilt uitvoeren met Microsoft Entra-verificatie, moet u ervoor zorgen dat uw gebruikersaccount is geverifieerd via de Azure Toolkit voor IntelliJ, de Azure-accountinvoegtoepassing van Visual Studio Code of de Azure CLI. Zorg er ook voor dat het account voldoende machtigingen heeft gekregen.

  1. Zoek in Azure Portal uw Event Hubs-naamruimte met behulp van de hoofdzoekbalk of linkernavigatiebalk.

  2. Selecteer op de overzichtspagina van Event Hubs toegangsbeheer (IAM) in het menu aan de linkerkant.

  3. Selecteer op de pagina Toegangsbeheer (IAM) het tabblad Roltoewijzingen .

  4. Selecteer Toevoegen in het bovenste menu en voeg vervolgens roltoewijzing toe in de resulterende vervolgkeuzelijst.

    Screenshot of Azure portal Access Control (IAM) page of Event Hubs Namespace resource with Add role assignment highlighted.

  5. Gebruik het zoekvak om de resultaten te filteren op de gewenste rol. Zoek voor dit voorbeeld naar Azure Event Hubs-gegevenszender en Azure Event Hubs-gegevensontvanger en selecteer het overeenkomende resultaat en kies vervolgens Volgende.

  6. Selecteer onder Toegang toewijzen de optie Gebruiker, groep of service-principal en kies vervolgens Leden selecteren.

  7. Zoek in het dialoogvenster naar uw Microsoft Entra-gebruikersnaam (meestal uw user@domain e-mailadres) en kies Vervolgens onderaan het dialoogvenster Selecteren .

  8. Selecteer Beoordelen + toewijzen om naar de laatste pagina te gaan en vervolgens opnieuw beoordelen en toewijzen om het proces te voltooien.

Zie Toegang tot Event Hubs-resources autoriseren met behulp van Microsoft Entra ID voor meer informatie over het verlenen van toegangsrollen.

2) Meld u aan en migreer de app-code om wachtwoordloze verbindingen te gebruiken

Zorg ervoor dat u voor lokale ontwikkeling bent geverifieerd met hetzelfde Microsoft Entra-account waaraan u de rol hebt toegewezen in uw Event Hubs. U kunt zich verifiëren via de Azure CLI, Visual Studio, Azure PowerShell of andere hulpprogramma's, zoals IntelliJ.

Meld u aan bij Azure via de Azure CLI met behulp van de volgende opdracht:

az login

Gebruik vervolgens de volgende stappen om uw Spring Kafka-toepassing bij te werken voor het gebruik van verbindingen zonder wachtwoord. Hoewel conceptueel vergelijkbaar, maakt elk framework gebruik van verschillende implementatiedetails.

  1. Open het pom.xml-bestand in uw project en voeg de volgende verwijzing toe:

    <dependency>
       <groupId>com.azure</groupId>
       <artifactId>azure-identity</artifactId>
       <version>1.6.0</version>
    </dependency>
    
  2. Implementeer na de migratie AuthenticateCallbackHandler en OAuthBearerToken in uw project voor OAuth2-verificatie, zoals wordt weergegeven in het volgende voorbeeld.

    public class KafkaOAuth2AuthenticateCallbackHandler implements AuthenticateCallbackHandler {
    
       private static final Duration ACCESS_TOKEN_REQUEST_BLOCK_TIME = Duration.ofSeconds(30);
       private static final String TOKEN_AUDIENCE_FORMAT = "%s://%s/.default";
    
       private Function<TokenCredential, Mono<OAuthBearerTokenImp>> resolveToken;
       private final TokenCredential credential = new DefaultAzureCredentialBuilder().build();
    
       @Override
       public void configure(Map<String, ?> configs, String mechanism, List<AppConfigurationEntry> jaasConfigEntries) {
          TokenRequestContext request = buildTokenRequestContext(configs);
          this.resolveToken = tokenCredential -> tokenCredential.getToken(request).map(OAuthBearerTokenImp::new);
       }
    
       private TokenRequestContext buildTokenRequestContext(Map<String, ?> configs) {
          URI uri = buildEventHubsServerUri(configs);
          String tokenAudience = buildTokenAudience(uri);
    
          TokenRequestContext request = new TokenRequestContext();
          request.addScopes(tokenAudience);
          return request;
       }
    
       @SuppressWarnings("unchecked")
       private URI buildEventHubsServerUri(Map<String, ?> configs) {
          String bootstrapServer = Arrays.asList(configs.get(BOOTSTRAP_SERVERS_CONFIG)).get(0).toString();
          bootstrapServer = bootstrapServer.replaceAll("\\[|\\]", "");
          URI uri = URI.create("https://" + bootstrapServer);
          return uri;
       }
    
       private String buildTokenAudience(URI uri) {
          return String.format(TOKEN_AUDIENCE_FORMAT, uri.getScheme(), uri.getHost());
       }
    
       @Override
       public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
          for (Callback callback : callbacks) {
             if (callback instanceof OAuthBearerTokenCallback) {
                OAuthBearerTokenCallback oauthCallback = (OAuthBearerTokenCallback) callback;
                this.resolveToken
                        .apply(credential)
                        .doOnNext(oauthCallback::token)
                        .doOnError(throwable -> oauthCallback.error("invalid_grant", throwable.getMessage(), null))
                        .block(ACCESS_TOKEN_REQUEST_BLOCK_TIME);
             } else {
                throw new UnsupportedCallbackException(callback);
             }
          }
       }
    
       @Override
       public void close() {
          // NOOP
       }
    }
    
    public class OAuthBearerTokenImp implements OAuthBearerToken {
        private final AccessToken accessToken;
        private final JWTClaimsSet claims;
    
        public OAuthBearerTokenImp(AccessToken accessToken) {
            this.accessToken = accessToken;
            try {
                claims = JWTParser.parse(accessToken.getToken()).getJWTClaimsSet();
            } catch (ParseException exception) {
                throw new SaslAuthenticationException("Unable to parse the access token", exception);
            }
        }
    
        @Override
        public String value() {
            return accessToken.getToken();
        }
    
        @Override
        public Long startTimeMs() {
            return claims.getIssueTime().getTime();
        }
    
        @Override
        public long lifetimeMs() {
            return claims.getExpirationTime().getTime();
        }
    
        @Override
        public Set<String> scope() {
            // Referring to https://docs.microsoft.com/azure/active-directory/develop/access-tokens#payload-claims, the scp
            // claim is a String, which is presented as a space separated list.
            return Optional.ofNullable(claims.getClaim("scp"))
                    .map(s -> Arrays.stream(((String) s)
                    .split(" "))
                    .collect(Collectors.toSet()))
                    .orElse(null);
        }
    
        @Override
        public String principalName() {
            return (String) claims.getClaim("upn");
        }
    
        public boolean isExpired() {
            return accessToken.isExpired();
        }
    }
    
  3. Wanneer u uw Kafka-producent of -consument maakt, voegt u de configuratie toe die nodig is om het SASL/OAUTHBEARER-mechanisme te ondersteunen. In de volgende voorbeelden ziet u hoe uw code eruit moet zien vóór en na de migratie. Vervang in beide voorbeelden de <eventhubs-namespace> tijdelijke aanduiding door de naam van uw Event Hubs-naamruimte.

    Voordat de migratie wordt uitgevoerd, moet uw code eruitzien zoals in het volgende voorbeeld:

    Properties properties = new Properties();
    properties.put(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, "<eventhubs-namespace>.servicebus.windows.net:9093");
    properties.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_SSL");
    properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
    properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
    properties.put(SaslConfigs.SASL_MECHANISM, "PLAIN");
    properties.put(SaslConfigs.SASL_JAAS_CONFIG,
            String.format("org.apache.kafka.common.security.plain.PlainLoginModule required username=\"$ConnectionString\" password=\"%s\";", connectionString));
    return new KafkaProducer<>(properties);
    

    Na de migratie moet uw code eruitzien als in het volgende voorbeeld. Vervang in dit voorbeeld de <path-to-your-KafkaOAuth2AuthenticateCallbackHandler> tijdelijke aanduiding door de volledige klassenaam voor uw geïmplementeerde KafkaOAuth2AuthenticateCallbackHandlerklasse.

    Properties properties = new Properties();
    properties.put(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, "<eventhubs-namespace>.servicebus.windows.net:9093");
    properties.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_SSL");
    properties.put(SaslConfigs.SASL_MECHANISM, "OAUTHBEARER");
    properties.put(SaslConfigs.SASL_JAAS_CONFIG, "org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required");
    properties.put(SaslConfigs.SASL_LOGIN_CALLBACK_HANDLER_CLASS, "<path-to-your-KafkaOAuth2AuthenticateCallbackHandler>");
    return new KafkaProducer<>(properties);
    

De app lokaal uitvoeren

Nadat u deze codewijzigingen hebt aangebracht, voert u uw toepassing lokaal uit. De nieuwe configuratie moet uw lokale referenties ophalen, ervan uitgaande dat u bent aangemeld bij een compatibel IDE- of opdrachtregelprogramma, zoals de Azure CLI, Visual Studio of IntelliJ. Met de rollen die u hebt toegewezen aan uw lokale dev-gebruiker in Azure, kan uw app lokaal verbinding maken met de Azure-service.

3) De Azure-hostingomgeving configureren

Nadat uw toepassing is geconfigureerd voor het gebruik van verbindingen zonder wachtwoord en deze lokaal wordt uitgevoerd, kan dezelfde code worden geverifieerd bij Azure-services nadat deze is geïmplementeerd in Azure. Een toepassing die is geïmplementeerd in een Azure Spring Apps-exemplaar waaraan een beheerde identiteit is toegewezen, kan bijvoorbeeld verbinding maken met Azure Event Hubs voor Kafka.

In deze sectie voert u twee stappen uit om ervoor te zorgen dat uw toepassing op een wachtwoordloze manier kan worden uitgevoerd in een Azure-hostingomgeving:

  • Wijs de beheerde identiteit toe voor uw Azure-hostingomgeving.
  • Wijs rollen toe aan de beheerde identiteit.

Notitie

Azure biedt ook Service Verbinding maken or, waarmee u uw hostingservice kunt verbinden met Event Hubs. Met Service Verbinding maken or voor het configureren van uw hostingomgeving kunt u de stap voor het toewijzen van rollen aan uw beheerde identiteit weglaten, omdat Service Verbinding maken or dit voor u doet. In de volgende sectie wordt beschreven hoe u uw Azure-hostingomgeving op twee manieren configureert: één via Service Verbinding maken or en de andere door elke hostingomgeving rechtstreeks te configureren.

Belangrijk

Voor opdrachten van de service Verbinding maken or is Azure CLI 2.41.0 of hoger vereist.

De beheerde identiteit toewijzen voor uw Azure-hostingomgeving

De volgende stappen laten zien hoe u een door het systeem toegewezen beheerde identiteit toewijst voor verschillende webhostingservices. De beheerde identiteit kan veilig verbinding maken met andere Azure-services met behulp van de app-configuraties die u eerder hebt ingesteld.

  1. Selecteer Identiteit in het navigatiedeelvenster op de hoofdpagina van uw Azure-app Service-exemplaar.

  2. Zorg ervoor dat u op het tabblad Systeem toegewezen het veld Status instelt op Aan. Een door het systeem toegewezen identiteit wordt intern beheerd door Azure en verwerkt beheertaken voor u. De details en id's van de identiteit worden nooit weergegeven in uw code.

    Screenshot of Azure portal Identity page of App Service resource with System assigned tab showing and Status field highlighted.

U kunt ook beheerde identiteit toewijzen in een Azure-hostingomgeving met behulp van de Azure CLI.

U kunt een beheerde identiteit toewijzen aan een Azure-app Service-exemplaar met de opdracht az webapp identity assign, zoals wordt weergegeven in het volgende voorbeeld.

export AZURE_MANAGED_IDENTITY_ID=$(az webapp identity assign \
    --resource-group $AZ_RESOURCE_GROUP \
    --name <app-service-name> \
    --query principalId \
    --output tsv)

Rollen toewijzen aan de beheerde identiteit

Vervolgens verleent u machtigingen aan de beheerde identiteit die u hebt gemaakt voor toegang tot uw Event Hubs-naamruimte. U kunt machtigingen verlenen door een rol toe te wijzen aan de beheerde identiteit, net als bij uw lokale ontwikkelingsgebruiker.

Als u uw services hebt verbonden met behulp van de service-Verbinding maken or, hoeft u deze stap niet te voltooien. De volgende benodigde configuraties zijn voor u verwerkt:

  • Als u een beheerde identiteit hebt geselecteerd toen u de verbinding maakte, is er een door het systeem toegewezen beheerde identiteit gemaakt voor uw app en zijn de rollen Azure Event Hubs-gegevenszender en Azure Event Hubs-gegevensontvanger toegewezen aan de Event Hubs.

  • Als u ervoor kiest om een verbindingsreeks te gebruiken, is de verbindingsreeks toegevoegd als een omgevingsvariabele voor apps.

De app testen

Nadat u deze codewijzigingen hebt aangebracht, bladert u naar uw gehoste toepassing in de browser. Uw app moet verbinding kunnen maken met de Azure Event Hubs voor Kafka. Houd er rekening mee dat het enkele minuten kan duren voordat de roltoewijzingen zijn doorgegeven via uw Azure-omgeving. Uw toepassing is nu geconfigureerd om zowel lokaal als in een productieomgeving uit te voeren zonder dat de ontwikkelaars geheimen in de toepassing zelf hoeven te beheren.

Volgende stappen

In deze zelfstudie hebt u geleerd hoe u een toepassing migreert naar verbindingen zonder wachtwoord.

U kunt de volgende bronnen lezen om de concepten die in dit artikel worden besproken, uitgebreider te verkennen: