Skip to main contentCertyo Developer Portal

Integración con Microsoft Azure

Arquitectura de referencia para integrar Certyo con servicios gestionados de Azure — API Management, Service Bus, Functions, Logic Apps y Key Vault.

Compatibilidad nativa con .NET
El backend .NET 8 de Certyo se ejecuta nativamente en Azure App Service o AKS — la integración más estrecha es con Azure.

Requisitos previos

  • Suscripción de Azure con rol de Colaborador
  • Azure CLI v2.60 o posterior
  • Clave API de Certyo (almacenada en Azure Key Vault — ver sección Autenticación más abajo)
  • .NET 8 SDK (para desarrollo de Azure Functions)

Arquitectura de referencia

Esta arquitectura utiliza servicios nativos de Azure para una ingesta durable, observable y de grado empresarial hacia Certyo:

Azure Reference Architecture
Source System ──► Event Grid ──► Service Bus Queue ──► Azure Function ──► Certyo API
                                         │                                      │
                                    Dead-letter                          Logic App polls
                                      queue                              anchoring status
                                                                                │
                                                                        Event Grid topic
                                                                         (record anchored)
                                                                                │
                                                                        Subscriber webhooks
                                                                        / Teams / Email

Event Grid captura eventos de dominio de tus sistemas fuente (SQL, Cosmos DB, Storage, aplicaciones personalizadas). Service Bus proporciona colas durables con manejo de dead-letter. Azure Functions transforman y envían registros a Certyo. Logic Apps orquestan el sondeo de verificación y notificaciones posteriores.


API Management (APIM)

Despliega el API de Certyo detrás de Azure API Management para gobernanza empresarial — limitación de tasa, validación JWT, transformación de solicitudes y un portal de desarrollador para equipos internos.

Importar la especificación OpenAPI

Registra Certyo como un backend en APIM, luego importa la definición OpenAPI para auto-generar políticas y documentación:

Import Certyo API into APIMbash
# Create the APIM instance (skip if you already have one)
az apim create \
  --name certyo-apim \
  --resource-group certyo-rg \
  --publisher-name "Your Organization" \
  --publisher-email ops@yourorg.com \
  --sku-name Developer

# Import Certyo API from OpenAPI spec
az apim api import \
  --resource-group certyo-rg \
  --service-name certyo-apim \
  --path certyo \
  --api-id certyo-records \
  --specification-format OpenApi \
  --specification-url "https://www.certyos.com/api/v1/swagger.json" \
  --display-name "Certyo Records API"

# Set the backend URL
az apim api update \
  --resource-group certyo-rg \
  --service-name certyo-apim \
  --api-id certyo-records \
  --service-url "https://www.certyos.com"

Políticas de APIM

Agrega políticas de entrada para limitación de tasa, inyección de clave API desde Key Vault y validación de solicitudes:

APIM inbound policy (XML in JSON config)json
<policies>
  <inbound>
    <!-- Rate limit per subscription: 100 calls/minute -->
    <rate-limit calls="100" renewal-period="60" />

    <!-- Validate JWT from Azure AD -->
    <validate-jwt header-name="Authorization" failed-validation-httpcode="401">
      <openid-config url="https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration" />
      <required-claims>
        <claim name="aud" match="all">
          <value>{your-app-client-id}</value>
        </claim>
      </required-claims>
    </validate-jwt>

    <!-- Inject Certyo API key from Named Value (backed by Key Vault) -->
    <set-header name="X-API-Key" exists-action="override">
      <value>{{certyo-api-key}}</value>
    </set-header>

    <!-- Remove the Authorization header before forwarding -->
    <set-header name="Authorization" exists-action="delete" />
  </inbound>
  <backend>
    <forward-request />
  </backend>
  <outbound />
</policies>

Este patrón significa que los consumidores internos se autentican con tokens de Azure AD y nunca ven la clave API de Certyo. APIM maneja el intercambio de credenciales de forma transparente.


Service Bus

Usa Azure Service Bus como un buffer de mensajes durable entre tus sistemas empresariales y Certyo. La cola garantiza entrega al menos una vez con reintento configurable y manejo de dead-letter:

  • Cola — punto a punto, un consumidor (la Azure Function que llama a Certyo)
  • Topic + Suscripciones — distribución para patrones multi-consumidor (por ejemplo, ingesta a Certyo Y espejo a un data lake)
  • Cola de dead-letter — los mensajes fallidos llegan aquí después del máximo de intentos de entrega, permitiendo investigación sin pérdida de datos

Azure Functions

Las funciones serverless actúan como el pegamento entre Service Bus y Certyo. Dos funciones clave:

1. Función de ingesta (trigger de Service Bus)

Activada por cada mensaje en la cola de Service Bus, lo transforma en un registro Certyo y llama a POST /api/v1/records:

2. Función de sondeo de verificación (trigger de Timer)

Se ejecuta según un horario para verificar si los registros ingestados recientemente han sido anclados on-chain, luego publica los resultados en Event Grid:

CertyoIngestionFunction.cscsharp
using System.Net.Http.Json;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace Certyo.Functions;

public class CertyoIngestionFunction
{
    private readonly HttpClient _http;
    private readonly ILogger<CertyoIngestionFunction> _logger;
    private string? _apiKey;

    public CertyoIngestionFunction(
        IHttpClientFactory httpClientFactory,
        ILogger<CertyoIngestionFunction> logger)
    {
        _http = httpClientFactory.CreateClient("Certyo");
        _logger = logger;
    }

    [Function("IngestRecord")]
    public async Task Run(
        [ServiceBusTrigger("certyo-ingest", Connection = "ServiceBusConnection")]
        ServiceBusReceivedMessage message,
        FunctionContext context)
    {
        var apiKey = await GetApiKeyAsync();
        var record = message.Body.ToObjectFromJson<CertyoRecord>();

        _logger.LogInformation(
            "Ingesting record {RecordId} for tenant {TenantId}",
            record.RecordId, record.TenantId);

        var request = new HttpRequestMessage(HttpMethod.Post, "/api/v1/records")
        {
            Content = JsonContent.Create(new
            {
                record.TenantId,
                record.Database,
                record.Collection,
                record.RecordId,
                record.RecordVersion,
                operationType = "upsert",
                record.RecordPayload,
                sourceTimestamp = record.SourceTimestamp ?? DateTimeOffset.UtcNow,
                idempotencyKey = $"{record.RecordId}-{record.RecordVersion}-{DateTime.UtcNow:yyyy-MM-dd}"
            })
        };
        request.Headers.Add("X-API-Key", apiKey);

        var response = await _http.SendAsync(request);

        if (!response.IsSuccessStatusCode)
        {
            var body = await response.Content.ReadAsStringAsync();
            _logger.LogError(
                "Certyo ingestion failed for {RecordId}: {Status} {Body}",
                record.RecordId, response.StatusCode, body);
            throw new InvalidOperationException(
                $"Certyo returned {response.StatusCode}");
        }

        var result = await response.Content
            .ReadFromJsonAsync<CertyoIngestionResult>();
        _logger.LogInformation(
            "Record {RecordId} accepted. Hash: {Hash}",
            record.RecordId, result?.RecordHash);
    }

    private async Task<string> GetApiKeyAsync()
    {
        if (_apiKey is not null) return _apiKey;

        var vaultUri = Environment.GetEnvironmentVariable("KEY_VAULT_URI")!;
        var client = new SecretClient(new Uri(vaultUri), new DefaultAzureCredential());
        var secret = await client.GetSecretAsync("certyo-api-key");
        _apiKey = secret.Value.Value;
        return _apiKey;
    }
}

public record CertyoRecord(
    string TenantId,
    string Database,
    string Collection,
    string RecordId,
    string RecordVersion,
    object RecordPayload,
    DateTimeOffset? SourceTimestamp);

public record CertyoIngestionResult(
    string RecordId,
    string RecordHash,
    string TenantId,
    DateTimeOffset AcceptedAt,
    bool IdempotencyReplayed);

Logic Apps

Para usuarios de negocio que necesitan orquestación sin código, Logic Apps proporciona un diseñador visual para conectar triggers empresariales a Certyo. Patrón común:

  1. Trigger — "Cuando se agrega una fila a la tabla SQL" o "Cuando se crea un registro de Dynamics 365"
  2. Transformar — Mapea los campos fuente al esquema de registro de Certyo usando el mapeador de datos integrado
  3. Acción HTTP — POST a https://www.certyos.com/api/v1/records con el encabezado X-API-Key
  4. Condición — Verificar 202 Accepted
  5. Notificar — Publicar en canal de Teams o enviar correo en caso de éxito/fallo
Logic App template: SQL row to Certyojson
{
  "definition": {
    "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
    "triggers": {
      "When_a_row_is_added": {
        "type": "ApiConnection",
        "inputs": {
          "host": { "connection": { "name": "@parameters('$connections')['sql']['connectionId']" } },
          "method": "get",
          "path": "/datasets/default/tables/@{encodeURIComponent('dbo.AuditRecords')}/onnewitems"
        },
        "recurrence": { "frequency": "Minute", "interval": 1 }
      }
    },
    "actions": {
      "Send_to_Certyo": {
        "type": "Http",
        "inputs": {
          "method": "POST",
          "uri": "https://www.certyos.com/api/v1/records",
          "headers": {
            "X-API-Key": "@parameters('certyoApiKey')",
            "Content-Type": "application/json"
          },
          "body": {
            "tenantId": "@parameters('certyoTenantId')",
            "database": "azure-sql",
            "collection": "AuditRecords",
            "recordId": "@{triggerBody()?['Id']}",
            "recordVersion": "1",
            "operationType": "insert",
            "recordPayload": "@triggerBody()",
            "sourceTimestamp": "@{triggerBody()?['CreatedAt']}",
            "idempotencyKey": "@{triggerBody()?['Id']}-1-@{formatDateTime(utcNow(), 'yyyy-MM-dd')}"
          }
        },
        "runAfter": {}
      },
      "Post_to_Teams": {
        "type": "ApiConnection",
        "inputs": {
          "host": { "connection": { "name": "@parameters('$connections')['teams']['connectionId']" } },
          "method": "post",
          "path": "/v3/beta/teams/@{parameters('teamsTeamId')}/channels/@{parameters('teamsChannelId')}/messages",
          "body": {
            "body": {
              "content": "Record @{triggerBody()?['Id']} sent to Certyo. Hash: @{body('Send_to_Certyo')?['recordHash']}"
            }
          }
        },
        "runAfter": { "Send_to_Certyo": ["Succeeded"] }
      }
    }
  }
}

Autenticación

El patrón de autenticación recomendado superpone la identidad nativa de Azure sobre la clave API de Certyo:

  • Key Vault — Almacena el X-API-Key de Certyo como un secreto. Otorga acceso vía RBAC (rol Key Vault Secrets User) a los service principals que lo necesiten.
  • Managed Identity — Azure Functions y Logic Apps usan identidad administrada asignada por el sistema para recuperar la clave de Key Vault en tiempo de ejecución. Sin credenciales en código o configuración.
  • Claves de suscripción APIM — Los consumidores internos se autentican con APIM usando claves de suscripción o tokens de Azure AD. APIM inyecta la clave API de Certyo en su nombre (ver la política anterior).
Grant Function App access to Key Vaultbash
# Get the Function App's managed identity principal ID
PRINCIPAL_ID=$(az functionapp identity show \
  --name certyo-fn-abc123 \
  --resource-group certyo-rg \
  --query principalId -o tsv)

# Assign Key Vault Secrets User role
az role assignment create \
  --assignee $PRINCIPAL_ID \
  --role "Key Vault Secrets User" \
  --scope "/subscriptions/{sub-id}/resourceGroups/certyo-rg/providers/Microsoft.KeyVault/vaults/certyo-kv"

Monitoreo

Integra Application Insights para observabilidad de extremo a extremo en todo el pipeline de ingesta:

  • Rastreo distribuido — Azure Functions correlaciona automáticamente trazas a través de mensajes de Service Bus vía encabezados Diagnostic-Id
  • Métricas personalizadas — Rastrea la latencia de ingesta (mensaje en cola hasta respuesta 202 de Certyo) y la latencia de anclaje (ingesta hasta confirmación on-chain)
  • Alertas — Configura alertas sobre la profundidad de la cola de dead-letter, fallos de ejecución de funciones y tasas de error del API de Certyo
  • Workbooks — Construye Azure Monitor Workbooks para visualizar el throughput de registros, cumplimiento del SLA de anclaje y tasas de éxito de verificación
Custom metrics in Azure Functionscsharp
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts;

// In your function class constructor:
private readonly TelemetryClient _telemetry;

// After successful ingestion:
_telemetry.TrackMetric(new MetricTelemetry
{
    Name = "CertyoIngestionLatencyMs",
    Sum = stopwatch.ElapsedMilliseconds,
    Count = 1,
    Properties =
    {
        ["tenantId"] = record.TenantId,
        ["collection"] = record.Collection
    }
});

_telemetry.TrackEvent("CertyoRecordIngested", new Dictionary<string, string>
{
    ["recordId"] = record.RecordId,
    ["recordHash"] = result.RecordHash,
    ["tenantId"] = record.TenantId
});

// KQL query for Application Insights:
// customMetrics
// | where name == "CertyoIngestionLatencyMs"
// | summarize avg(value), percentile(value, 95) by bin(timestamp, 5m)
// | render timechart

Próximos pasos

  • Despliega la plantilla Bicep anterior para crear toda la infraestructura en minutos
  • Configura las políticas de APIM para tu tenant de Azure AD y la estructura de equipos internos
  • Configura alertas de Application Insights para la profundidad de la cola de dead-letter y fallos de ingesta
  • Revisa la Guía de ingesta para detalles sobre el esquema de registros e idempotencia
  • Ve la Guía de verificación para detalles sobre pruebas criptográficas

AI Integration · v1.0.0

AI Integration Skill

Download a skill file that enables AI agents to generate working Microsoft Azure + Certyo integration code for any language or framework.

v1.0.0
What is this?
A markdown file containing Microsoft Azure-specific field mappings, authentication setup, code examples, and integration patterns for Certyo. Drop it into your AI agent's context and ask it to generate integration code.

What's inside

  • Autenticación — Managed Identity, secretos de Key Vault y claves de suscripción APIM
  • Arquitectura — Event Grid → Service Bus → Azure Function → arquitectura de referencia Certyo
  • Ejemplos de código — C# Azure Functions (ServiceBusTrigger, TimerTrigger), plantilla Bicep IaC
  • API Management — Configuración de APIM con limitación de tasa, validación JWT y portal de desarrollador
  • Logic Apps — Plantilla de orquestación sin código para SQL → Certyo → notificación de Teams
  • Monitoreo — Métricas personalizadas de Application Insights y consultas KQL para observabilidad

How to use

Claude Code

Place the file in your project's .claude/commands/ directory, then use it as a slash command:

# Download the skill file
mkdir -p .claude/commands
curl -o .claude/commands/certyo-azure.md \
  https://www.certyos.com/developers/skills/certyo-azure-skill.md

# Use it in Claude Code
/certyo-azure "Genera un pipeline de Service Bus a Certyo con Azure Functions y Key Vault"

Cursor / Copilot / Any AI Agent

Add the file to your project root or attach it to a conversation. The AI agent will use the Microsoft Azure-specific patterns, field mappings, and code examples to generate correct integration code.

# Add to your project
curl -o CERTYO_AZURE.md \
  https://www.certyos.com/developers/skills/certyo-azure-skill.md

# Then in your AI agent:
"Using the Certyo Microsoft Azure spec in CERTYO_AZURE.md,
 genera un pipeline de service bus a certyo con azure functions y key vault"

CLAUDE.md Context File

Append the skill file to your project's CLAUDE.md so every Claude conversation has Microsoft Azure + Certyo context automatically.

# Append to your project's CLAUDE.md
echo "" >> CLAUDE.md
echo "## Certyo Microsoft Azure Integration" >> CLAUDE.md
cat CERTYO_AZURE.md >> CLAUDE.md