Partager via


Migrer une application pour utiliser des connexions sans mot de passe avec Azure Event Hubs pour Kafka

Cet article explique comment migrer des méthodes d’authentification traditionnelles vers des connexions sans mot de passe plus sécurisées avec Azure Event Hubs pour Kafka.

Les demandes d’application adressées à Azure Event Hubs pour Kafka doivent être authentifiées. Azure Event Hubs pour Kafka fournit différentes façons pour les applications de se connecter en toute sécurité. L’une des façons d’utiliser une chaîne de connexion. Toutefois, vous devez hiérarchiser les connexions sans mot de passe dans vos applications lorsque cela est possible.

Les connexions sans mot de passe sont prises en charge depuis Spring Cloud Azure 4.3.0. Cet article est un guide de migration pour supprimer les informations d’identification des applications Kafka Spring Cloud Stream.

Comparer les options d’authentification

Lorsque l’application s’authentifie auprès d’Azure Event Hubs pour Kafka, elle fournit une entité autorisée pour connecter l’espace de noms Event Hubs. Les protocoles Apache Kafka fournissent plusieurs mécanismes d’authentification et de couche de sécurité (SASL) simples pour l’authentification. Selon les mécanismes SASL, il existe deux options d’authentification que vous pouvez utiliser pour autoriser l’accès à vos ressources sécurisées : l’authentification Microsoft Entra et l’authentification SAP (Shared Access Signature).

Authentification Microsoft Entra

L’authentification Microsoft Entra est un mécanisme de connexion à Azure Event Hubs pour Kafka à l’aide d’identités définies dans l’ID Microsoft Entra. Avec l’authentification Microsoft Entra, vous pouvez gérer les identités de principal de service et d’autres services Microsoft dans un emplacement central, ce qui simplifie la gestion des autorisations.

L’utilisation de l’ID Microsoft Entra pour l’authentification offre les avantages suivants :

  • Authentification uniforme des utilisateurs dans les services Azure.
  • Gestion des stratégies de mot de passe et de la rotation de mot de passe dans un emplacement unique.
  • Plusieurs formes d’authentification prises en charge par l’ID Microsoft Entra, qui peuvent éliminer la nécessité de stocker les mots de passe.
  • Les clients peuvent gérer les autorisations Event Hubs à l’aide de groupes externes (Microsoft Entra ID).
  • Prise en charge de l’authentification basée sur des jetons pour les applications qui se connectent à Azure Event Hubs pour Kafka.

Authentification avec SAS

Event Hubs fournit également des signatures d’accès partagé (SAP) pour l’accès délégué à Event Hubs pour les ressources Kafka.

Bien qu’il soit possible de se connecter à Azure Event Hubs pour Kafka avec SAS, il doit être utilisé avec précaution. Vous devez être vigilant pour ne jamais exposer les chaîne de connexion dans un emplacement non sécurisé. Toute personne ayant accès aux chaîne de connexion est en mesure de s’authentifier. Par exemple, il existe un risque qu’un utilisateur malveillant puisse accéder à l’application si un chaîne de connexion est accidentellement archivé dans le contrôle de code source, envoyé via un e-mail non sécurisé, collé dans une conversation incorrecte ou consulté par une personne qui ne doit pas avoir d’autorisation. Au lieu de cela, l’autorisation de l’accès à l’aide du mécanisme basé sur des jetons OAuth 2.0 offre une sécurité et une facilité d’utilisation supérieures sur SAS. Envisagez de mettre à jour votre application pour utiliser des connexions sans mot de passe.

Présentation des connexions sans mot de passe

Avec une connexion sans mot de passe, vous pouvez vous connecter aux services Azure sans stocker d’informations d’identification dans le code de l’application, ses fichiers de configuration ou dans les variables d’environnement.

De nombreux services Azure prennent en charge les connexions sans mot de passe, par exemple via Azure Managed Identity. Ces techniques fournissent des fonctionnalités de sécurité robustes que vous pouvez implémenter à l’aide de DefaultAzureCredential à partir des bibliothèques clientes Azure Identity. Dans ce tutoriel, vous allez apprendre à mettre à jour une application existante à utiliser DefaultAzureCredential au lieu d’alternatives telles que des chaîne de connexion.

DefaultAzureCredential prend en charge plusieurs méthodes d’authentification et détermine automatiquement celle qui doit être utilisée au moment de l’exécution. Cette approche permet à votre application d’utiliser différentes méthodes d’authentification dans différents environnements (développement local et production) sans implémenter de code spécifique à l’environnement.

L’ordre et les emplacements dans lesquels DefaultAzureCredential les recherches d’informations d’identification sont disponibles dans la vue d’ensemble de la bibliothèque d’identités Azure. Par exemple, lorsque vous travaillez localement, DefaultAzureCredential s’authentifie généralement à l’aide du compte utilisé par le développeur pour se connecter à Visual Studio. Lorsque l’application est déployée sur Azure, DefaultAzureCredential bascule automatiquement pour utiliser une identité managée. Aucune modification du code n’est requise pour cette transition.

Pour vous assurer que les connexions sont sans mot de passe, vous devez prendre en compte le développement local et l’environnement de production. Si une chaîne de connexion est requise à l’un ou l’autre endroit, l’application n’est pas sans mot de passe.

Dans votre environnement de développement local, vous pouvez vous authentifier auprès d’Azure CLI, d’Azure PowerShell, de Visual Studio ou de plug-ins Azure pour Visual Studio Code ou IntelliJ. Dans ce cas, vous pouvez utiliser ces informations d’identification dans votre application au lieu de configurer des propriétés.

Lorsque vous déployez des applications dans un environnement d’hébergement Azure, tel qu’une machine virtuelle, vous pouvez affecter une identité managée dans cet environnement. Ensuite, vous n’avez pas besoin de fournir des informations d’identification pour vous connecter aux services Azure.

Remarque

Une identité managée fournit une identité de sécurité pour représenter une application ou un service. Managée par la plateforme Azure, l’identité ne nécessite pas que vous approvisionniez ou permutiez de secrets. Vous pouvez en savoir plus sur les identités managées dans la documentation vue d’ensemble .

Migrer une application existante pour utiliser des connexions sans mot de passe

Les étapes suivantes expliquent comment migrer une application existante pour utiliser des connexions sans mot de passe au lieu d’une solution SAP.

0) Préparer l’environnement de travail pour l’authentification de développement local

Tout d’abord, utilisez la commande suivante pour configurer certaines variables d’environnement.

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

Remplacez les espaces réservés par les valeurs suivantes, qui sont utilisées dans cet article :

  • <YOUR_RESOURCE_GROUP>: nom du groupe de ressources que vous utiliserez.
  • <YOUR_EVENTHUBS_NAMESPACE_NAME>: nom de l’espace de noms Azure Event Hubs que vous utiliserez.
  • <YOUR_EVENTHUB_NAME>: nom du hub d’événements que vous utiliserez.

1) Accorder l’autorisation pour Azure Event Hubs

Si vous souhaitez exécuter cet exemple localement avec l’authentification Microsoft Entra, assurez-vous que votre compte d’utilisateur s’est authentifié via le kit de ressources Azure pour IntelliJ, le plug-in de compte Azure Visual Studio Code ou Azure CLI. Vérifiez également que le compte a reçu des autorisations suffisantes.

  1. Dans le portail Azure, recherchez votre espace de noms Event Hubs à l’aide de la barre de recherche principale ou de la navigation gauche.

  2. Dans la page vue d’ensemble d’Event Hubs, sélectionnez Contrôle d’accès (IAM) dans le menu de gauche.

  3. Sur la page Contrôle d’accès (IAM), sélectionnez l’onglet Attributions de rôles.

  4. Sélectionnez Ajouter dans le menu supérieur, puis Ajoutez une attribution de rôle dans le menu déroulant résultant.

    Capture d’écran de Portail Azure page Contrôle d’accès (IAM) de la ressource d’espace de noms Event Hubs avec ajout d’une attribution de rôle mise en surbrillance.

  5. Utilisez la zone de recherche pour filtrer les résultats sur le rôle souhaité. Pour cet exemple, recherchez l’expéditeur de données Azure Event Hubs et le récepteur de données Azure Event Hubs, puis sélectionnez le résultat correspondant, puis choisissez Suivant.

  6. Sous Attribuer l’accès, sélectionnez Utilisateur, groupe ou principal de service, puis sélectionnez Sélectionner des membres.

  7. Dans la boîte de dialogue, recherchez votre nom d’utilisateur Microsoft Entra (généralement votre adresse e-mail utilisateur@domaine), puis choisissez Sélectionner en bas de la boîte de dialogue.

  8. Sélectionnez Vérifier + affecter pour accéder à la page finale, puis Vérifier + attribuer à nouveau pour terminer le processus.

Pour plus d’informations sur l’octroi de rôles d’accès, consultez Autoriser l’accès aux ressources Event Hubs à l’aide de l’ID Microsoft Entra.

2) Connectez-vous et migrez le code de l’application pour utiliser des connexions sans mot de passe

Pour le développement local, vérifiez que vous êtes authentifié avec le même compte Microsoft Entra auquel vous avez affecté le rôle sur vos Hubs d’événements. Vous pouvez vous authentifier via Azure CLI, Visual Studio, Azure PowerShell ou d’autres outils tels qu’IntelliJ.

Connectez-vous à Azure via Azure CLI à l’aide de la commande suivante :

az login

Ensuite, procédez comme suit pour mettre à jour votre application Spring Kafka pour utiliser des connexions sans mot de passe. Bien que conceptuellement similaire, chaque infrastructure utilise des détails d’implémentation différents.

  1. Dans votre projet, ouvrez le fichier pom.xml et ajoutez la référence suivante :

    <dependency>
       <groupId>com.azure</groupId>
       <artifactId>azure-identity</artifactId>
       <version>1.6.0</version>
    </dependency>
    
  2. Après la migration, implémentez AuthenticateCallbackHandler et OAuthBearerToken dans votre projet pour l’authentification OAuth2, comme illustré dans l’exemple suivant.

    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. Lorsque vous créez votre producteur ou consommateur Kafka, ajoutez la configuration nécessaire pour prendre en charge le mécanisme SASL/OAUTHBEARER . Les exemples suivants montrent l’apparence de votre code avant et après la migration. Dans les deux exemples, remplacez l’espace <eventhubs-namespace> réservé par le nom de votre espace de noms Event Hubs.

    Avant la migration, votre code doit ressembler à l’exemple suivant :

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

    Après la migration, votre code doit ressembler à l’exemple suivant. Dans cet exemple, remplacez l’espace <path-to-your-KafkaOAuth2AuthenticateCallbackHandler> réservé par le nom de classe complet de votre implémentation KafkaOAuth2AuthenticateCallbackHandler.

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

Exécutez l’application localement.

Après avoir apporté ces modifications de code, exécutez votre application localement. La nouvelle configuration doit récupérer vos informations d’identification locales, en supposant que vous êtes connecté à un outil en ligne de commande ou IDE compatible, tel que Azure CLI, Visual Studio ou IntelliJ. Les rôles que vous avez attribués à votre utilisateur de développement local dans Azure permettent à votre application de se connecter au service Azure localement.

3) Configurer l’environnement d’hébergement Azure

Une fois que votre application est configurée pour utiliser des connexions sans mot de passe et qu’elle s’exécute localement, le même code peut s’authentifier auprès des services Azure après son déploiement sur Azure. Par exemple, une application déployée sur une instance Azure Spring Apps qui a une identité managée affectée peut se connecter à Azure Event Hubs pour Kafka.

Dans cette section, vous allez exécuter deux étapes pour permettre à votre application de s’exécuter dans un environnement d’hébergement Azure de manière sans mot de passe :

  • Attribuez l’identité managée pour votre environnement d’hébergement Azure.
  • Attribuez des rôles à l’identité managée.

Remarque

Azure fournit également Service Connector, qui peut vous aider à connecter votre service d’hébergement à Event Hubs. Avec Service Connector pour configurer votre environnement d’hébergement, vous pouvez omettre l’étape d’attribution de rôles à votre identité managée, car Service Connector le fera pour vous. La section suivante explique comment configurer votre environnement d’hébergement Azure de deux façons : une via Service Connector et l’autre en configurant directement chaque environnement d’hébergement.

Important

Les commandes de Service Connector nécessitent Azure CLI 2.41.0 ou version ultérieure.

Attribuer l’identité managée pour votre environnement d’hébergement Azure

Les étapes suivantes vous montrent comment attribuer une identité managée affectée par le système pour différents services d’hébergement web. L’identité managée peut se connecter en toute sécurité à d’autres services Azure à l’aide des configurations d’application que vous avez configurées.

  1. Dans la page de vue d’ensemble principale de votre instance Azure App Service, sélectionnez Identité dans le volet de navigation.

  2. Sous l’onglet Affecté par le système, veillez à définir le champ État sur activé. Une identité affectée par le système est gérée par Azure en interne et gère les tâches d’administration pour vous. Les détails et ID de l’identité ne sont jamais exposés dans votre code.

Vous pouvez également affecter une identité managée sur un environnement d’hébergement Azure à l’aide d’Azure CLI.

Vous pouvez affecter une identité managée à une instance Azure App Service avec la commande az webapp identity assign, comme illustré dans l’exemple suivant.

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

Attribuer des rôles à l’identité managée

Ensuite, accordez des autorisations à l’identité managée que vous avez créée pour accéder à votre espace de noms Event Hubs. Vous pouvez accorder des autorisations en affectant un rôle à l’identité managée, comme vous l’avez fait avec votre utilisateur de développement local.

Si vous avez connecté vos services à l’aide du connecteur de service, vous n’avez pas besoin d’effectuer cette étape. Les configurations nécessaires suivantes ont été gérées pour vous :

  • Si vous avez sélectionné une identité managée lors de la création de la connexion, une identité managée affectée par le système a été créée pour votre application et a affecté les rôles Expéditeur de données Azure Event Hubs et Récepteur de données Azure Event Hubs sur Event Hubs.

  • Si vous avez choisi d’utiliser un chaîne de connexion, la chaîne de connexion a été ajoutée en tant que variable d’environnement d’application.

Tester l'application

Après avoir apporté ces modifications de code, accédez à votre application hébergée dans le navigateur. Votre application doit être en mesure de se connecter à Azure Event Hubs pour Kafka. N’oubliez pas qu’il peut falloir plusieurs minutes pour que les attributions de rôle se propagent dans l’environnement Azure. Votre application est désormais configurée pour s’exécuter localement et dans un environnement de production sans que les développeurs n’aient à gérer les secrets dans l’application elle-même.

Étapes suivantes

Dans ce didacticiel, vous avez appris à migrer une application vers des connexions sans mot de passe.

Vous pouvez lire les ressources suivantes pour explorer les concepts abordés dans cet article plus en détails :