Skip to content

Commit

Permalink
added eventhub logger and openai api to the apim
Browse files Browse the repository at this point in the history
  • Loading branch information
cmendible committed Nov 6, 2023
1 parent 1d4d124 commit bfee0ac
Show file tree
Hide file tree
Showing 8 changed files with 1,030 additions and 7 deletions.
26 changes: 20 additions & 6 deletions infra/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,29 @@ module "nsg" {
pe_subnet_id = module.vnet.pe_subnet_id
}

module "apim" {
source = "./modules/apim"
module "evh" {
source = "./modules/evh"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
apim_name = var.apim_name
apim_subnet_id = module.vnet.apim_subnet_id
publisher_name = var.publisher_name
publisher_email = var.publisher_email
eventhub_name = var.eventhub_name
enable_apim = var.enable_apim
}

module "apim" {
source = "./modules/apim"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
apim_name = var.apim_name
apim_subnet_id = module.vnet.apim_subnet_id
publisher_name = var.publisher_name
publisher_email = var.publisher_email
enable_apim = var.enable_apim
eventhub_id = module.evh.eventhub_id
eventhub_name = module.evh.eventhub_name
eventhub_connection_string = module.evh.eventhub_connection_string
openai_service_name = module.openai.openai_service_name
openai_service_endpoint = module.openai.openai_endpoint
tenant_id = data.azurerm_subscription.current.tenant_id

depends_on = [module.nsg]
}
Expand Down
811 changes: 811 additions & 0 deletions infra/modules/apim/azure_openai.json

Large diffs are not rendered by default.

139 changes: 139 additions & 0 deletions infra/modules/apim/main.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
locals {
logger_name = "openai-logger"
}

resource "azurerm_api_management" "apim" {
count = var.enable_apim ? 1 : 0
name = var.apim_name
Expand All @@ -12,3 +16,138 @@ resource "azurerm_api_management" "apim" {
subnet_id = var.apim_subnet_id
}
}

// TODO: https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-log-event-hubs?tabs=bicep#logger-with-system-assigned-managed-identity-credentialss
resource "azurerm_api_management_logger" "logger" {
count = var.enable_apim ? 1 : 0
name = "openai-logger"
api_management_name = azurerm_api_management.apim[0].name
resource_group_name = var.resource_group_name
resource_id = var.eventhub_id

eventhub {
name = var.eventhub_name
connection_string = var.eventhub_connection_string
}
}

// https://learn.microsoft.com/en-us/semantic-kernel/deploy/use-ai-apis-with-api-management#setup-azure-api-management-instance-with-azure-openai-api
resource "azurerm_api_management_api" "openai" {
count = var.enable_apim ? 1 : 0
name = "openai-api"
resource_group_name = var.resource_group_name
api_management_name = azurerm_api_management.apim[0].name
revision = "1"
display_name = "Azure Open AI API"
path = ""
protocols = ["https"]

import {
content_format = "openapi"
content_value = replace(replace(file("${path.module}/azure_openai.json"), "{endpoint}", var.openai_service_endpoint), "{servicename}", var.openai_service_name)
}
}

// https://github.com/mattfeltonma/azure-openai-apim/blob/main/apim-policies/apim-policy-event-hub-logging.xml
resource "azurerm_api_management_api_policy" "policy" {
count = var.enable_apim ? 1 : 0
api_name = azurerm_api_management_api.openai[0].name
api_management_name = azurerm_api_management.apim[0].name
resource_group_name = var.resource_group_name

xml_content = <<XML
<!--
This sample policy enforces Azure AD authentication and authorization to the Azure OpenAI Service.
It limits the authorization tokens issued by the organization's tenant for Cognitive Services.
The authorization token is passed on to the Azure OpenAI Service ensuring authorization to the actions within
the service are limited to the permissions defined in Azure RBAC.
The sample policy also logs audit information such as the application id making the call, the prompt, the response,
the model used, and the number of tokens consumed. This can be helpful when handling chargebacks. The events are delivered
to an Azure Event Hub through the Azure API Management Logger.
You must provide values for the AZURE_OAI_SERVICE_NAME, TENANT_ID, YOUR_LOGGER_COMPLIANCE, and YOUR_LOGGER_CHARGEBACK a parameters.
You can use separate APIM Loggers for compliance and chargeback or the same logger. It is your choice.
-->
<policies>
<inbound>
<base />
<validate-jwt header-name="Authorization" failed-validation-httpcode="403" failed-validation-error-message="Forbidden">
<openid-config url="https://login.microsoftonline.com/${var.tenant_id}/v2.0/.well-known/openid-configuration" />
<issuers>
<issuer>https://sts.windows.net/${var.tenant_id}/</issuer>
</issuers>
<required-claims>
<claim name="aud">
<value>https://cognitiveservices.azure.com</value>
</claim>
</required-claims>
</validate-jwt>
<set-variable name="message-id" value="@(Guid.NewGuid())" />
<log-to-eventhub logger-id="${local.logger_name}" partition-id="0">@{
var requestBody = context.Request.Body?.As<JObject>(true);
string prompt = requestBody["prompt"]?.ToString();
string messages = requestBody["messages"]?.ToString();
return new JObject(
new JProperty("event-time", DateTime.UtcNow.ToString()),
new JProperty("backend", context.Request.Url.Host.ToString()),
new JProperty("message-id", context.Variables["message-id"]),
new JProperty("appid", context.Request.Headers.GetValueOrDefault("Authorization",string.Empty).Split(' ').Last().AsJwt().Claims.GetValueOrDefault("appid", string.Empty)),
new JProperty("operationname", context.Operation.Id),
new JProperty("prompt", prompt),
new JProperty("messages", messages)
).ToString();
}</log-to-eventhub>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<log-to-eventhub logger-id="${local.logger_name}" partition-id="1">@{
var responseBody = context.Response.Body?.As<JObject>(true);
string response = responseBody["choices"]?.ToString();
return new JObject(
new JProperty("event-time", DateTime.UtcNow.ToString()),
new JProperty("backend", context.Request.Url.Host.ToString()),
new JProperty("response-time", context.Response.Headers.GetValueOrDefault("openai-processing-ms",string.Empty)),
new JProperty("message-id", context.Variables["message-id"]),
new JProperty("appid", context.Request.Headers.GetValueOrDefault("Authorization",string.Empty).Split(' ').Last().AsJwt().Claims.GetValueOrDefault("appid", string.Empty)),
new JProperty("choices",response),
new JProperty("operation", responseBody["object"].ToString()),
new JProperty("model", responseBody["model"].ToString())
).ToString();
}</log-to-eventhub>
<log-to-eventhub logger-id="${local.logger_name}" partition-id="0">@{
var responseBody = context.Response.Body?.As<JObject>(true);
return new JObject(
new JProperty("event-time", DateTime.UtcNow.ToString()),
new JProperty("message-id", context.Variables["message-id"]),
new JProperty("appid", context.Request.Headers.GetValueOrDefault("Authorization",string.Empty).Split(' ').Last().AsJwt().Claims.GetValueOrDefault("appid", string.Empty)),
new JProperty("operation", responseBody["object"].ToString()),
new JProperty("model", responseBody["model"].ToString()),
new JProperty("modeltime", context.Response.Headers.GetValueOrDefault("Openai-Processing-Ms",string.Empty)),
new JProperty("completion_tokens", responseBody["usage"]["completion_tokens"].ToString()),
new JProperty("prompt_tokens", responseBody["usage"]["prompt_tokens"].ToString()),
new JProperty("total_tokens", responseBody["usage"]["total_tokens"].ToString())
).ToString();
}</log-to-eventhub>
</outbound>
<on-error>
<base />
</on-error>
</policies>
XML
}
6 changes: 6 additions & 0 deletions infra/modules/apim/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,11 @@ variable "apim_name" {}
variable "publisher_name" {}
variable "publisher_email" {}
variable "apim_subnet_id" {}
variable "eventhub_name" {}
variable "eventhub_connection_string" {}
variable "eventhub_id" {}
variable "openai_service_name" {}
variable "openai_service_endpoint" {}
variable "tenant_id" {}

variable "enable_apim" {}
32 changes: 32 additions & 0 deletions infra/modules/evh/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
resource "azurerm_eventhub_namespace" "evh" {
count = var.enable_apim ? 1 : 0
name = var.eventhub_name
location = var.location
resource_group_name = var.resource_group_name
sku = "Standard"
capacity = 1

# network_rulesets {
# default_action = "Deny"
# trusted_service_access_enabled = true

# ip_rule {
# ip_mask = "0.0.0.0"
# }
# }

lifecycle {
ignore_changes = [
network_rulesets
]
}
}

resource "azurerm_eventhub" "hub" {
count = var.enable_apim ? 1 : 0
name = var.eventhub_name
namespace_name = azurerm_eventhub_namespace.evh[0].name
resource_group_name = var.resource_group_name
partition_count = 2
message_retention = 1
}
12 changes: 12 additions & 0 deletions infra/modules/evh/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
output "eventhub_name" {
value = var.enable_apim ? azurerm_eventhub_namespace.evh[0].name : ""
}

output "eventhub_id" {
value = var.enable_apim ? azurerm_eventhub_namespace.evh[0].id : ""
}

output "eventhub_connection_string" {
value = var.enable_apim ? azurerm_eventhub_namespace.evh[0].default_primary_connection_string : ""
}

5 changes: 5 additions & 0 deletions infra/modules/evh/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
variable "resource_group_name" {}
variable "location" {}
variable "eventhub_name" {}

variable "enable_apim" {}
6 changes: 5 additions & 1 deletion infra/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ variable "storage_account_name" {
default = "stgenai"
}

variable "eventhub_name" {
default = "evh-activate-genai"
}

variable "apim_name" {
default = "apim-activate-genai"
}
Expand Down Expand Up @@ -75,4 +79,4 @@ variable "enable_entra_id_authentication" {

variable "enable_apim" {
default = false
}
}

0 comments on commit bfee0ac

Please sign in to comment.