Archives par étiquette : API

Mise en place de l’Azure Function Resourcegroupasaservicepublicapi

La première instance Azure Function était dédiée à une API interne. Maintenant, nouvelle Azure Function dédiée à l’hébergement des API accessibles par les consommateurs. C’est au travers de ces API que les consommateurs pourront :

  • Savoir s’ils ont accès au service Resource Group As a Service
  • Dans quelle souscription pourront-ils demander la création de groupes de ressources
  • Quelles régions Azure sont autorisées
  • Quel CostCenter associer au groupe de ressource
  • Demander la création d’un groupe de ressources

Pour cette nouvelle instance d’Azure Function, j’ai encore fait le choix de la performance e choisissant le mode de fonctionnement « Hosting Plan ». Certes, ça ne fait pas très Server-Less. La création de l’instance est tout ce qu’il y a de plus classique. Un point de détail, le choix du Storage Account associé. J’aurai pu utiliser un seul Storage Account pour mes deux Azure Function mais je voulais maintenir une isolation entre un composant font-end et un composant backend. En plus, de cette manière ce sont des clés d’accès au stockage bien distinctes.

clip_image001

 

Tout comme pour la première instance Azure Function, nous allons uploader le contenu de nos différentes fonctions sous la forme d’un fichier Zip. Quand j’aurai le temps, j’industrialiserai le tout avec un beau template ARM disponible sur mon GitHub.

clip_image002

 

L’importation du contenu se déroule de la même manière que pour la première instance d’Azure Function, pas grand-chose à dire de plus sur ce sujet.

$username = « <Compte FTP> »

$password = « <Mot de passe FTP> »

$filePath = « <emplacement local du fichier resourcegroupasaservicepublicapi.zip> »

$apiUrl = « « 

$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes((« {0}:{1} » -f $username, $password)))

$userAgent = « powershell/1.0 »

Invoke-RestMethod -Uri $apiUrl -Headers @{Authorization=(« Basic {0} » -f $base64AuthInfo)} -UserAgent $userAgent -Method POST -InFile $filePath -ContentType « multipart/form-data »

clip_image003

 

Par contre, c’est au niveau des Applications Settings que cela se complique. Il y en a beaucoup plus à configurer, d’où l’intérêt d’avoir un peu de PowerShell pour réaliser l’opération.

Nom

Contenu

AuthorizationModuleAuthorizeTableName AuthorizedCallers
AuthorizationModuleBackupTagName Backup
AuthorizationModuleCostCenterTagName CostCenter
AuthorizationModuleCreatedOnTagName CreatedOn
AuthorizationModuleDefaultCostCenterTableName DefaultCostCenter
AuthorizationModuleEnvironnementTagname Environnement
AuthorizationModuleIAMTemplateRoleTableName AuthorizedIAMTemplateRole
AuthorizationModuleKeyVault <Nom du groupe de ressources de la solution>
AuthorizationModuleOwnerTagName Owner
AuthorizationModulePolicyAssignmentTableName AuthorizedPolicyAssignment
AuthorizationModuleProjectTagName ProjectName
AuthorizationModuleSLAName SLALevel
AuthorizationModuleStorageAccountMasterKey AuthorizationModuleStorageAccountMasterKey
AuthorizationModuleStorageAccountName Nom du Storage Account de la solution
AuthorizationModuleReadKeyvaletURL <URL API du Key-Valet avec secret>

 

On va distinguer trois types de paramètres :

  • Ceux qui désignent des constantes pour le code des API
  • Ceux qui désignent des Tags
  • Ceux qui sont utilisés pour configurer la solution

 

Dans mon développement, mes constantes, ce sont principalement des noms de table Azure table :

  • AuthorizationModuleAuthorizeTableName : Cette table référence les souscriptions accessibles pour chaque consommateur.
  • AuthorizationModuleIAMTemplateRoleTableName : Nom de la table dans Azure Table qui référence les identités et les rôles à associer lors de la création d’un groupe de ressources pour le Role-Based Access Control
  • AuthorizationModulePolicyAssignmentTableName : Nom de la table dans Azure Table qui référence les Azure Policy à positionner sur les groupes de ressources nouvellement créés.

La solution va positionner des tags sur les groupes de ressources nouvellement créés. En externalisant les noms dans les Applications Settings, je vous permets de personnaliser la solution en fonction de votre environnement.

  • AuthorizationModuleBackupTagName : Nom du tag qui devra être positionné sur le groupe de ressources nouvellement créé pour indiquer le besoin de sauvegarder ou non le contenu du groupe de ressources.
  • AuthorizationModuleCostCenterTagName : Nom du Tag qui devra être positionné sur le groupe de ressources nouvellement créé pour référencer le centre de coût pour la refacturation des usages.
  • AuthorizationModuleCreatedOnTagName : Nom du Tag qui devra être positionné sur le groupe de ressources nouvellement créé pour indiquer la date de création de la ressource (utile pour distinguer des ressources éphémères)
  • AuthorizationModuleDefaultCostCenterTableName : Nom de la table qui référence le CostCenter qui devra être utilisé lors de la création d’un groupe de ressources si le consommateur ne précise rien.
  • AuthorizationModuleEnvironnementTagName : Nom du Tag qui devra être positionné sur le groupe de ressources nouvellement créé pour désigner le type d’environnement (production, dev, …)
  • AuthorizationModuleOwnerTagName : Désigne le nom du Tag qui devra être positionné sur le groupe de ressources nouvellement créé pour désigner le propriétaire / responsable des ressources hébergées/
  • AuthorizationModuleProjectTagName : Nom du Tag qui devra être positionné sur le groupe de ressources nouvellement créé pour regrouper les ressources composant un même projet
  • AuthorizationModuleSLAName : Nom du Tag qui devra être positionné sur le groupe de ressources nouvellement créé pour signaler le niveau de SLA associé aux ressources qui sont contenues dans le groupe de ressources.

 

Il ne nous reste plus que les paramètres propres au fonctionnement de la solution.

  • AuthorizationModuleKeyVault : Désigne le nom de l’instance KeyVault qui a été mise en place pour stocker les secrets de la solution. Dans cette version, on référence le nom. Quand j’aurai un peu de temps, on référencera l’URL complète pour permettre à la solution de fonctionner dans tous les environnements Azure, y compris Azure Stack.
  • AuthorizationModuleStorageAccountMasterKey : Désigne le nom du secret dans l’instance de Key Vault de la solution qui contient la clé primaire du Storage Account qui héberge mes Azure table.
  • AuthorizationModuleStorageAccountName : Désigne le nom du Storage Account qui contient les Azure Table de la solution
  • AuthorizationModuleReadKeyvaletURL : Référence l’URL de l’API Get-ValetKeyforAzureTableRead hébergé par notre première instance Azure Function. Attention à bien référencer l’URL avec la Function Key qui sert de mécanisme d’authentification. Clairement, dans ma todo-list, c’est un truc qu’il faudra réviser pour stocker cette information dans le Key vault.

 

Tout comme pour la première instance, nous allons importer ces Applications Settings en prenant soin de ne pas écraser les paramètres déjà positionnés.

$webapp = Get-AzureRmWebApp -ResourceGroupName ResourceGroupAsAService -Name resourcegroupasaservicepublicapi

$AppSettings = @{}

$AppSettings = $webapp.SiteConfig.AppSettings

$hash = @{}

ForEach ($kvp in $AppSettings) {

$hash[$kvp.Name] = $kvp.Value

}

$hash[‘AuthorizationModuleAuthorizeTableName’] = « AuthorizedCallers »

$hash[‘AuthorizationModuleBackupTagName’] = « BACKUP »

$hash[‘AuthorizationModuleCostCenterTagName’] = « CostCenter »

$hash[‘AuthorizationModuleCreatedOnTagName’] = « CreatedOn »

$hash[‘AuthorizationModuleDefaultCostCenterTableName’] = « DefaultCostCenter »

$hash[‘AuthorizationModuleDisplayName’] = « DisplayName »

$hash[‘AuthorizationModuleEnvironnementTagname’] = « Environnement »

$hash[‘AuthorizationModuleIAMTemplateRoleTable’] = « AuthorizedIAMTemplateRole »

$hash[‘AuthorizationModuleKeyVault’] = « resourcegroupasaservice »

$hash[‘AuthorizationModuleKeyVaultSubscriptionLogin’] = « SubscriptionLogin »

$hash[‘AuthorizationModuleKeyVaultSubscriptionPassword’] = « SubscriptionPassword »

$hash[‘AuthorizationModuleOwnerTagName’] = « Owner »

$hash[‘AuthorizationModulePolicyAssignmentTable’] = « AuthorizedPolicyAssignment »

$hash[‘AuthorizationModuleProjectTagName’] = « ProjectName »

$hash[‘AuthorizationModuleReadKeyvaletURL’] = «  clé>« 

$hash[‘AuthorizationModuleSLAName’] = « SLALevel »

$hash[‘AuthorizationModuleStorageAccountName’] = « resourcegroupasaservice3 »

Set-AzureRMWebApp -ResourceGroupName resourcegroupasaservice -AppServicePlan resourcegroupasaservicepublicapi -Name resourcegroupasaservicepublicapi -AppSettings $hash

clip_image004

 

Pour cette nouvelle instance d’Azure Function, nous allons aussi activer la fonctionnalité Managed Service Identity. La fonctionnalité sera utilisé par l’API Request-ResourceGroup pour extraire les secrets nécessaires de l’instance Key Vault de la solution.

clip_image005

 

Maintenant, la partie la plus intéressante, à savoir la mise en place de l’authentification Azure AD. Comme déjà vu dans le billet Authentifiez vos Azure Function avec Azure AD , nous commençons par activer la fonctionnalité.

clip_image006

 

C’est ici que cela se complique. Après avoir activé la fonctionnalité et exigé l’authentification, nous allons demander la création d’une application Azure AD.

clip_image007

 

A ce niveau, cela implique que notre compte dispose du rôle « Global Administrator » pour déclarer l’application Azure AD. Cette application Azure AD devra disposer de permissions déléguées pour Azure Active Directory.

clip_image008

 

Côté application, c’est OK. Maintenant passons côté utilisateurs. Il faut autoriser nos utilisateurs à accéder à notre application. J’ai retenu de faire simple, tous les utilisateurs de mon Tenant Azure AD seront accrédités à consommer mon application. Plus tard dans le développement de Resource Group as a service, nous introduirons la notion de rôle au sein de l’application (consommateur versus administrateur).

clip_image009

 

C’est maintenant qu’on passe sous la moquette et qu’on sort le PowerShell. Commençons par identifier le Service Principal associé à la fonctionnalité Managed Service Identity pour lui accorder le droit de lire les secrets dans l’instance de Key Vault utilisé par notre solution.

$ADDObject = Get-AzureADServicePrincipal | where {$_.displayname -eq « resourcegroupasaservicepublicapi »}

$ADDObject

Set-AzureRmKeyVaultAccessPolicy -VaultName resourcegroupasaservice -ObjectId $ADDObject.ObjectID -PermissionsToSecrets Get, List

clip_image010

 

A ce stade, les permissions sur notre première instance de KeyVault doivent ressembler à l’illustration ci-dessous :

(Get-AzureRmKeyVault -VaultName resourcegroupasaservice).accesspolicies

clip_image011

 

Cependant, il ne faut pas oublier la seconde instance. Dans mon design j’ai retenu de séparer les secrets de chaque souscription dans des instances de Key Vault séparées. Notre Azure Function portant nos API publique doit pouvoir extraire les secrets (Login & mot de passe) pour se connecter à la souscription Azure donnée :

$AzureADApplication = Get-AzureRmADApplication -DisplayNameStartWith resourcegroupasaservicepublicapi

$AzureADApplication

Set-AzureRmKeyVaultAccessPolicy -VaultName $KeyVaultName -ObjectID $AzureADApplication.ObjectId -PermissionsToSecrets Get

clip_image012

 

Ne reste plus qu’à positionner les secrets dans cette souscription. Pour chaque souscription utilisable par l’API, nous avons une instance de KeyVault dédiée avec toujours les mêmes secrets :

  • SubscriptionLogin
  • SubscriptionPassword

 

$SubscriptionCredential = Get-Credential (Get-AzureRmContext).account.ID

$SubscriptionLoginSecret = ConvertTo-SecureString -String $SubscriptionCredential.username -AsPlainText -Force

Set-AzureKeyVaultSecret -VaultName $KeyVaultName -Name ‘SubscriptionLogin’ -SecretValue $SubscriptionLoginSecret

Set-AzureKeyVaultSecret -VaultName $KeyVaultName -Name ‘SubscriptionPassword’ -SecretValue $SubscriptionCredential.Password

clip_image013

 

Maintenant, ce qui manque, c’est comment l’API va déterminer dans quelle instance de Key Vault se trouve les secrets d’une souscription Azure donnée. Tout simplement en créant un secret ayant comme nom l’identifiant unique de la souscription. Ce secret référencera l’URL de l’instance de Key Vault contenant les secrets pour la souscription. Il ne nous reste donc plus qu’à créer un secret dans l’instance de Key Vault utilisée pour les secrets partagés par les API :

$SubscriptionVault = Get-AzurermKeyVault -VaultName $KeyVaultName -ResourceGroupName $resourcegroupname

$SubscriptionSecret = ConvertTo-SecureString -String $($SubscriptionVault.VaultUri) -AsPlainText -Force

Set-AzureKeyVaultSecret -VaultName resourcegroupasaservice -Name $((Get-AzureRmContext).Subscription.ID) -SecretValue $SubscriptionSecret

clip_image014

 

D’un point de vue technique, l’API est maintenant en place. Prochaine étape, consommer nos différentes API avec Postman.

BenoîtS – Simple and Secure by Design but Business compliant

Azure API Management 4/5 – C’est l’heure de consommer

Nous avons une API exposée avec des nouvelles fonctionnalités :

  • Point d’accès unique pour toutes mes futures API
  • Une méthode d’authentification unique pour toutes mes API
  • Une journalisation centralisée et non plus gérée au niveau de chaque API
  • Une politique de limitation d’usage

 

La prochaine étape, c’est donc nécessairement de consommer. Azure API Management est capable de s’interfacer avec bon nombre de systèmes d’authentification. Dans le contexte de cette série de billets, nous allons utiliser le fournisseur d’identité par défaut. Chaque utilisateur doit disposer d’un compte et d’un mot de passe pour accéder au service. On peut soit créer des utilisateurs ou les inviter. L’avantage de l’invitation, c’est que c’est l’invité qui sera chargé de configurer son mot de passe. J’ai donc retenu de lui envoyer une invitation.

clip_image002

 

Le client de ma licorne reçoit un mail qui l’invite à se connecter au portail. A noter que ces éléments de communication (template de mails) sont configurables dans Azure API Management.

clip_image004

 

Point d’attention, la politique de mot de passe d’Azure API Management est assez pointue. N’essayez pas d’utiliser des séquences continues dans vos mots de passe.

clip_image006

 

Une fois authentifié, on arrive sur le portail développeurs de notre instance du service Azure API Management. Dans la rubrique « Products », on constate qu’il nous est proposé la souscription d’un service. La notion de souscription à un produit est importante car pour chaque souscription de produit, une paire de clés d’accès est générée.

clip_image008

 

Au sens Azure API Management, un produit permet aux futurs clients de ma licorne de souscrire à nos API. Dans l’exemple ci-dessous, Azure API Management va imposer une Policy qui limite le nombre d’appels par minutes / semaines. Dans mon Business plan de la mort qui tue, j’ai un mode gratuit mais faut pas non plus qu’il me coute les yeux de la tête. Pour l’instant, il n’y a qu’une seule API.

clip_image009

 

Il est possible de personnaliser le nom de chaque souscription réalisée. C’est intéressant si on souscrit plusieurs fois au même produit.

clip_image011

 

C’est souscrit, pour accéder à mon API, je peux constater que j’ai deux clés.

clip_image013

 

En tant que client consommateur de l’API, je peux aussi référencer ma propre application qui va changer la face du monde.

clip_image015

 

Je peux la soumettre à publication, reste à voir si l’administrateur de l’Azure API Management service est prêt à m’aider à démarrer et qui sait devenir demain le nouveau Facebook 3.0.

clip_image017

 

Nous approchons de la fin de cette série de billets. Ne nous reste plus qu’à nous placer en tant que client pour consommer notre API. Ce sera le sujet du dernier billet.

 

BenoîtS – Simple and secure by design but Business compliant (with disruptive flag enabled)

Azure API Management 3/5 – Exposition de notre première API

A partir de maintenant, tout va se passer dans Azure API Management. Notre Azure Function est prête à être référencée comme API. Dans l’interface de gestion du service, en cliquant sur « API », on arrive à l’interface ci-dessous :

clip_image001

Azure API Management prend en charge plusieurs langages de description pour nos API. Par chance, l’intégration avec Azure Function est nativement supportée ou presque. L’interface nous propose bien de sélectionner notre Function App (ce qui porte notre fonction) mais pas la fonction en elle-même. C’est pour cela que je spécifie le paramètre API Url suffixe correspondant le nom de la fonction.

clip_image002

Autre sujet important, l’accès authentifié à notre Azure Function. Pour rappel, chaque fonction que nous avons développée dispose de sa propre URL et clé d’accès :

clip_image003

Si je ne fais rien, aucune authentification sera présentée à mon Azure Function. Il faut donc pouvoir intégrer ce code d’authentification dans l’appel depuis Azure API Management. Vu que c’est un secret, on va commencer par le stocker dans une Named Value. Au moment de l’écriture de cette série de billets, il n’est pas encore possible de stocker ses secrets dans un Azure KeyVault. A ce jour, c’est un feedback qui a été remonté à Microsoft : Integration with Azure KeyVault. En attendant KeyVault, nous allons utiliser les Named Values.

clip_image004

Azure API Management permet d’injecter des paramètres additionnels dans le Header. C’est une des nombreuses fonctionnalités offertes par les Azure Policies d’Azure API Management. Nous allons travailler au niveau « Inbound Processing »

clip_image005

Notre opération consistera à ajouter un nouveau paramètre à notre requête HTTP. Pour éditer ma policy, je suis passé en mode « Code-View » pour intégrer une règle de transformation nommée « Set query request parameter ». De cette manière, on va injecter le paramètre « Code » avec la valeur contenue dans la Named Value {{AzureFunctionAPICode}}. Reste à ne pas oublier de cliquer sur le bouton Save.

clip_image006

De retour dans la view « From View », c’est plus simple à comprendre.

clip_image007

Attention, l’utilisation du Named Parameters, dans la vue form view ne conservera pas le named parameters mais va juste remplacer le contenu. D’ou le passage en mode « Form View ».

BenoîtS – Simple and secure by design but Business compliant (with disruptive flag enabled)

Azure API Management 2/5 – Préparer l’exposition de notre Azure Function

Notre service Azure API Management est maintenant posé. Nous allons y revenir. Pour commencer, nous allons rendre notre Azure Function consommable par mon service API Management. Il faut un peu de préparation. A ce stade, il manque une description contenant :

  • Ce que produit notre API
  • Les paramètres qu’elle attend en entrée
  • Les paramètres qu’elle retourne
  • La ou ses différentes versions

Première étape, on va commencer par limiter ce que va accepter notre Azure Function en termes de verbes. Au niveau du nœud « Integrate » de notre fonction. Nous allons affiner la listes méthodes HTTP pour ne retenir que POST sans oublier de sauvegarder notre modification.

clip_image001

 

Prochaine étape, documenter notre API. Dans le contexte Azure Function, c’est le Framework Swagger qui a été retenu par Microsoft pour l’intégration avec Azure API management. Le Framework Swagger utiliser les spécifications OpenAPI. Allons configurer la définition de notre API en cliquant sur « API Definition ».

clip_image002

 

Azure Function peut être exposé sous forme d’API de deux manières :

  • Function (Preview pour l’intégration avec Azure API Management)
  • External URL (Utilisation d’un service tierce)

 

Azure API Management étant un service interne Azure, nous allons cliquer sur « Function (Preview) ».

clip_image003

 

Remarque importante, cela ne change strictement rien sur la méthode d’authentification de notre Azure Function. Nous pouvons toujours la solliciter ne direct dès lors que nous disposons de toutes les informations. C’est un sujet sur lequel nous allons revenir dans un prochain billet de la série.

clip_image004

 

Pour décrire notre API, nous allons utiliser les spécifications OpenAPI. L’intégration avec Azure est bien faite puisqu’on nous propose de créer un squelette JSON en cliquant sur le bouton « Generate API Definition template ».

clip_image005

 

OpenAPI va nous permettre de produire une description qui sera consommée par Azure API Management. Heureusement que mon API est simple. Globalement, j’ai indiqué :

  • Que mon API ne supportera que le HTTPS pas le HTTP
  • Que mon API ne supportait que la méthode POST via une URL bien précise
  • Qu’elle consomme ses paramètres au format JSON (même s’il n’y en a pas dans mon exemple)
  • Quelle produira du contenu au format JSON avec un seul message documenté

clip_image006

 

N’oubliez pas d’appuyer sur « Save ».

Avant d’aller plus loin dans l’intégration, nous allons déjà valider que cela fonctionne. Pour cela nous avons besoin d’une clé d’accès pour notre Azure Function. Dans le nœud « Manage » de notre Azure Function, nous allons récupérer une clé d’authentification en cliquant sur le bouton « Copy ».

clip_image007

 

De retour dans la configuration de la définition de notre API, dans la zone droite de l’interface, nous avons la possibilité de valider l’accès à notre future API. Cliquons sur « Change Authentication ».

clip_image008

 

Dans l’interface ci-dessous, nous allons renseigner la clé d’accès précédemment obtenus puis cliquer sur le bouton « Authenticate ».

clip_image009

 

Un peu plus bas dans l’interface, on constate la présence de la description de la seule méthode supportée par notre API : « Post ». En cliquant sur « Try this operation », nous allons réaliser un appel à notre future API avec la clé d’authentification.

clip_image010

 

Côté Request, mon API étant assez simpliste (aucun paramètre en entrée), ayant limité les choix d’utilisation à HTTPS seulement et imposé le JSON pour les paramètres, il ne nous reste qu’à appuyer sur le bouton « Send Request ».

clip_image011

 

Si tout se passe bien, nous devrions avoir le résultat retourné par notre Azure Function.

clip_image012

 

Côté Azure Function, les prérequis sont en place. Prochaine étape, l’exposition de notre première API.

BenoîtS – Simple and secure by design but Business compliant (with disruptive flag enabled)