Contournement des stratégies d'accès conditionnel d'Entra ID pour le déploiement de clusters AKS privés avec l'identité managée Azure et des runners auto-hébergés
Cette preuve de concept valide que l'identité managée Azure contourne les stratégies d'accès conditionnel (AC) d'Entra ID lors du déploiement de clusters AKS privés.
Les organisations ayant des stratégies AC strictes basées sur la localisation peuvent utiliser l'identité managée pour éviter les échecs d'authentification qui surviennent avec les principaux de service. Le PoC déploie un cluster AKS entièrement privé depuis un runner GitHub Actions auto-hébergé à l'intérieur du même VNet, démontrant la connectivité privée de bout en bout et le contournement de l'AC.
L'authentification par principal de service lors de la création AKS est bloquée par les stratégies d'accès conditionnel basées sur la localisation.
Lorsque le fournisseur de ressources AKS s'authentifie avec les informations d'identification d'un principal de service lors de l'exécution de az aks create, la connexion provient des adresses IP des centres de données Azure, et non du réseau du client. Si l'organisation applique des stratégies d'accès conditionnel qui restreignent l'authentification aux adresses IP du périmètre connu, ces stratégies bloquent la connexion du principal de service.
FLUX PRINCIPAL DE SERVICE (PROBLÉMATIQUE) :
VM Runner → az login --service-principal → login.microsoftonline.com (depuis IP du runner ✓)
VM Runner → az aks create → ARM → AKS RP → login.microsoftonline.com (depuis IP du centre de données Azure ✗)
↑ BLOQUÉ par l'AC
FLUX IDENTITÉ MANAGÉE (RECOMMANDÉ) :
VM Runner → az login --identity → IMDS 169.254.169.254 (interne, pas d'AC ✓)
VM Runner → az aks create → ARM → AKS RP → jeton Azure fabric (interne, pas d'AC ✓)
↑ NON évalué par l'AC
La distinction est architecturale : les identités managées ne déclenchent pas l'accès conditionnel car leurs informations d'identification sont gérées par Azure et l'émission de jetons s'effectue au sein de l'infrastructure Azure. Il n'y a pas d'« adresse IP source » à évaluer par l'AC.
L'identité managée contourne entièrement l'accès conditionnel — les jetons sont acquis en interne via IMDS, et non via login.microsoftonline.com.
« Les identités managées ne sont pas couvertes par les stratégies. » — Documentation Microsoft sur l'accès conditionnel pour les identités de charge de travail
Les jetons MI sont acquis via 169.254.169.254 — un point de terminaison interne de l'infrastructure Azure. Aucune connexion externe ne se produit.
Le moteur d'accès conditionnel n'évalue pas du tout les demandes de jetons d'identité managée. Aucune adresse IP source n'est exposée pour évaluation.
Une VM runner auto-hébergée dans le même VNet que le cluster AKS assure l'accès API privé et l'authentification basée sur IMDS.
Workflow à trois tâches sur deux types de runners : hébergé par GitHub pour le provisionnement de l'infrastructure, auto-hébergé pour le déploiement AKS privé.
graph TD
A["GitHub workflow_dispatch"] -->|ubuntu-latest| B["Tâche 1 : Configuration de l'infrastructure"]
B --> B1["Créer VNet\nsubnet-aks + subnet-runner"]
B1 --> B2["Créer MI + RBAC"]
B2 --> B3["Créer VM Runner\ndans subnet-runner"]
B3 --> B4["Enregistrer le runner GH Actions"]
B4 -->|runner auto-hébergé| C["Tâche 2 : Déploiement + Validation"]
C --> C1["az login --identity via IMDS"]
C1 --> C2["az aks create\n--enable-private-cluster\ndans subnet-aks"]
C2 --> C3{"Déploiement OK ?"}
C3 -->|Oui| C4["kubectl get nodes\nvia point de terminaison privé"]
C4 --> C5["Journaliser les IP + Téléverser les artéfacts"]
C3 -->|Non| C5
C5 --> C6["Attendre N minutes"]
C6 --> C7["Supprimer le RG AKS"]
C7 -->|ubuntu-latest| D["Tâche 3 : Nettoyage"]
D --> D1["Désenregistrer le runner"]
D1 --> D2["Supprimer le RG d'infrastructure"]
style A fill:#1e1b4b,stroke:#4f46e5,color:#e6edf3
style B fill:#1e3a5f,stroke:#3b82f6,color:#e6edf3
style C fill:#3b0764,stroke:#7c3aed,color:#e6edf3
style D fill:#4a1530,stroke:#e11d48,color:#e6edf3
style C3 fill:#78350f,stroke:#d97706,color:#e6edf3
style C4 fill:#064e3b,stroke:#059669,color:#e6edf3
graph LR
subgraph VNET["VNet partagé — 10.224.0.0/16"]
direction LR
subgraph SAKS["subnet-aks\n10.224.0.0/24"]
AKS["Cluster AKS privé\nAPI : 10.224.0.4\nNœud : 10.224.0.5"]
end
subgraph SRUNNER["subnet-runner\n10.224.1.0/24"]
RUNNER["VM Runner\n10.224.1.4"]
end
RUNNER -->|"point de terminaison privé"| AKS
end
RUNNER -->|"IMDS\n169.254.169.254"| FABRIC["Azure Fabric\nÉmission de jetons"]
style VNET fill:#0c1929,stroke:#3b82f6,stroke-width:2px,color:#e6edf3
style SAKS fill:#1a0a2e,stroke:#7c3aed,color:#e6edf3
style SRUNNER fill:#0a2e1e,stroke:#059669,color:#e6edf3
style FABRIC fill:#1e1b4b,stroke:#4f46e5,color:#e6edf3
graph LR
A["VM Runner"] -->|"az login --identity"| B["IMDS\n169.254.169.254"]
B -->|"jeton MI"| C["Azure Fabric"]
A -->|"az aks create"| D["ARM"]
D --> E["AKS RP"]
E -->|"MI du cluster via IMDS"| C
style A fill:#0a2e1e,stroke:#059669,color:#e6edf3
style B fill:#1e1b4b,stroke:#4f46e5,color:#e6edf3
style C fill:#064e3b,stroke:#059669,stroke-width:2px,color:#e6edf3
style D fill:#1e293b,stroke:#64748b,color:#e6edf3
style E fill:#1e293b,stroke:#64748b,color:#e6edf3
Cycle de vie de l'infrastructure entièrement automatisé — provisionnement, déploiement, validation et nettoyage en une seule exécution de workflow.
Un workflow à trois tâches déclenché par workflow_dispatch :
S'exécute sur ubuntu-latest via OIDC. Crée un VNet partagé avec deux sous-réseaux, provisionne une identité managée avec RBAC, crée une VM runner et l'enregistre comme runner auto-hébergé.
S'exécute sur le runner auto-hébergé. S'authentifie via l'identité managée (IMDS), déploie un AKS privé dans subnet-aks, valide avec kubectl, journalise les IP et téléverse les artéfacts.
S'exécute sur ubuntu-latest. Désenregistre le runner, supprime les groupes de ressources AKS et d'infrastructure. S'exécute toujours, même en cas d'échec.
Un workflow déclenché manuellement qui recherche les groupes de ressources correspondant au modèle rg-aks-poc-* datant de plus de 45 minutes. Sert de filet de sécurité pour les ressources orphelines.
Les 3 tâches ont réussi. Objectifs du PoC confirmés. Exécution du workflow #23919580744
| Tâche | Runner | Durée | Résultat |
|---|---|---|---|
| setup-runner | ubuntu-latest | 7 min | ✅ Succès |
| deploy-and-log | self-hosted (dans le VNet) | 40 min (incl. 30 min d'attente) | ✅ Succès |
| teardown-runner | ubuntu-latest | 18 sec | ✅ Succès |
Le journal d'activité Azure confirme que l'opération d'écriture ARM az aks create provient de l'adresse IP 20.104.78.99 — l'adresse IP publique de la VM runner. L'authentification s'est effectuée via IMDS, et non via login.microsoftonline.com. Aucune évaluation d'AC n'a été déclenchée.
Extrait du journal d'activité : Microsoft.ContainerService/managedClusters/write Accepted ClientIp: 20.104.78.99 Microsoft.ContainerService/managedClusters/write Started ClientIp: 20.104.78.99
enablePrivateCluster : true privateFqdn : aks-poc-23-...privatelink.canadacentral.azmk8s.io API Server Endpoint : https://...privatelink.canadacentral.azmk8s.io:443 Le FQDN privé résout : 10.224.0.4 (adresse IP privée au sein du VNet)
kubectl cluster-info → Plan de contrôle Kubernetes à ...privatelink.canadacentral.azmk8s.io:443 kubectl get nodes → 1 nœud, Ready, v1.34.4 kubectl get pods -n kube-system → 15 pods, tous en cours d'exécution kubectl get namespaces → default, kube-node-lease, kube-public, kube-system nslookup FQDN privé → 10.224.0.4 ✓
| Fichier de journal | Contenu |
|---|---|
| runner-network.log | IP publique/privée de la VM runner, nom d'hôte, sous-réseau |
| aks-create.log | Sortie complète de az aks create (9 Ko) |
| aks-cluster-info.log | Propriétés du cluster (version, FQDN, configuration réseau) |
| kubectl-validation.log | Toute la sortie kubectl incluant la résolution DNS |
| ip-activity-log.log | IP des appelants des opérations ARM du journal d'activité Azure |
| ip-signin-log.log | Requête de connexion Entra (erreur 403 attendue sans P1/P2) |
Exécutez le PoC dans votre abonnement en quelques minutes.
Contributeur + Administrateur de l'accès utilisateur au niveau de l'abonnementGH_PAT) avec le scope repomainContributeur + Administrateur de l'accès utilisateur au niveau de l'abonnementAZURE_CLIENT_ID — Identifiant client de l'enregistrement d'applicationAZURE_TENANT_ID — Identifiant du locataire Entra IDAZURE_SUBSCRIPTION_ID — Identifiant de l'abonnement cibleGH_PAT — PAT GitHub avec le scope repo⚠️ Important : La tâche 3 du workflow s'exécute toujours (même en cas d'échec) et supprime les groupes de ressources AKS et d'infrastructure. Le nettoyage manuel n'est nécessaire que si le workflow lui-même est annulé avant l'exécution de la tâche 3.
Chaque exécution de PoC de 30 minutes coûte environ 0,05 $ à 0,08 $ avec un seul nœud Standard_B2s sur le plan de contrôle AKS gratuit. La VM runner ne fonctionne que pendant la durée du workflow et est automatiquement supprimée.
Documentation officielle et dépôt source.
| Ressource | Lien |
|---|---|
| Dépôt source | aks-private-deployment |
| Clusters AKS privés Azure | learn.microsoft.com |
| Utiliser l'identité managée avec AKS | learn.microsoft.com |
| Accès conditionnel pour les identités de charge de travail | learn.microsoft.com |