- Azure
- Azure API Management
- Azure Open AI
- Terraform
Dans ce tutoriel, vous allez configurer la communication entre API Management (APIM) et Azure Open AI à l’aide d’une identité managée et Terraform !
Par défaut, pour accéder aux services Azure Open AI, vous devez utiliser une clé d’accès ainsi qu’un endpoint. Cependant, ce macanisme peut être exposé dans l’application client, ce qui constitue un risque pour la sécurité. Pour éviter cela, vous pouvez utiliser une identité managée pour vous authentifier auprès du service backend. Dans ce tutoriel, vous utiliserez Terraform pour créer une APIM, ajouter une API basée sur la documentation Swagger d’OpenAI, et attribuerez un rôle à l’APIM. Vous ajouterez également une policy à l’APIM pour utiliser son identité managée pour s’authentifier auprès de la ressource Azure Open AI.
## De quoi avez-vous besoin?
Pour pouvoir réaliser entièrement ce tutoriel vous aurez besoin de :
Dans un nouveau dossier, créons un fichier provider.tf
et déclarez le provider azurerm
:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "3.105.0"
}
}
backend "local" {}
}
provider "azurerm" {
features {
}
}
Ensuite, créez un fichier variables.tf
et déclarez les variables que vous utiliserez dans ce tutoriel :
variable "application" {
default = "app"
description = "Name of the application"
type = string
}
variable "environment" {
description = "The environment deployed"
type = string
default = "dev"
validation {
condition = can(regex("(dev|stg|pro)", var.environment))
error_message = "The environment value must be a valid."
}
}
variable "region" {
description = "Azure deployment region"
type = string
default = "we"
}
variable "location" {
description = "Azure deployment location"
type = string
default = "westeurope"
}
variable "owner" {
description = "The name of the project's owner"
type = string
default = "me"
}
variable "resource_group_name_suffix" {
type = string
default = "01"
description = "The resource group name suffix"
validation {
condition = can(regex("[0-9]{2}", var.resource_group_name_suffix))
error_message = "The resource group name suffix value must be two digits."
}
}
variable "tags" {
type = map(any)
description = "The custom tags for all resources"
default = {}
}
Sur cette base, vous pouvez créer un fichier locals.tf
et déclarer les locals que vous utiliserez dans ce tutoriel :
locals {
resource_suffix = [lower(var.environment), lower(var.region), substr(lower(var.application), 0, 3), substr(lower(var.owner), 0, 3), var.resource_group_name_suffix]
resource_suffix_kebabcase = join("-", local.resource_suffix)
chat_model_name = "gpt-35-turbo"
tags = merge(
var.tags,
tomap(
{
"Owner" = var.owner,
"Environment" = var.environment,
"Region" = var.region,
"Application" = var.application
}
)
)
}
Comme vous pouvez le voir, vous disposez d’un resource_suffix
et d’un resource_suffix_kebabcase
pour générer un nom unique pour vos ressources. De plus, comme le balisage des ressources est important, vous avez fusionné les tags
par défaut avec les tags d’entrée.
Créez un fichier rg.tf
et déclarez le groupe de ressources que vous utiliserez pour y mettre toutes les ressources :
resource "azurerm_resource_group" "this" {
name = format("rg-%s", local.resource_suffix_kebabcase)
location = var.location
tags = local.tags
}
Maintenant, vous devez créer une APIM et une API basée sur la documentation Swagger d’OpenAI. Le bloc identity
dans ce code définit le type d’identité sur SystemAssigned
, ce qui signifie qu’Azure gérera automatiquement l’identité de cette APIM.
Dans un fichier apim.tf
, vous pouvez déclarer la ressource comme suit :
resource "azurerm_api_management" "this" {
name = format("apim-%s", local.resource_suffix_kebabcase)
location = azurerm_resource_group.this.location
resource_group_name = azurerm_resource_group.this.name
publisher_name = "Me"
publisher_email = "admin@me.io"
sku_name = "Developer_1"
tags = local.tags
identity {
type = "SystemAssigned"
}
}
Ensuite, définissons une API basée sur la documentation Swagger d’OpenAI. Le bloc de code Terraform suivant configure une API dans l’APIM’. Le fichier de spécification se trouve dans la documentation officielle Azure Open AI Swagger ou dans le dépôt GitHub de ce tutoriel.
En supposant que le fichier Swagger se trouve dans un répertoire assets
, vous pouvez utiliser le code suivant pour lire le fichier et l’importer dans l’APIM.
data "template_file" "open_ai_spec" {
template = file("${path.module}/assets/api_spec/open_ai_spec.json")
}
Ensuite, vous pouvez ajouter l’API à l’aide du code suivant :
resource "azurerm_api_management_api" "open_ai" {
name = "api-azure-open-ai"
resource_group_name = azurerm_resource_group.this.name
api_management_name = azurerm_api_management.this.name
revision = "1"
display_name = "Azure Open API"
path = "openai"
protocols = ["https"]
import {
content_format = "openapi+json"
content_value = data.template_file.open_ai_spec.rendered
}
}
L’API est maintenant créée et importée dans l’APIM. Déployons la ressource Azure Open AI. Placez toutes les ressources liées à Azure Open AI dans un fichier open_ai.tf
.
resource "azurerm_cognitive_account" "open_ai" {
name = format("oai-%s", local.resource_suffix_kebabcase)
location = azurerm_resource_group.this.location
resource_group_name = azurerm_resource_group.this.name
kind = "OpenAI"
sku_name = "S0"
tags = local.tags
custom_subdomain_name = format("oai-%s", local.resource_suffix_kebabcase)
identity {
type = "SystemAssigned"
}
}
resource "azurerm_cognitive_deployment" "chat_model" {
name = local.chat_model_name
cognitive_account_id = azurerm_cognitive_account.open_ai.id
model {
format = "OpenAI"
name = local.chat_model_name
version = "0301"
}
scale {
type = "Standard"
capacity = 5
}
}
Lors du déploiement du service Azure Open AI, il est important de spécifier un domaine personnalisé pour pouvoir accéder correctement au service. Le custom_subdomain_name
peut être le même nom que celui donné au service Azure Open AI.
L’étape suivante consiste à déclarer le service Azure Open AI en tant que service backend dans l’APIM:
resource "azurerm_api_management_backend" "open_ai" {
name = "azure-open-ai-backend"
resource_group_name = azurerm_resource_group.this.name
api_management_name = azurerm_api_management.this.name
protocol = "http"
url = format("%sopenai", azurerm_cognitive_account.open_ai.endpoint)
}
Comme vous pouvez le voir, l’url est le endpoint du service Azure Open AI qui se termine par un /
combiné avec le path openai
.
Enfin, vous pouvez attribuer le rôle Cognitive Services OpenAI User
à l’identité managée de l’APIM. Ce rôle lui donne les autorisations dont elle a besoin pour interagir avec le service Azure Open AI. Dans un fichier role.tf
, vous pouvez déclarer l’attribution du rôle :
resource "azurerm_role_assignment" "this" {
scope = azurerm_cognitive_account.open_ai.id
role_definition_name = "Cognitive Services OpenAI User"
principal_id = azurerm_api_management.this.identity[0].principal_id
}
Vous pouvez ensuite ajouter une policy à l’API pour utiliser son identité managée pour vous authentifier auprès du service Azure Open AI. Ce bloc XML ci-dessous définit plusieurs policy sur la façon dont les requêtes et les réponses doivent être traitées.
<policies>
<inbound>
<set-backend-service backend-id="azure-open-ai-backend" />
<authentication-managed-identity resource="https://cognitiveservices.azure.com" output-token-variable-name="msi-access-token" ignore-error="false" />
<set-header name="Authorization" exists-action="override">
<value>@("Bearer " + (string)context.Variables["msi-access-token"])</value>
</set-header>
<base />
</inbound>
<backend>
<forward-request />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
La policy set-backend-service
spécifie le service backend à utiliser pour l’API, dans ce scénario, le service Azure Open AI.
La policy authentication-managed-identity
spécifie que votre APIM doit utiliser son identité managée pour s’authentifier auprès du service Azure Open AI. La policy set-header
ajoute un header d’Authorization
à chaque requête, en utilisant l’access token obtenu à partir de l’authentification de l’identité managée. L’élément base
dans chaque section inclut les politiques par défaut pour ces sections. Pour plus de détails concernant cette policy, consultez la documentation officielle.
En supposant que cette stratégie se trouve dans le répertoire assets
, vous pouvez utiliser le code suivant pour lire le fichier et l’importer dans l’APIM.
data "template_file" "global_open_ai_policy" {
template = file("${path.module}/assets/policies/global_open_ai_policy.xml")
}
Enfin, vous pouvez appliquer cette policy à l’API à l’aide du code suivant :
resource "azurerm_api_management_api_policy" "global_open_ai_policy" {
api_name = azurerm_api_management_api.open_ai.name
resource_group_name = azurerm_resource_group.this.name
api_management_name = azurerm_api_management.this.name
xml_content = data.template_file.global_open_ai_policy.rendered
}
Initialisons Terraform et appliquons-le :
terraform init
terraform plan --out=plan.out
Puis:
terraform apply plan.out
Cela prendra quelques minutes pour créer toutes les ressources. Assurez-vous de configurer le backend Terraform pour enregistrer le fichier de state à distance dans un emplacement sécurisé tel qu’un Azure Storage Account.
Pour tester l’API, vous pouvez utiliser Azure API Management, sélectionner l’API Open AI et dans l’onglet Test
, vous pouvez tester l’API. Si vous utilisez l’option Trace
, vous pouvez voir les détails de la requête et de la réponse avec un Bearer Token ajouté à la requête.
Voici un exemple de paramètres à passer pour tester l’API :
deployment-id: gpt-35-turbo
api-version: 2024-02-01
{
"temperature": 1,
"top_p": 1,
"stream": false,
"stop": null,
"max_tokens": 2000,
"presence_penalty": 0,
"frequency_penalty": 0,
"logit_bias": {},
"user": "user-1234",
"messages": [
{
"role": "system",
"content": "You are an AI assistant that helps people find information"
},
{
"role": "user",
"content": "When Microsoft company was created?."
}
],
"n": 1
}
et vous aurez ce genre de réponses:
{
"choices": [{
"content_filter_results": {
"hate": {
"filtered": false,
"severity": "safe"
},
"self_harm": {
"filtered": false,
"severity": "safe"
},
"sexual": {
"filtered": false,
"severity": "safe"
},
"violence": {
"filtered": false,
"severity": "safe"
}
},
"finish_reason": "stop",
"index": 0,
"message": {
"content": "Microsoft was created on April 4, 1975.",
"role": "assistant"
}
}],
"created": 1717078187,
"id": "chatcmpl-9UalPYoIMtfCe2d0LSavtobQX3RUk",
"model": "gpt-4",
"object": "chat.completion",
"prompt_filter_results": [{
"prompt_index": 0,
"content_filter_results": {
"hate": {
"filtered": false,
"severity": "safe"
},
"self_harm": {
"filtered": false,
"severity": "safe"
},
"sexual": {
"filtered": false,
"severity": "safe"
},
"violence": {
"filtered": false,
"severity": "safe"
}
}
}],
"system_fingerprint": null,
"usage": {
"completion_tokens": 12,
"prompt_tokens": 27,
"total_tokens": 39
}
}
Dans ce tutoriel, vous avez appris à utiliser Terraform pour créer une APIM, une API basée sur la documentation Swagger d’OpenAI, et attribuer un rôle à l’APIM. Vous avez également ajouté une policy à l’API pour utiliser l’identité managée de l’APIM pour s’authentifier auprès de la ressource Azure Open AI. Vous trouverez le code source complet dans ce tutoriel dans le répertoire Github.