Aller au contenu
English

Identité et secrets

  • Leçon 11
  • 45 min
  • Module 4 : Les services de base du nuage

Ce que vous saurez faire

Dans le nuage, votre application doit prouver son identité avant de récupérer son image ou de lire un secret. Donnez-lui une identité sans mot de passe et autorisez seulement l’action dont elle a besoin. Gardez son secret là où peu de personnes et de programmes peuvent le lire.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 45 minutes

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur

  • Vos notes de l’exercice guidé de Régions et types de services. Cette leçon y ajoute un plan d’accès.
  • Le dossier du projet ~/projects/ticket-api à la fin du module 3. S’il manque, copiez l’instantané end-of-m03, comme dans Utiliser un instantané.
  • Aucun compte Azure. Toutes les sorties Azure de cette leçon sont des sorties réelles, obtenues pendant l’exécution. Vous exécuterez ces commandes au module 5.

Les étapes Azure ont été exécutées avec Azure CLI 2.88.0 et l’extension containerapp 1.3.0b5, dans la région canadacentral.

Sur son ordinateur, Amira récupère une image d’un registre privé après az acr login. Le registre pose deux questions. Sa connexion répond aux deux :

  1. Qui êtes-vous? Amira, une utilisatrice dans le locataire de son organisation.
  2. Que pouvez-vous faire ici? Envoyer et récupérer des images dans ce registre.

Dans le nuage, l’application conteneur récupère elle-même l’image à 3 h, sans personne de connecté. Elle doit répondre elle-même aux deux questions. Il existe deux façons de lui donner ces réponses :

  • Un mot de passe. Le registre a un utilisateur administrateur avec un mot de passe. Vous copiez ce mot de passe dans les paramètres de l’application. Ce mot de passe n’expire jamais de lui-même. Toute personne qui le voit peut l’utiliser, et vous devez penser à le changer.
  • Une identité. Azure donne à l’application sa propre identité et la prouve pour elle. Vous autorisez cette identité à faire une seule chose : récupérer des images de ce registre précis. Il n’y a aucun mot de passe, donc aucun mot de passe ne peut être divulgué.

Le cours utilise la deuxième façon.

Une identité désigne toute personne ou tout programme qui peut se connecter et demander un accès. Par exemple, Amira est une identité. Une identité managée est une identité qu’Azure crée et gère pour une ressource. Grâce à elle, la ressource peut se connecter à d’autres services Azure sans mot de passe. Azure conserve et renouvelle ses identifiants. Personne ne les voit, pas même vous.

Il en existe deux types :

Affectée par le système Affectée par l’utilisateur
Ce qu’elle est Une partie d’une seule ressource, comme une application conteneur Une ressource distincte, dans un groupe de ressources
Cycle de vie Supprimée quand cette ressource est supprimée Existe jusqu’à ce que vous la supprimiez
Nombre de ressources pouvant l’utiliser Cette seule ressource Une ou plusieurs
Moment où elle existe Seulement après la création de la ressource Avant la ressource, si vous la créez d’abord

Le cours utilise une identité affectée par l’utilisateur, id-ticket-api, pour une raison : elle peut exister avant l’application. Amira crée l’identité, lui accorde son autorisation, puis crée l’application avec cette identité. L’application peut donc récupérer l’image dès son premier démarrage. Une identité affectée par le système existe seulement après la création de l’application par Azure. Sans étapes supplémentaires, elle ne peut pas recevoir son rôle à temps pour cette première récupération.

Les autres nuages ont le même concept : un rôle IAM pour un service sur AWS, un compte de service sur Google Cloud.

Une identité seule ne peut rien faire. L’accès vient d’une attribution de rôle, qui comprend trois parties :

  • Qui : l’identité, par exemple id-ticket-api.
  • Le rôle : une liste nommée d’actions autorisées, par exemple AcrPull.
  • La portée : l’endroit où le rôle s’applique. Dans Azure, la portée comporte quatre niveaux, du plus large au plus restreint : un groupe d’administration, un abonnement, un groupe de ressources ou une ressource. Un rôle de portée large s’applique à tout ce qu’elle contient.

Un rôle est plus facile à comprendre quand vous lisez ses actions. Cette commande ne fait que lire :

Terminal (optional, needs an Azure account)
az role definition list --name AcrPull --query "[0].{name:roleName, actions:permissions[0].actions, dataActions:permissions[0].dataActions}" -o json
{
"actions": [
"Microsoft.ContainerRegistry/registries/pull/read"
],
"dataActions": [],
"name": "AcrPull"
}

Une seule action : récupérer depuis un registre. Comparez avec le rôle Owner (propriétaire) :

{
"actions": [
"*"
],
"name": "Owner"
}

* signifie toutes les actions. Une identité ayant le rôle Owner sur l’abonnement peut créer, modifier et supprimer toutes ses ressources, et donner accès à d’autres.

Le principe du moindre privilège consiste à donner à chaque identité le rôle minimal, à la portée la plus restreinte, permettant son travail. Pour l’API de billets, c’est AcrPull, sur le registre ticketapi4821 seulement. Si quelqu’un vole l’accès de l’application, il peut récupérer une image, et rien de plus.

Boîtes imbriquées : un locataire, l'annuaire de l'organisation, contient un abonnement, qui contient le groupe de ressources rg-ticket-api-practice. Le groupe contient le registre ticketapi4821, l'application conteneur ticket-api et le Key Vault facultatif kv-ticket-api-4821. Amira, une utilisatrice, a le rôle Owner sur l'abonnement. L'identité managée id-ticket-api a AcrPull sur le registre seulement et, facultativement, Key Vault Secrets User sur le coffre seulement. L'application conteneur récupère son image sous l'identité id-ticket-api.
Chaque attribution de rôle comprend une identité, un rôle et une portée. L'identité de l'application reçoit les rôles minimaux, sur des ressources individuelles. Le rôle Owner d'Amira sur l'abonnement sert à une personne qui crée et supprime des ressources, pas à une application.
Description textuelle du diagramme

Les boîtes montrent les portées, les unes dans les autres : le locataire, qui est l’annuaire de l’organisation, puis l’abonnement, puis le groupe de ressources rg-ticket-api-practice. Le groupe contient trois ressources : le registre ticketapi4821, l’application conteneur ticket-api et le Key Vault facultatif kv-ticket-api-4821. À gauche se trouvent deux identités. Amira, une utilisatrice, a le rôle Owner sur tout l’abonnement, car elle crée et supprime les ressources. L’identité managée id-ticket-api a deux rôles restreints : AcrPull sur le registre seulement et Key Vault Secrets User (utilisateur des secrets Key Vault) sur le coffre facultatif seulement. L’application conteneur n’a aucun rôle propre. Elle récupère son image sous l’identité id-ticket-api.

Au module 5, Amira crée l’identité dans le groupe d’exercice (sortie réelle; les identifiants sont abrégés) :

Terminal (Module 5)
az identity create --resource-group rg-ticket-api-practice --name id-ticket-api -o table
ClientId Location Name PrincipalId ResourceGroup
------------------------------------ ------------- ------------- ------------------------------------ ----------------------
faf6b35b-... canadacentral id-ticket-api d2066809-... rg-ticket-api-practice

Le champ PrincipalId (identifiant du principal) est l’identifiant de l’identité dans le locataire : les attributions de rôles l’utilisent. Elle donne ensuite AcrPull à l’identité, avec le registre comme portée :

Terminal (Module 5)
PRINCIPAL_ID=$(az identity show -g rg-ticket-api-practice -n id-ticket-api --query principalId -o tsv)
REGISTRY_ID=$(az acr show -n ticketapi4821 --query id -o tsv)
az role assignment create --assignee-object-id $PRINCIPAL_ID --assignee-principal-type ServicePrincipal --role AcrPull --scope $REGISTRY_ID -o table

La sortie (colonnes abrégées) :

CreatedOn PrincipalType ResourceGroup Scope
-------------------------------- ---------------- ---------------------- ---------------------------------------------------------------------------------------------------------------
2026-10-07T16:12:09.352851+00:00 ServicePrincipal rg-ticket-api-practice /subscriptions/.../resourceGroups/rg-ticket-api-practice/providers/Microsoft.ContainerRegistry/registries/ticketapi4821

Lisez Scope (portée) de droite à gauche : le registre ticketapi4821, dans le groupe rg-ticket-api-practice, dans un abonnement. C’est la portée la plus restreinte pour un registre. --assignee-principal-type ServicePrincipal indique à Azure le type d’identité. Sans ce paramètre, la commande peut échouer pour une nouvelle identité que le service des rôles ne connaît pas encore.

Quand elle crée l’application, deux paramètres la relient à l’identité. --user-assigned attribue l’identité à l’application. --registry-identity signifie « récupérer depuis le registre sous cette identité ». Le module 5 explique chaque paramètre.

L’utilisateur administrateur du registre : gardez-le désactivé

Section intitulée « L’utilisateur administrateur du registre : gardez-le désactivé »

Le registre a aussi un utilisateur administrateur. L’exécution réelle a montré qu’il est désactivé lors de la création du registre :

NAME RESOURCE GROUP LOCATION SKU LOGIN SERVER CREATION DATE ADMIN ENABLED
------------- ---------------------- ------------- ----- ------------------------ -------------------- ---------------
ticketapi4821 rg-ticket-api-practice canadacentral Basic ticketapi4821.azurecr.io 2026-10-07T16:10:57Z False

L’utilisateur administrateur est un compte partagé pour tout le registre, avec des droits d’envoi et de récupération. Toutes les personnes qui utilisent son mot de passe apparaissent comme le même utilisateur. Vous ne pouvez donc pas savoir qui a fait quoi. Si vous changez le mot de passe, tous les programmes qui l’utilisent s’arrêtent. La documentation de Microsoft présente cette fonction comme servant surtout aux tests effectués par une seule personne. Le cours ne l’active jamais.

L’application a besoin d’un secret : la clé d’API. Vous connaissez déjà deux endroits où elle ne doit jamais se trouver : dans l’image (module 2) et dans Git (le cours sur les API). Dans le nuage, il y a deux bons endroits et un mauvais :

Endroit Comment l’application l’obtient Qui peut lire la valeur Utilisation
Une variable d’environnement ordinaire : --env-vars API_KEY=the-key Comme variable d’environnement Toute personne pouvant lire la configuration de l’application, comme avec docker inspect au module 3 Les paramètres non secrets, comme SHOW_DOCS
Un secret de la plateforme : --secrets api-key=the-key et --env-vars API_KEY=secretref:api-key Comme variable d’environnement, remplie à partir du secret Seulement les identités ayant un rôle permettant de lister les secrets de l’application L’exercice : simple, sans élément supplémentaire à supprimer
Un magasin de secrets : un secret Key Vault et une référence à celui-ci dans l’application La plateforme lit le coffre sous l’identité de l’application et remplit le secret Seulement les identités ayant un rôle Key Vault sur le coffre Un vrai service : un seul endroit pour les secrets, avec des versions et un journal d’accès

secretref: signifie « prendre la valeur du secret portant ce nom ». La configuration de l’application contient alors une référence, pas la clé. L’exécution réelle le montre. az containerapp show liste les noms des secrets, pas leurs valeurs (sortie réelle, abrégée) :

{
"ingress": {"external": true, "port": 8000},
"registries": [{"identity": "/subscriptions/.../userAssignedIdentities/id-ticket-api", "server": "ticketapi4821.azurecr.io"}],
"secrets": ["api-key"]
}

Un secret de la plateforme n’est pas parfait. La documentation de Microsoft avertit que certains rôles intégrés, comme Container Apps Contributor, peuvent lister les valeurs des secrets en clair. Elle recommande une référence Key Vault en production. C’est pourquoi l’option Key Vault est l’exercice supplémentaire ci-dessous.

Exercice supplémentaire facultatif : la clé dans Key Vault

Section intitulée « Exercice supplémentaire facultatif : la clé dans Key Vault »

Un Key Vault est le magasin de secrets d’Azure. Pendant l’exécution réelle, Amira y a aussi déplacé la clé d’API. Voici les étapes et ce qu’elles ont montré. Le module 5 présente cette option comme facultative. Elle coûte quelques opérations et ajoute un élément à nettoyer.

  1. Créez le coffre avec le contrôle d’accès basé sur les rôles (RBAC). La suppression réversible était activée, avec une conservation de 90 jours :

    Name Rbac SoftDelete Retention
    ------------------ ------ ------------ -----------
    kv-ticket-api-4821 True True 90
  2. Accordez-vous le rôle Key Vault Secrets Officer (responsable des secrets Key Vault) sur le coffre pour pouvoir écrire des secrets. Être Owner de l’abonnement ne suffit pas : Owner gère le coffre, mais lire et écrire ses secrets exige un rôle de données Key Vault.

  3. Accordez à l’identité de l’application le rôle Key Vault Secrets User sur le coffre. Ses actions, selon az role definition list :

    "dataActions": [
    "Microsoft.KeyVault/vaults/secrets/getSecret/action",
    "Microsoft.KeyVault/vaults/secrets/readMetadata/action"
    ]

    Elle peut lire les secrets. Elle ne peut pas les écrire ni les supprimer.

  4. Écrivez la clé dans le coffre avec az keyvault secret set. Le premier essai a échoué (voir l’erreur courante ci-dessous). Le deuxième essai, 20 secondes plus tard, a fonctionné.

  5. Remplacez le secret de l’application par une référence : api-key=keyvaultref:https://kv-ticket-api-4821.vault.azure.net/secrets/api-key,identityref:<the identity's ID>. keyvaultref: désigne le secret dans le coffre, et identityref: désigne l’identité qui le lit.

  6. Redémarrez la révision. Ensuite, une requête de classification avec la clé a renvoyé 200, et une mauvaise clé a renvoyé 401.

Après l’étape 5, la configuration de l’application contenait seulement l’adresse du coffre et l’identité, pas la valeur (sortie réelle) :

[
{
"identity": "/subscriptions/.../userAssignedIdentities/id-ticket-api",
"keyVaultUrl": "https://kv-ticket-api-4821.vault.azure.net/secrets/api-key",
"name": "api-key"
}
]

À retenir pour la leçon 3 : un Key Vault supprimé reste en état de suppression réversible pendant 90 jours. Il n’entraîne aucuns frais, mais son nom reste réservé jusqu’à ce que vous le purgiez.

Rédigez le plan d’accès pour la conception de l’exercice. Ajoutez-le à vos notes de la leçon 1.

  1. Listez toutes les identités de la conception. Incluez-vous.
  2. Pour chaque identité, écrivez ce qu’elle doit faire, en une phrase.
  3. Choisissez le rôle intégré minimal pour ce travail. Utilisez AcrPull, Key Vault Secrets User, Key Vault Secrets Officer ou Owner.
  4. Choisissez la portée la plus restreinte : l’abonnement, le groupe de ressources ou une ressource.
  5. Listez chaque secret, son emplacement et les identités pouvant lire sa valeur.
  6. Écrivez quels paramètres ne sont pas secrets.
Afficher un exemple de réponse
Identité Travail à faire Rôle Portée
Vous (Amira) Créer, modifier et supprimer les ressources de l’exercice Owner (ou Contributor) Votre abonnement, ou seulement le groupe d’exercice si quelqu’un d’autre possède l’abonnement
id-ticket-api Récupérer l’image ticket-api:1.1.0 AcrPull Le registre ticketapi4821
id-ticket-api (exercice supplémentaire) Lire la clé d’API dans le coffre Key Vault Secrets User Le coffre kv-ticket-api-4821
Vous (exercice supplémentaire) Écrire la clé d’API dans le coffre Key Vault Secrets Officer Le coffre kv-ticket-api-4821
Secret Emplacement Qui peut lire la valeur
La clé d’API Le secret de la plateforme api-key, utilisé comme API_KEY=secretref:api-key (ou un secret Key Vault) Vous, l’application et les identités ayant un rôle permettant de lister les secrets de l’application (ou des rôles Key Vault sur le coffre)

Non secrets : REQUIRE_API_KEY=true, SHOW_DOCS=false, la région, le nom du registre, l’adresse de l’application. Le plan ne contient aucun mot de passe de registre, car l’utilisateur administrateur reste désactivé.

À vous de jouer : l’application lit un fichier de modèle

Section intitulée « À vous de jouer : l’application lit un fichier de modèle »

Une version ultérieure de l’API charge un fichier de modèle, model.joblib, depuis un conteneur nommé models dans un compte de stockage (Blob Storage). Elle lit seulement le fichier. Modifiez votre plan d’accès pour cette seule condition. Quel rôle, à quelle portée? Que ne donnez-vous pas?

Afficher une réponse

Donnez à id-ticket-api le rôle Storage Blob Data Reader (lecteur de données Blob) à la portée du conteneur models dans le compte de stockage. Un conteneur Blob peut aussi servir de portée. Son action sur les données est Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read : elle permet de lire les objets Blob, rien de plus. Ne donnez pas le rôle Storage Blob Data Contributor (contributeur aux données Blob), qui permet aussi d’écrire et de supprimer des objets Blob. N’accordez pas le rôle sur tout le compte de stockage si d’autres conteneurs contiennent d’autres données. Ne donnez pas à l’application la clé d’accès du compte de stockage. Cette clé est un mot de passe pour tout le contenu du compte.

Erreur courante

Accès interdit, juste après l'attribution du rôle

Symptôme : Lors de l’exécution réelle, le compte personnel d’Amira a reçu le rôle Key Vault Secrets Officer (responsable des secrets Key Vault) sur le coffre. La commande suivante a tenté d’écrire le secret immédiatement, mais elle a échoué :

ERROR: (Forbidden) Caller is not authorized to perform action on resource.
If role assignments, deny assignments or role definitions were changed recently, please observe propagation time.

Cause : Une nouvelle attribution de rôle prend un peu de temps à atteindre toutes les parties d’Azure. C’est ce qu’on appelle la propagation. Le rôle était correct, mais le coffre n’en avait pas encore connaissance.

Solution :

  1. Lisez le message jusqu’à la fin. Ici, il nomme la cause : « observe propagation time » (respectez le délai de propagation).
  2. Attendez, puis exécutez la même commande de nouveau. Lors de l’exécution réelle, elle a fonctionné environ 20 secondes plus tard.
  3. Si elle échoue encore après quelques minutes, vérifiez l’attribution du rôle : la bonne identité, le bon rôle, la bonne portée.
  4. Ne « corrigez » pas le problème avec un rôle plus large, comme Owner (propriétaire) sur l’abonnement. Cela transforme une courte attente en risque durable.

Dans les déploiements automatisés, par exemple en intégration continue, ajoutez une courte attente ou une nouvelle tentative après chaque attribution de rôle. Ainsi, un déploiement correct n’échoue pas parce qu’il était trop rapide.

Vérifiez votre compréhension

Qu'est-ce qu'une identité managée, et pourquoi le cours utilise-t-il une identité attribuée par l'utilisateur plutôt que par le système?

Afficher la réponse

Une identité managée est une identité qu’Azure crée et gère pour une ressource. Elle permet à la ressource de se connecter à d’autres services Azure sans mot de passe. Azure conserve ses informations d’identification, et personne ne les voit. Le cours utilise une identité attribuée par l’utilisateur, car c’est une ressource distincte qui peut exister avant l’application. Amira lui donne d’abord le rôle AcrPull sur le registre. Ainsi, l’application peut récupérer l’image dès son premier démarrage. Une identité attribuée par le système existe seulement après qu’Azure a créé l’application. Elle ne peut donc pas avoir le rôle avant la première récupération.

Vérifiez votre compréhension

Un collègue donne à id-ticket-api le rôle Owner sur l'abonnement, parce que c'est plus rapide. Prévoyez les problèmes possibles et indiquez quoi donner à la place.

Afficher la réponse

Tout ce qui peut utiliser l’identité peut alors créer, modifier et supprimer chaque ressource de l’abonnement, et donner accès à d’autres. Un attaquant qui exécute du code dans le conteneur, ou un bogue, pourrait alors endommager tout l’abonnement, pas seulement une image. Donnez seulement le rôle AcrPull sur le registre ticketapi4821 : le rôle le plus limité, à la portée la plus restreinte (principe du moindre privilège). L’application fonctionne alors de la même façon, et une erreur peut coûter beaucoup moins cher.

Vérifiez votre compréhension

Nommez trois endroits où placer la clé d'API dans la conception infonuagique. Indiquez celui utilisé dans l'exercice et pourquoi.

Afficher la réponse

Une simple variable d’environnement : un mauvais choix, car toute personne qui peut lire la configuration de l’application voit la valeur. Un secret de plateforme (--secrets api-key=... et API_KEY=secretref:api-key) : l’exercice l’utilise, car il garde la valeur hors de la configuration et n’ajoute rien à supprimer. Une référence Key Vault (keyvaultref: avec identityref:) : un meilleur choix pour un service réel. La valeur reste uniquement dans le coffre, et seules les identités avec un rôle Key Vault peuvent la lire. Jamais dans l’image ni dans Git.

Récapitulatif

  • Une identité répond à « qui êtes-vous? ». Une attribution de rôle (identité, rôle, portée) répond à « que pouvez-vous faire, et où? ».
  • Une identité managée permet à une ressource de se connecter sans mot de passe. Une identité attribuée par l’utilisateur peut exister avant l’application et recevoir son rôle en premier.
  • Principe du moindre privilège : le rôle le plus limité, à la portée la plus restreinte. Pour l’API de billets : AcrPull sur un seul registre.
  • Gardez le compte administrateur du registre désactivé. Il utilise un seul mot de passe partagé permettant d’envoyer et de récupérer des images.
  • Placez la clé dans un secret de plateforme (secretref:) ou dans Key Vault (keyvaultref: + identityref:). Jamais dans un simple paramètre, dans l’image ou dans Git. Un secret modifié exige un redémarrage ou une nouvelle révision.
  • Une nouvelle attribution de rôle peut prendre quelques secondes avant de fonctionner. Attendez et réessayez. N’élargissez pas le rôle.

Ensuite, vous repérerez chaque partie de la conception qui peut coûter de l’argent, et comment arrêter chacune.

Leçon suivante : Connaître les coûts