• Skip to primary navigation
  • Skip to main content
  • Skip to footer

Codemotion Magazine

We code the future. Together

  • Discover
    • Events
    • Community
    • Partners
    • Become a partner
    • Hackathons
  • Magazine
    • DevOps
    • Carreras tech
    • Frontend
    • Inteligencia Artificial
    • Dev life
    • Desarrollo web
  • Talent
    • Discover Talent
    • Jobs
    • Manifiesto
  • Companies
  • For Business
    • EN
    • IT
    • ES
  • Sign in
ads

Orli Dunnoviembre 7, 2025 5 min read

Microsoft Azure: el miércoles negro que detuvo la red

Computacion en la nube
facebooktwitterlinkedinreddit

El pasado miércoles 29 de octubre de 2025, el mundo digital experimentó un parón dramático que afectó a millones, una falla global masiva en la plataforma de servicios en la nube de Microsoft Azure. Lo que comenzó como un problema de latencia pronto escaló a una interrupción a gran escala, paralizando servicios esenciales y reavivando el debate sobre nuestra dependencia de las infraestructuras cloud. 

Millones de usuarios y empresas vieron interrumpidas sus operaciones, afectando desde videojuegos hasta plataformas críticas de productividad. El origen del problema fue identificado en Azure Front Door, el servicio encargado de distribuir el tráfico global y garantizar que aplicaciones y sitios web estén siempre disponibles.

Recommended article
octubre 22, 2025

AWS: La Fragilidad del Internet en la Nube

Orli Dun

Orli Dun

Computacion en la nube

¿Cuál fue el epicentro de la falla de Microsoft Azure? 

Microsoft no tardó en confirmar la raíz del problema, apuntando a Azure Front Door (AFD).

Azure Front Door funciona como un “portero digital”. Es el sistema de distribución de contenido (CDN) global y punto de entrada de red de Microsoft. Actúa como la “puerta principal” de muchos de los servicios más grandes y críticos alojados en Azure y más allá (incluyendo a menudo el acceso a Microsoft 365).

  • Distribuye el tráfico: redirige a los usuarios al servidor más cercano y disponible.
  • Optimiza la velocidad: reduce la latencia al usar la red global de Microsoft.
  • Protege contra ataques: incluye firewalls y mitigación de DDoS.

En otras palabras, si piensas en internet como una autopista, Front Door es el sistema de peajes y desvíos inteligentes que asegura que los autos (usuarios) lleguen rápido y sin congestión a su destino (aplicaciones).

¿Qué ocurrió en el “miércoles negro”con Microsoft Azure?

  • Hora del fallo: alrededor del mediodía, los reportes en Downdetector se dispararon en cuestión de minutos.
  • Servicios afectados: Microsoft 365 (Outlook, Teams, OneDrive). Xbox y juegos en línea como Minecraft y Sea of Thieves. Microsoft Store y servicios empresariales críticos.
  • Impacto global: usuarios en EE. UU., Europa y América Latina reportaron interrupciones simultáneas.

El problema fue tan severo que incluso empresas que dependen de Azure para alojar sus sitios web y aplicaciones quedaron fuera de línea, generando pérdidas económicas y de productividad.

La causa confirmada

  • Un defecto de software en el plano de control de AFD, introducido semanas antes, fue el catalizador. Este fallo desencadenó una pérdida de capacidad en las instancias subyacentes de Kubernetes que gestionan el tráfico, resultando en:
  • Fallo en la gestión y resolución de solicitudes DNS (para dominios críticos como azureedge.net).
  • Tiempos de espera (timeouts) y latencia masiva.
  • Fallo intermitente para acceder a portales de administración y para iniciar sesión en múltiples servicios.

Ejemplos — infraestructura como código: Azure Front Door Standard/Premium

Cómo configurar Azure Front Door, diseñar rutas de failover activo-activo, aplicar reglas para manejar errores 503/504, y endurecer el cliente con reintentos y circuit breakers. Todo pensado para minimizar el impacto de una caída similar.

Terraform — Azure Front Door (Standard/Premium) con dos backends y failover por latencia

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.75"
    }
  }
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = "rg-frontdoor"
  location = "eastus"
  tags = {
    project = "edge-resilience"
    owner   = "team-plat"
  }
}

resource "azurerm_cdn_frontdoor_profile" "fdp" {
  name                = "fd-global-profile"
  resource_group_name = azurerm_resource_group.rg.name
  sku_name            = "Standard_AzureFrontDoor"
  tags = {
    env = "prod"
  }
}

# Origin Group (agrupar orígenes, probe y restore policy)
resource "azurerm_cdn_frontdoor_origin_group" "og" {
  name                          = "og-prod"
  cdn_frontdoor_profile_id      = azurerm_cdn_frontdoor_profile.fdp.id
  session_affinity_enabled      = false
  restore_traffic_time_to_healed_origins_in_minutes = 1
  tags = { purpose = "failover" }

  health_probe {
    interval_in_seconds = 10
    path                = "/healthz"
    protocol            = "Https"
    request_type        = "GET"
  }
}

# Origen East US
resource "azurerm_cdn_frontdoor_origin" "origin_eastus" {
  name                           = "api-eastus"
  cdn_frontdoor_origin_group_id  = azurerm_cdn_frontdoor_origin_group.og.id
  host_name                      = "api-eastus.contoso.com"
  http_port                      = 80
  https_port                     = 443
  origin_host_header             = "api-eastus.contoso.com"
  priority                       = 1
  weight                         = 50
  enabled                        = true
  tags = { region = "eastus" }
}

# Origen West Europe
resource "azurerm_cdn_frontdoor_origin" "origin_westeurope" {
  name                           = "api-westeurope"
  cdn_frontdoor_origin_group_id  = azurerm_cdn_frontdoor_origin_group.og.id
  host_name                      = "api-weu.contoso.com"
  http_port                      = 80
  https_port                     = 443
  origin_host_header             = "api-weu.contoso.com"
  priority                       = 1
  weight                         = 50
  enabled                        = true
  tags = { region = "westeurope" }
}

# Endpoint público (Front Door endpoint)
resource "azurerm_cdn_frontdoor_endpoint" "fde" {
  name                     = "edge-contoso"
  cdn_frontdoor_profile_id = azurerm_cdn_frontdoor_profile.fdp.id
  enabled                  = true
  tags = { public = "true" }
}

# Route: enruta todo el tráfico a la origin group con failover
resource "azurerm_cdn_frontdoor_route" "route_all" {
  name                          = "route-all"
  cdn_frontdoor_endpoint_id     = azurerm_cdn_frontdoor_endpoint.fde.id
  cdn_frontdoor_origin_group_id = azurerm_cdn_frontdoor_origin_group.og.id

  supported_protocols    = ["Http", "Https"]
  https_redirect_enabled = true
  patterns_to_match      = ["/*"]
  forwarding_protocol    = "HttpsOnly"
  cache_enabled          = true
  enabled                = true

  # Opcional: define caching defaults a nivel de ruta
  origin_request_policy = {
    # dejar por defecto o definir headers, cookies que pasar
  }

  tags = { route = "global" }
}Lenguaje del código: PHP (php)

Rules Engine — JSON (degradación elegante ante 503/504 + throttle simple)

{
  "name": "rules-degradacion",
  "properties": {
    "rules": [
      {
        "name": "fallback-503",
        "conditions": [
          {
            "name": "ResponseStatusCode",
            "parameters": {
              "matchValues": ["503", "504"],
              "operator": "Equals"
            }
          }
        ],
        "actions": [
          {
            "name": "UrlRewrite",
            "parameters": {
              "sourcePattern": "/.*",
              "destination": "/fallback/index.html",
              "preserveUnmatchedPath": false
            }
          },
          {
            "name": "Cache",
            "parameters": {
              "cacheBehavior": "Override",
              "cacheDuration": "600"
            }
          }
        ],
        "priority": 1,
        "enabledState": "Enabled"
      },
      {
        "name": "throttle-burst",
        "conditions": [
          {
            "name": "RequestRate",
            "parameters": {
              "operator": "GreaterThan",
              "matchValues": ["1000"],
              "transform": "None",
              "aggregationIntervalInSeconds": 60
            }
          }
        ],
        "actions": [
          {
            "name": "ModifyResponseHeader",
            "parameters": {
              "headerAction": "Append",
              "headerName": "Retry-After",
              "value": "5"
            }
          }
        ],
        "priority": 2,
        "enabledState": "Enabled"
      }
    ]
  }
}Lenguaje del código: JSON / JSON con comentarios (json)

Explicación: Cache en Rules Engine sirve para overrides puntuales, para caching por defecto lo ideal es usar settings de Route/Endpoint. Aquí lo dejo explícito como mecanismo de contingencia.

Cliente Node.js — Axios + retry exponencial + Opossum (circuit breaker)

// resilientClient.js
import axios from "axios";
import CircuitBreaker from "opossum";

const client = axios.create({
  baseURL: "https://edge-contoso.azurefd.net",
  timeout: 3000,
  validateStatus: status => status < 500 // deja pasar 2xx/3xx/4xx; 5xx -> catch
});

// Función que realizará la petición — retorna una Promise
async function callApi(path) {
  const maxRetries = 5;
  let attempt = 0;
  let delay = 200;

  while (attempt < maxRetries) {
    try {
      const res = await client.get(path);
      return res.data;
    } catch (err) {
      attempt++;
      if (attempt >= maxRetries) throw err;
      await new Promise(r => setTimeout(r, delay));
      delay = Math.min(delay * 2, 4000);
    }
  }
}

// Opossum espera una función que retorne una promesa.
// Envolveremos callApi en una función que reciba el argumento "path".
const breakerOptions = {
  timeout: 5000, // timepo máximo para la función del breaker
  errorThresholdPercentage: 50,
  resetTimeout: 10000,
  rollingCountTimeout: 10000
};

const breaker = new CircuitBreaker((path) => callApi(path), breakerOptions);

breaker.on("open", () => console.warn("Circuito ABIERTO: degradando"));
breaker.on("halfOpen", () => console.info("Circuito HALF-OPEN: probando"));
breaker.on("close", () => console.info("Circuito CERRADO: normal"));
breaker.on("fallback", (data) => console.info("fallback invoked", data));

export async function getProfile() {
  try {
    // breaker.fire acepta argumentos que se pasarán a la función envuelta
    return await breaker.fire("/api/profile");
  } catch (err) {
    // Degradación: devolver datos mínimos o cache local
    console.error("Fallo al obtener profile:", err.message || err);
    return { name: "Offline", features: [] };
  }
}

// Ejemplo de uso
if (require.main === module) {
  (async () => {
    const p = await getProfile();
    console.log("Profile:", p);
    process.exit(0);
  })();
}Lenguaje del código: JavaScript (javascript)

C# (.NET) — Polly con jitter, reintentos y circuit breaker (Program.cs)

using System;
using System.Net.Http;
using System.Threading.Tasks;
using Polly;
using Polly.CircuitBreaker;
using Polly.Extensions.Http;
using Polly.Contrib.WaitAndRetry;
using Microsoft.Extensions.Logging;

class Program
{
    static async Task<int> Main(string[] args)
    {
        var loggerFactory = LoggerFactory.Create(b => b.AddConsole());
        var logger = loggerFactory.CreateLogger("resilience");

        using var http = new HttpClient {
            BaseAddress = new Uri("https://edge-contoso.azurefd.net"),
            Timeout = TimeSpan.FromSeconds(3)
        };

        // Backoff con jitter (Polly.Contrib.WaitAndRetry)
        var jitter = Backoff.DecorrelatedJitterBackoffV2(TimeSpan.FromMilliseconds(200), retryCount: 5);

        var retryPolicy = HttpPolicyExtensions
            .HandleTransientHttpError() // 5xx, 408, HttpRequestException
            .OrResult(msg => (int)msg.StatusCode >= 500)
            .WaitAndRetryAsync(
                jitter,
                onRetry: (outcome, timespan, retryAttempt, context) =>
                {
                    logger.LogWarning("Retry {attempt} after {delay} due to {reason}", retryAttempt, timespan, outcome.Exception?.Message ?? outcome.Result?.StatusCode.ToString());
                }
            );

        var breakerPolicy = Policy
            .Handle<HttpRequestException>()
            .OrResult<HttpResponseMessage>(r => (int)r.StatusCode >= 500)
            .CircuitBreakerAsync(
                exceptionsAllowedBeforeBreaking: 5,
                durationOfBreak: TimeSpan.FromSeconds(10),
                onBreak: (outcome, timespan) =>
                {
                    logger.LogError("Circuit broken for {duration} because {reason}", timespan, outcome.Exception?.Message ?? outcome.Result?.StatusCode.ToString());
                },
                onReset: () => logger.LogInformation("Circuit reset."),
                onHalfOpen: () => logger.LogInformation("Circuit half-open: testing.")
            );

        var resilientPolicy = Policy.WrapAsync(retryPolicy, breakerPolicy);

        try
        {
            var res = await resilientPolicy.ExecuteAsync(() => http.GetAsync("/api/orders"));
            if (!res.IsSuccessStatusCode)
            {
                logger.LogWarning("Request returned non-success: {code}", res.StatusCode);
                Console.WriteLine("offline");
            }
            else
            {
                var content = await res.Content.ReadAsStringAsync();
                Console.WriteLine(content);
            }
        }
        catch (BrokenCircuitException)
        {
            logger.LogWarning("Circuit is open - returning degraded response");
            Console.WriteLine("offline");
        }
        catch (Exception ex)
        {
            logger.LogError("Unexpected error: {err}", ex.Message);
            Console.WriteLine("offline");
        }

        return 0;
    }
}Lenguaje del código: JavaScript (javascript)

CDN cache y “stale-while-revalidate” para absorber picos: cabeceras recomendadas en respuestas del backend

HTTP/1.1 200 OK
Cache-Control: public, max-age=300, stale-while-revalidate=60, stale-if-error=300
ETag: "v1-orders-71f9"Lenguaje del código: HTTP (http)

Explicación: Label – stale-while-revalidate: sirve contenido “viejo” mientras se recalienta el caché. stale-if-error: si el backend falla, Front Door devuelve la versión cacheada.

WAF (Azure Application Gateway / Front Door) — política JSON de ejemplo (rate limit + OWASP)

{
  "policySettings": { "enabledState": "Enabled", "mode": "Prevention" },
  "customRules": [
    {
      "name": "limit-rapid-requests",
      "priority": 10,
      "ruleType": "RateLimitRule",
      "rateLimitDurationInMinutes": 1,
      "rateLimitThreshold": 300,
      "matchConditions": [
        {
          "matchVariable": "RemoteAddr",
          "operator": "IPMatch",
          "matchValues": ["0.0.0.0/0"]
        }
      ],
      "action": "Block",
      "enabledState": "Enabled"
    }
  ],
  "managedRules": {
    "managedRuleSets": [
      { "ruleSetType": "OWASP", "ruleSetVersion": "3.2" }
    ]
  }
}Lenguaje del código: JSON / JSON con comentarios (json)

Nota: para producción, en lugar de IP 0.0.0.0/0 suele emplearse combinación con encabezados o fingerprinting; aquí se usa0.0.0.0/0 solo como ejemplo global (bloquea picos masivos).

Azure Monitor — Metric Alert (ARM JSON simplificado con ventana & evaluación)

{
  "type": "Microsoft.Insights/metricAlerts",
  "apiVersion": "2018-03-01",
  "name": "fd-5xx-spike",
  "location": "global",
  "properties": {
    "description": "Alerta ante incremento de 5xx en Front Door",
    "severity": 2,
    "enabled": true,
    "scopes": [
      "/subscriptions/<SUB>/resourceGroups/rg-frontdoor/providers/Microsoft.Cdn/profiles/fd-global-profile"
    ],
    "evaluationFrequency": "PT1M",
    "windowSize": "PT5M",
    "criteria": {
      "odata.type": "Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria",
      "allOf": [
        {
          "name": "5xx-rate",
          "metricName": "TotalRequests",
          "metricNamespace": "",
          "operator": "GreaterThan",
          "timeAggregation": "Count",
          "threshold": 1000,
          "dimensions": [
            {
              "name": "ResponseCodeGroup",
              "operator": "Include",
              "values": ["5xx"]
            }
          ]
        }
      ]
    },
    "autoMitigate": true,
    "actions": [
      {
        "actionGroupId": "/subscriptions/<SUB>/resourceGroups/rg-monitor/providers/microsoft.insights/actiongroups/pagerduty"
      }
    ]
  }
}Lenguaje del código: JSON / JSON con comentarios (json)

Ajustar threshold y windowSize a la realidad de tu tráfico para evitar false positives.

NGINX — fallback a página estática si upstream falla

# /etc/nginx/conf.d/edge-origin.conf
upstream app_pool {
  server api-eastus.contoso.com:443 max_fails=1 fail_timeout=5s;
  server api-weu.contoso.com:443 backup;
}

server {
  listen 443 ssl;
  server_name edge-origin.contoso.com;

  ssl_certificate     /etc/ssl/certs/edge-origin.crt;
  ssl_certificate_key /etc/ssl/private/edge-origin.key;

  location / {
    proxy_pass https://app_pool;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    proxy_next_upstream error timeout http_502 http_503 http_504;
    proxy_connect_timeout 3s;
    proxy_read_timeout 10s;
  }

  error_page 502 503 504 /fallback.html;
  location = /fallback.html {
    root /var/www/static;
    add_header Cache-Control "public, max-age=300, stale-if-error=300";
    internal;
  }

  # opcional: servir healthz local
  location = /healthz {
    return 200 "OK";
    add_header Content-Type text/plain;
  }
}Lenguaje del código: PHP (php)

Estos snippets son operativos y reflejan las mejores prácticas: tolerancia a fallos en cliente y servidor, caching estratégico, políticas WAF y alertas operativas.

Resiliencia en la era cloud

Este “miércoles negro” ha impulsado una reflexión crítica en la industria tecnológica:

  1. Diversificación es Clave: La dependencia en un solo proveedor de nube, incluso uno tan grande como Microsoft, introduce un riesgo sistémico. Se refuerza la necesidad de estrategias multi-nube o de redundancia entre regiones para servicios críticos.
  2. La Importancia del Edge: El fallo se originó en la capa más externa, el CDN global (Front Door). Esto subraya que la cadena de suministro de la infraestructura de internet es tan fuerte como su eslabón más débil.
  3. Pruebas de Recuperación ante Desastres: Las organizaciones deben realizar pruebas de penetración y recuperación de desastres robustas, simulando no solo fallos de servidores, sino fallos en los servicios de gestión de tráfico globales.

El camino hacia la recuperación

Microsoft movilizó rápidamente a sus equipos, priorizando el reinicio de las instancias de Kubernetes afectadas y la activación de mecanismos de failover. Si bien la disponibilidad fue restaurada en un 98% en pocas horas, la latencia residual persistió.

El incidente de Azure Front Door es un caso de estudio crucial. Nos recuerda que, aunque la nube ofrece una escalabilidad y confiabilidad sin igual, la complejidad inherente a estos sistemas gigantescos siempre contendrá el riesgo de un fallo único con un impacto global. Aunque el servicio fue restablecido progresivamente, el incidente dejó en evidencia la dependencia global de la nube y la fragilidad de un ecosistema donde un solo punto de falla puede afectar a millones.

El panorama digital global se ha visto sacudido por dos incidentes monumentales: la falla global de Microsoft Azure y el colapso masivo de Amazon Web Services (AWS). Estos eventos, que paralizaron una parte significativa de internet, no son meros fallos técnicos; son el “Miércoles Negro” y la señal de alarma que expone la fragilidad de nuestra hiperconectada dependencia en la infraestructura de la nube.

La nube no falla a menudo, pero cuando lo hace, nos recuerda que la resiliencia no se diseña en tiempos de crisis, sino en la calma. La ingeniería moderna no es solo código: es prever la caída y asegurar la recuperación.

Codemotion Collection Background
Top of the week
Seleccionados para ti

¿Te gustaría leer más artículos como este? Explora la colección Top of the week , con una selección personalizada y siempre actualizada de contenido nuevo.

Share on:facebooktwitterlinkedinreddit

Tags:Desarrollo web

Orli Dun
¡De las finanzas a la revolución digital! Software Developer - Cloud & AI - OCI Certified - Tech Content Creator #porunmillondeamigos
Seguridad en protocolos de contexto de modelo: Un análisis del OWASP MCP Top 10
Artículo anterior
Red Neuronal: la inspiración biológica
Próximo artículo

Footer

Discover

  • Events
  • Community
  • Partners
  • Become a partner
  • Hackathons

Magazine

  • Tech articles

Talent

  • Discover talent
  • Jobs

Companies

  • Discover companies

For Business

  • Codemotion for companies

About

  • About us
  • Become a contributor
  • Work with us
  • Contact us

Follow Us

© Copyright Codemotion srl Via Marsala, 29/H, 00185 Roma P.IVA 12392791005 | Privacy policy | Terms and conditions