Azure API Management est un service Azure sécurisé, fiable et scalable permettant de publier, consommer et gérer des APIs. Cette plateforme permet de renforcer la sécurité et d'analyser l'usage des APIs.

Selon les projets, proposer un front-end pour ses ressources peut répondre à plusieurs besoins:

  1. Gestion de la sécurité directement depuis API Management afin de restreindre l'accès aux ressources à différentes applications ou utilisateurs.
  2. Transformer les accès aux ressources. Aggréger plusieurs ressources en une seule réponse GET par exemple.
  3. Gérer le cache des réponses afin d'alléger les requêtes au Storage.

 

Scénario

Dans cet article, nous allons voir ensemble l'implémentation d'une API permettant de télécharger des Blobs privés depuis Azure Storage. Nous n'aborderons pas la sécurisation de cet API puisque celle-ci pourrait faire l'objet d'un article à part entière.

 

Azure Storage REST API

Nous allons commencer par créer un Compte de Stockage ou Storage Account.

La sécurisation globale de ce compte de stockage est définie dans l'onglet Settings >> Access Keys.

Notez bien comment récupérer la clé Key car elle vous sera utile dans la configuration de votre API.

 

 

Dans de compte nous allons créer un Blob Container. Lors de la création du container, veillez à saisir Public access level  : Private (no anonymous access)

 

Dans ce container, nous allons ajouter un fichier qui sera celui que nous essaierons de télécharger à la fin de cet article.

Pour cela, dans le container, cliquez sur le bouton Upload et laissez vous guider.

 

API Management

Partons du postulat que vous avez déja créé votre ressource API Management puisque celle-ci prend environ 45 minutes à être provisionnée :S

Il vous faut désormais créer une API que l'on appelera "Storage". Lors de la création de votre API, renseignez https://{storageAccountName}.blob.core.windows.net dans la propriété Web Service URL.

Notez également la propriété API URL Suffix, surtout si vous la customisez, puisqu'elle fera partie de la route d'accès à vos ressources.

Ouvrez ensuite votre API, sélectionnez Add Operation et créez une opération avec comme URL GET + /{container}/{blob}.

 

Vous avez désormais une API qui répond aux requêtes entrantes et les redirige vers l'API Blobs d'Azure Storage mais à ce stade, si vous tentez de la consommer vous recevrez une erreur d'authentification.

 

Policy

Nous avons défini une sécurité pour notre container dans Azure Storage (Authentication Type SAS). Nous allons donc désormais indiquer à notre API comment utiliser cette SAS Key pour authentifier les requêtes faites aux ressources.

Sélectionnez votre API puis l'opération créée auparavant et, dans l'onglet Design, sélectionnez le bouton Policies pour passer en mode édition.

La partie inbound correspond aux traitements effectuées sur les requêtes entrantes et c'est ici que nous allons travailler.

Nous allons commencer par définir des variables :

<set-variable name="APIVersion" value="2012-02-12" />
<set-variable name="RequestPath" value="@(context.Request.Url.Path)" />
<set-variable name="UTCNow" value="@(DateTime.UtcNow.ToString("R"))" />

 

Nous allons ensuite ajouter un header date aux requêtes entrantes :

<set-header name="date" exists-action="override">
<value>@(context.Variables.GetValueOrDefault<string>("UTCNow"))</value>
</set-header>
 

Enfin nous ajouterons un header Authorization : 

<set-header name="Authorization" exists-action="override">
<value>@{
var account = "storageproxy";
var key = "QOQDHuUMSB9ztzLn49SUph3LpL2gIjVXpfkpOuy8855kkOdMvlvgz7mJ9S2F6zPgN6nCSPdiy0+AgHQFeetBmQ==";
var splitPath = context.Variables.GetValueOrDefault<string>("RequestPath").Split('/');
var container = splitPath.Reverse().Skip(1).First();
var file = splitPath.Last();
var dateToSign = context.Variables.GetValueOrDefault<string>("UTCNow");
var stringToSign = string.Format("GET\n\n\n{0}\n/{1}/{2}/{3}", dateToSign, account, container, file);
string signature;
var unicodeKey = Convert.FromBase64String(key);
using (var hmacSha256 = new HMACSHA256(unicodeKey))
{
var dataToHmac = Encoding.UTF8.GetBytes(stringToSign);
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
var authorizationHeader = string.Format(
"{0} {1}:{2}",
"SharedKey",
account,
signature);
return authorizationHeader;
}</value>
</set-header>
 

Vous remplacerez bien évidemment les variables account et key par le nom du StorageAccount et la clef SAS définis dans l'étape du Storage.

Les autres lignes du script consistent à récupérer la requêtes entrante, à convertir la SAS Key en signature et à ajouter cette SharedKey composée en tant que header Authorization.

La requête ainsi modifiée est ensuite transmise à l'API de Storage qui en reconnaît l'authentificatione et renvoie la ressource demandée.

 

Test du proxy

Une fois toutes ces étapes suivies, vous devriez vous retrouver avec une API consommable depuis n'importe quel client (navigateur, Postman, etc.) permettant de télécharger vos ressources depuis une url dynamique:

http://{apiManagementUrl}/{apiUrlSuffix}/{container}/{blob}

 

Conclusion

Nous avons vu ensemble comment proxyfier des ressources Azure Storage via une API dans Azure API Management.

Avec cette logique, vous proposez aux utilisateurs ou applications clientes un accès aux ressources agnostique de la plateforme de ressources sous-jacente. Vous pouvez alors désormais gérer votre logique de cache, de connexion aux storages (SPN, MSI ?), apporter de l'intelligence fonctionnelle ou même switcher vers un autre provider sans douleur pour les clients.

 

Aller plus loin

Plusieurs pistes d'évolution et d'amélioration pour votre proxy:

  • Ajouter une authentification type JWT sur vos API pour éviter que ce soit open-bar
  • Appliquer la Policy sur l'API au lieu de l'opération afin qu'elle s'applique sur d'autres opérations
  • Utiliser les NamedValues d'API Management pour stocker vos variables account, key, etc.
  • Utiliser un SPN ou MSI pour éviter de stocker votre SAS Key dans API Management

Comments


Comments are closed