Udostępnij za pośrednictwem


Migrowanie aplikacji do używania połączeń bez hasła z usługą Azure Event Hubs dla platformy Kafka

W tym artykule wyjaśniono, jak przeprowadzić migrację z tradycyjnych metod uwierzytelniania do bezpieczniejszych połączeń bez hasła z usługą Azure Event Hubs dla platformy Kafka.

Żądania aplikacji do usługi Azure Event Hubs dla platformy Kafka muszą być uwierzytelnione. Usługa Azure Event Hubs dla platformy Kafka udostępnia różne sposoby bezpiecznego łączenia aplikacji. Jednym ze sposobów jest użycie parametry połączenia. Jednak w miarę możliwości należy określić priorytety połączeń bez hasła w aplikacjach.

Połączenia bez hasła są obsługiwane od platformy Spring Cloud Azure 4.3.0. Ten artykuł zawiera przewodnik migracji dotyczący usuwania poświadczeń z aplikacji platformy Kafka usługi Spring Cloud Stream.

Porównanie opcji uwierzytelniania

Gdy aplikacja uwierzytelnia się w usłudze Azure Event Hubs dla platformy Kafka, udostępnia ona autoryzowaną jednostkę do łączenia przestrzeni nazw usługi Event Hubs. Protokoły platformy Apache Kafka udostępniają wiele mechanizmów uwierzytelniania prostego i zabezpieczeń (SASL) na potrzeby uwierzytelniania. Zgodnie z mechanizmami SASL istnieją dwie opcje uwierzytelniania, których można użyć do autoryzowania dostępu do bezpiecznych zasobów: uwierzytelnianie firmy Microsoft Entra i uwierzytelnianie sygnatury dostępu współdzielonego (SAS).

Uwierzytelnianie Microsoft Entra

Uwierzytelnianie Entra firmy Microsoft to mechanizm łączenia się z usługą Azure Event Hubs dla platformy Kafka przy użyciu tożsamości zdefiniowanych w identyfikatorze Entra firmy Microsoft. Dzięki uwierzytelnieniu firmy Microsoft Entra można zarządzać tożsamościami jednostki usługi i innymi usługi firmy Microsoft w centralnej lokalizacji, co upraszcza zarządzanie uprawnieniami.

Korzystanie z identyfikatora Entra firmy Microsoft do uwierzytelniania zapewnia następujące korzyści:

  • Uwierzytelnianie użytkowników w usługach platformy Azure w jednolity sposób.
  • Zarządzanie zasadami haseł i rotacją haseł w jednym miejscu.
  • Wiele form uwierzytelniania obsługiwanych przez identyfikator Entra firmy Microsoft, co może wyeliminować konieczność przechowywania haseł.
  • Klienci mogą zarządzać uprawnieniami usługi Event Hubs przy użyciu grup zewnętrznych (Microsoft Entra ID).
  • Obsługa uwierzytelniania opartego na tokenach dla aplikacji łączących się z usługą Azure Event Hubs dla platformy Kafka.

Uwierzytelnianie sygnatury dostępu współdzielonego

Usługa Event Hubs zapewnia również sygnatury dostępu współdzielonego (SAS) na potrzeby delegowanego dostępu do usługi Event Hubs dla zasobów platformy Kafka.

Chociaż istnieje możliwość nawiązania połączenia z usługą Azure Event Hubs dla platformy Kafka przy użyciu sygnatury dostępu współdzielonego, należy zachować ostrożność. Musisz być sumienny, aby nigdy nie ujawniać parametry połączenia w niezabezpieczonej lokalizacji. Każdy, kto uzyskuje dostęp do parametry połączenia, jest w stanie uwierzytelnić się. Istnieje na przykład ryzyko, że złośliwy użytkownik może uzyskać dostęp do aplikacji, jeśli parametry połączenia zostanie przypadkowo zaewidencjonowany w kontroli źródła, wysłany za pośrednictwem niezabezpieczonej wiadomości e-mail, wklejony do nieprawidłowego czatu lub wyświetlony przez osobę, która nie powinna mieć uprawnień. Zamiast tego autoryzowanie dostępu przy użyciu mechanizmu opartego na tokenach OAuth 2.0 zapewnia lepsze zabezpieczenia i łatwość użycia za pośrednictwem sygnatury dostępu współdzielonego. Rozważ zaktualizowanie aplikacji w celu korzystania z połączeń bez hasła.

Wprowadzenie do połączeń bez hasła

Za pomocą połączenia bez hasła można nawiązać połączenie z usługami platformy Azure bez przechowywania poświadczeń w kodzie aplikacji, jego plikach konfiguracji lub zmiennych środowiskowych.

Wiele usług platformy Azure obsługuje połączenia bez hasła, na przykład za pośrednictwem tożsamości zarządzanej platformy Azure. Te techniki zapewniają niezawodne funkcje zabezpieczeń, które można zaimplementować przy użyciu wartości DefaultAzureCredential z bibliotek klienckich tożsamości platformy Azure. Z tego samouczka dowiesz się, jak zaktualizować istniejącą aplikację do użycia DefaultAzureCredential zamiast alternatyw, takich jak parametry połączenia.

DefaultAzureCredential obsługuje wiele metod uwierzytelniania i automatycznie określa, które powinny być używane w czasie wykonywania. Takie podejście umożliwia aplikacji używanie różnych metod uwierzytelniania w różnych środowiskach (lokalnych deweloperów i produkcji) bez implementowania kodu specyficznego dla środowiska.

Kolejność i lokalizacje, w których DefaultAzureCredential można wyszukiwać poświadczenia, można znaleźć w przeglądzie biblioteki tożsamości platformy Azure. Na przykład podczas pracy lokalnie DefaultAzureCredential zazwyczaj uwierzytelnia się przy użyciu konta, które deweloper użył do logowania się w programie Visual Studio. Po wdrożeniu aplikacji na platformie Azure DefaultAzureCredential nastąpi automatyczne przełączenie w celu użycia tożsamości zarządzanej. Do tego przejścia nie są wymagane żadne zmiany kodu.

Aby upewnić się, że połączenia są bez hasła, należy wziąć pod uwagę zarówno lokalne programowanie, jak i środowisko produkcyjne. Jeśli parametry połączenia jest wymagana w obu miejscach, aplikacja nie jest bez hasła.

W lokalnym środowisku projektowym możesz uwierzytelnić się za pomocą interfejsu wiersza polecenia platformy Azure, programu Azure PowerShell, programu Visual Studio lub wtyczek platformy Azure dla programu Visual Studio Code lub IntelliJ. W takim przypadku można użyć tego poświadczenia w aplikacji zamiast konfigurowania właściwości.

Podczas wdrażania aplikacji w środowisku hostingu platformy Azure, takim jak maszyna wirtualna, można przypisać tożsamość zarządzaną w tym środowisku. Następnie nie trzeba podawać poświadczeń w celu nawiązania połączenia z usługami platformy Azure.

Uwaga

Tożsamość zarządzana zapewnia tożsamość zabezpieczeń reprezentującą aplikację lub usługę. Tożsamość jest zarządzana przez platformę Azure i nie wymaga aprowizacji ani rotacji żadnych wpisów tajnych. Więcej informacji na temat tożsamości zarządzanych można uzyskać w dokumentacji przeglądu .

Migrowanie istniejącej aplikacji do korzystania z połączeń bez hasła

W poniższych krokach wyjaśniono, jak przeprowadzić migrację istniejącej aplikacji w celu używania połączeń bez hasła zamiast rozwiązania SAS.

0) Przygotowanie środowiska roboczego do lokalnego uwierzytelniania programistycznego

Najpierw użyj następującego polecenia, aby skonfigurować niektóre zmienne środowiskowe.

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

Zastąp symbole zastępcze następującymi wartościami, które są używane w tym artykule:

  • <YOUR_RESOURCE_GROUP>: nazwa używanej grupy zasobów.
  • <YOUR_EVENTHUBS_NAMESPACE_NAME>: nazwa przestrzeni nazw usługi Azure Event Hubs, której będziesz używać.
  • <YOUR_EVENTHUB_NAME>: nazwa centrum zdarzeń, którego będziesz używać.

1) Udzielanie uprawnień do usługi Azure Event Hubs

Jeśli chcesz uruchomić ten przykład lokalnie z uwierzytelnianiem firmy Microsoft Entra, upewnij się, że twoje konto użytkownika zostało uwierzytelnione za pośrednictwem zestawu narzędzi Azure Toolkit for IntelliJ, wtyczki konta platformy Azure programu Visual Studio Code lub interfejsu wiersza polecenia platformy Azure. Upewnij się również, że konto otrzymało wystarczające uprawnienia.

  1. W witrynie Azure Portal znajdź przestrzeń nazw usługi Event Hubs przy użyciu głównego paska wyszukiwania lub nawigacji po lewej stronie.

  2. Na stronie przeglądu usługi Event Hubs wybierz pozycję Kontrola dostępu (Zarządzanie dostępem i tożsamościami) z menu po lewej stronie.

  3. Na stronie Kontrola dostępu (Zarządzanie dostępem i tożsamościami) wybierz kartę Przypisania ról.

  4. Wybierz pozycję Dodaj z górnego menu, a następnie pozycję Dodaj przypisanie roli z wyświetlonego menu rozwijanego.

    Zrzut ekranu przedstawiający stronę Kontroli dostępu (IAM) witryny Azure Portal zasobu przestrzeni nazw usługi Event Hubs z wyróżnioną pozycją Dodaj przypisanie roli.

  5. Użyj pola wyszukiwania, aby filtrować wyniki do żądanej roli. W tym przykładzie wyszukaj pozycję Nadawca danych usługi Azure Event Hubs i Odbiornik danych usługi Azure Event Hubs, a następnie wybierz odpowiedni wynik, a następnie wybierz pozycję Dalej.

  6. W obszarze Przypisz dostęp do wybierz pozycję Użytkownik, grupa lub jednostka usługi, a następnie wybierz pozycję Wybierz członków.

  7. W oknie dialogowym wyszukaj nazwę użytkownika firmy Microsoft Entra (zazwyczaj adres e-mail user@domain ), a następnie wybierz pozycję Wybierz w dolnej części okna dialogowego.

  8. Wybierz pozycję Przejrzyj i przypisz , aby przejść do ostatniej strony, a następnie ponownie przejrzyj i przypisz, aby ukończyć proces.

Aby uzyskać więcej informacji na temat udzielania ról dostępu, zobacz Autoryzowanie dostępu do zasobów usługi Event Hubs przy użyciu identyfikatora Entra firmy Microsoft.

2) Zaloguj się i zmigruj kod aplikacji, aby używać połączeń bez hasła

W przypadku programowania lokalnego upewnij się, że uwierzytelniasz się przy użyciu tego samego konta Microsoft Entra, do którego przypisano rolę w usłudze Event Hubs. Możesz uwierzytelnić się za pomocą interfejsu wiersza polecenia platformy Azure, programu Visual Studio, programu Azure PowerShell lub innych narzędzi, takich jak IntelliJ.

Zaloguj się do platformy Azure za pomocą interfejsu wiersza polecenia platformy Azure przy użyciu następującego polecenia:

az login

Następnie wykonaj następujące kroki, aby zaktualizować aplikację Spring Kafka do korzystania z połączeń bez hasła. Chociaż koncepcyjnie podobne, każda struktura używa różnych szczegółów implementacji.

  1. W projekcie otwórz plik pom.xml i dodaj następujące odwołanie:

    <dependency>
       <groupId>com.azure</groupId>
       <artifactId>azure-identity</artifactId>
       <version>1.6.0</version>
    </dependency>
    
  2. Po migracji zaimplementuj element AuthenticationCallbackHandler i OAuthBearerToken w projekcie na potrzeby uwierzytelniania OAuth2, jak pokazano w poniższym przykładzie.

    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. Podczas tworzenia producenta lub odbiorcy platformy Kafka dodaj konfigurację wymaganą do obsługi mechanizmu SASL/OAUTHBEARER . W poniższych przykładach pokazano, jak powinien wyglądać kod przed migracją i po nim. W obu przykładach zastąp <eventhubs-namespace> symbol zastępczy nazwą przestrzeni nazw usługi Event Hubs.

    Przed migracją kod powinien wyglądać podobnie do poniższego przykładu:

    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);
    

    Po migracji kod powinien wyglądać podobnie do poniższego przykładu. W tym przykładzie <path-to-your-KafkaOAuth2AuthenticateCallbackHandler> zastąp symbol zastępczy pełną nazwą klasy zaimplementowanego KafkaOAuth2AuthenticateCallbackHandlerelementu .

    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);
    

Lokalne uruchamianie aplikacji

Po wprowadzeniu tych zmian w kodzie uruchom aplikację lokalnie. Nowa konfiguracja powinna pobierać poświadczenia lokalne, przy założeniu, że zalogowano się do zgodnego środowiska IDE lub narzędzia wiersza polecenia, takiego jak interfejs wiersza polecenia platformy Azure, program Visual Studio lub IntelliJ. Role przypisane do lokalnego użytkownika deweloperskiego na platformie Azure umożliwiają aplikacji nawiązywanie połączenia z usługą platformy Azure lokalnie.

3) Konfigurowanie środowiska hostingu platformy Azure

Po skonfigurowaniu aplikacji do używania połączeń bez hasła i uruchomieniu go lokalnie ten sam kod może uwierzytelniać się w usługach platformy Azure po jej wdrożeniu na platformie Azure. Na przykład aplikacja wdrożona w wystąpieniu usługi Azure Spring Apps z przypisaną tożsamością zarządzaną może łączyć się z usługą Azure Event Hubs dla platformy Kafka.

W tej sekcji wykonasz dwa kroki, aby umożliwić uruchamianie aplikacji w środowisku hostingu platformy Azure w sposób bez hasła:

  • Przypisz tożsamość zarządzaną dla środowiska hostingu platformy Azure.
  • Przypisz role do tożsamości zarządzanej.

Uwaga

Platforma Azure udostępnia również łącznik usług, który może pomóc w połączeniu usługi hostingowej z usługą Event Hubs. Za pomocą łącznika usługi w celu skonfigurowania środowiska hostingu można pominąć krok przypisywania ról do tożsamości zarządzanej, ponieważ łącznik usługi zrobi to za Ciebie. W poniższej sekcji opisano sposób konfigurowania środowiska hostingu platformy Azure na dwa sposoby: jeden za pośrednictwem łącznika usługi i drugi przez bezpośrednie skonfigurowanie każdego środowiska hostingu.

Ważne

Polecenia łącznika usług wymagają interfejsu wiersza polecenia platformy Azure w wersji 2.41.0 lub nowszej.

Przypisywanie tożsamości zarządzanej dla środowiska hostingu platformy Azure

W poniższych krokach pokazano, jak przypisać tożsamość zarządzaną przypisaną przez system dla różnych usług hostingu sieci Web. Tożsamość zarządzana może bezpiecznie łączyć się z innymi usługami platformy Azure przy użyciu skonfigurowanych wcześniej konfiguracji aplikacji.

  1. Na stronie głównej przeglądu wystąpienia usługi aplikacja systemu Azure wybierz pozycję Tożsamość w okienku nawigacji.

  2. Na karcie Przypisane przez system upewnij się, że pole Stan ma wartość włączone. Tożsamość przypisana przez system jest zarządzana przez platformę Azure wewnętrznie i obsługuje zadania administracyjne. Szczegóły i identyfikatory tożsamości nigdy nie są ujawniane w kodzie.

Tożsamość zarządzaną można również przypisać w środowisku hostingu platformy Azure przy użyciu interfejsu wiersza polecenia platformy Azure.

Tożsamość zarządzaną można przypisać do wystąpienia usługi aplikacja systemu Azure za pomocą polecenia az webapp identity assign, jak pokazano w poniższym przykładzie.

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

Przypisywanie ról do tożsamości zarządzanej

Następnie przyznaj uprawnienia utworzonej tożsamości zarządzanej w celu uzyskania dostępu do przestrzeni nazw usługi Event Hubs. Uprawnienia można przyznać, przypisując rolę do tożsamości zarządzanej, podobnie jak w przypadku lokalnego użytkownika dewelopera.

Jeśli połączono usługi przy użyciu łącznika usługi, nie musisz wykonywać tego kroku. Zostały spełnione następujące niezbędne konfiguracje:

  • W przypadku wybrania tożsamości zarządzanej podczas tworzenia połączenia utworzono tożsamość zarządzaną przypisaną przez system dla aplikacji i przypisano role Nadawca danych usługi Azure Event Hubs i Odbiornik danych usługi Azure Event Hubs w usłudze Event Hubs.

  • Jeśli zdecydujesz się użyć parametry połączenia, parametry połączenia został dodany jako zmienna środowiskowa aplikacji.

Testowanie aplikacji

Po wprowadzeniu tych zmian w kodzie przejdź do hostowanej aplikacji w przeglądarce. Aplikacja powinna mieć możliwość pomyślnego nawiązania połączenia z usługą Azure Event Hubs dla platformy Kafka. Należy pamiętać, że propagowanie przypisań ról za pośrednictwem środowiska platformy Azure może potrwać kilka minut. Aplikacja jest teraz skonfigurowana do uruchamiania zarówno lokalnie, jak i w środowisku produkcyjnym bez konieczności zarządzania wpisami tajnymi w samej aplikacji.

Następne kroki

W tym samouczku przedstawiono sposób migrowania aplikacji do połączeń bez hasła.

Aby zapoznać się z pojęciami omówionymi w tym artykule, zapoznaj się z następującymi zasobami: