Plusieurs services Cloudflare ont été indisponibles pendant 121 minutes le 24 janvier 2023, en raison d'une erreur de publication du code assurant la gestion des jetons de service. L'incident a altéré le fonctionnement d'un grand nombre de produits Cloudflare, notamment des aspects de notre plateforme Workers et notre solution Zero Trust, ainsi que des fonctions du plan de contrôle de notre solution de réseau de diffusion de contenu (CDN).
Cloudflare fournit une fonctionnalité de jeton de service permettant aux services automatisés de s'authentifier auprès d'autres services. Les clients peuvent utiliser des jetons de service pour sécuriser les interactions entre une application exécutée dans un datacenter et une ressource hébergée par un fournisseur de cloud public, par exemple. Avec cette version, nous avions l'intention d'introduire une fonctionnalité qui indiquait aux administrateurs l'heure de la dernière utilisation d'un jeton, fournissant ainsi aux utilisateurs la possibilité d'effacer en toute sécurité les jetons inutilisés. Cette modification a malencontreusement écrasé d'autres métadonnées liées aux jetons de service et a rendu les jetons des comptes concernés invalides pendant la durée de l'incident.
Cette version a affecté d'autres services, car Cloudflare s'exécute sur Cloudflare. Les jetons de service affectent la capacité des comptes à s'authentifier, et deux des comptes concernés sont utilisés par plusieurs services Cloudflare. Lorsque les jetons de service de ces comptes ont été écrasés, les services fonctionnant sur ces comptes ont commencé à être affectés par des échecs de requêtes et d'autres erreurs inattendues.
Bien qu'un segment limité de clients et d'utilisateurs finaux ait été directement affecté par cet incident et que d'autres clients aient pu constater une dégradation du service, les répercussions globales sur le réseau et les services de Cloudflare n'ont pas été considérables. Néanmoins, nous savons que les répercussions ont été très problématiques pour les clients affectés. Nous documentons l'incident, afin que vous puissiez comprendre pourquoi il s'est produit et les mesures que nous prenons pour éviter qu'il se reproduise.
Qu'est-ce qu'un jeton de service ?
Lorsqu'un utilisateur se connecte à une application ou un fournisseur d'identité, il saisit généralement un nom d'utilisateur et un mot de passe. Le mot de passe permet à l'utilisateur de démontrer qu'il contrôle le nom d'utilisateur et que le service doit autoriser son accès. Des couches d'authentification supplémentaires, telles que des clés physiques ou un profil de sécurité de l'appareil, peuvent être ajoutées, mais le flux de travail consiste, pour un humain, à prouver à un service qu'il est bien celui qu'il prétend être.
Toutefois, les humains ne sont pas les seuls utilisateurs qui doivent s'authentifier auprès d'un service. Les applications ont souvent besoin de communiquer avec d'autres applications. Imaginons, par exemple, que vous construisiez une application qui présente à un utilisateur des informations concernant un voyage qu'il a prévu d'effectuer.
La compagnie aérienne conserve sur son système les informations détaillées concernant le vol et sa durée. Elle ne souhaite pas rendre publics sur Internet les détails de chaque voyage individuel, et ne souhaite pas non plus inviter votre application sur son réseau privé. De même, l'hôtel veut s'assurer de ne transmettre les informations détaillées d'une réservation de chambre qu'à un service tiers valide et approuvé.
Votre application a besoin d'une méthode de confiance pour s'authentifier auprès de ces systèmes externes. Les jetons de service résolvent ce problème en se comportant comme une sorte de « nom d'utilisateur et mot de passe » pour votre service. À l'instar des noms d'utilisateur et des mots de passe, les jetons de service sont constitués de deux parties : un identifiant client et un secret client. L'identifiant et le secret doivent être envoyés avec une requête d'authentification. Une durée est également attribuée aux jetons, au terme de laquelle ils deviennent invalides et doivent être renouvelés. Vous pouvez accorder un jeton de service à votre application et, s'il est validé par les systèmes nécessaires en amont, votre service peut récupérer les informations auprès de la compagnie aérienne et de l'hôtel, afin de les présenter à l'utilisateur final dans un rapport commun.
Lorsqu'un administrateur crée un jeton de service Cloudflare, nous générons la paire identifiant client et secret client. Un client peut ensuite configurer son service émettant la requête afin qu'il transmette ces deux valeurs sous forme d'en-têtes HTTP lorsqu'il doit accéder à une ressource protégée. Le service émettant la requête peut s'exécuter dans n'importe quel environnement, notamment à l'intérieur du réseau de Cloudflare, sous la forme d'une instance Workers, ou dans un emplacement distinct, tel qu'un fournisseur de cloud public. Le client doit déployer la ressource protégée correspondante derrière le proxy inverse de Cloudflare. Notre réseau vérifie les en-têtes HTTP de chaque requête destinée à un service configuré. S'ils sont présents, Cloudflare valide leur authenticité et bloque ou autorise la requête. Nous journalisons également l'événement d'authentification.
Chronologie de l'incident
Toutes les informations d'horodatage sont au format UTC.
Le 24-01-2023 à 16h55, l'équipe d'ingénierie d'Access a publié la version qui a malencontreusement commencé à écraser les métadonnées des jetons de service, provoquant l'incident.
Le 24-01-2023 à 17h05, un membre de l'équipe d'ingénierie d'Access a remarqué un problème sans lien avec l'incident et a annulé la publication de la version, empêchant tout nouvel écrasement des métadonnées des jetons de service.
Les valeurs des jetons de service ne sont pas mises à jour sur le réseau de Cloudflare tant que le jeton de service lui-même n'est pas mis à jour (plus de détails ci-dessous) ; les répercussions des jetons de service dont les métadonnées ont été écrasées ont donc été échelonnées.
24-01-2023 à 17h50 : le premier jeton de service invalide pour Cloudflare WARP a été synchronisé avec notre réseau mondial. L'incident a commencé à affecter les utilisateurs des solutions WARP et Zero Trust.
Les transferts d'informations sur le niveau de sécurité des appareils de WARP ont atteint zéro, déclenchant une alerte interne
Le 24-01-2023 à 18h12, un incident a été déclaré en raison de la forte augmentation du nombre d'échecs de transferts d'informations sur le niveau de sécurité des appareils de WARP.
24-01-2023 à 18h19 : le premier jeton de service invalide pour l'API Cloudflare a été synchronisé avec notre réseau mondial. L'incident a commencé à affecter Cache Purge, Cache Reserve, Images et R2. Des alertes ont été déclenchées pour ces produits, révélant que la portée de l'incident était plus importante.
Le 24-01-2023 à 18h21, les jetons de services écrasés ont été découverts lors de l'enquête initiale.
Le 24-01-2023 à 18h28, le niveau de l'incident a été élevé, afin d'inclure tous les produits affectés.
Le 24-01-2023 à 18h51, une solution initiale a été identifiée et mise en œuvre, afin de restaurer la valeur d'origine du jeton de service pour le compte Cloudflare WARP, qui affectait les solutions WARP et Zero Trust. Les répercussions ont pris fin pour WARP et Zero Trust.
Le 24-01-2023 à 18h56, la même solution a été mise en œuvre sur le compte de l'API Cloudflare, qui affectait Cache Purge, Cache Reserve, Images et R2. Les répercussions ont pris fin pour Cache Purge, Cache Reserve, Images et R2.
Le 24-01-2023 à 19h00, une mise à jour a été effectuée sur le compte de l'API Cloudflare, entraînant l'écrasement incorrect du compte de l'API Cloudflare. L'incident a de nouveau affecté Cache Purge, Cache Reserve, Images et R2. Toute modification interne sur le compte Cloudflare a ensuite été interdite jusqu'à la résolution de l'incident.
Le 24-01-2023 à 19h07, l'API Cloudflare a été mise à jour avec la valeur correcte du jeton de service. Les répercussions ont pris fin pour Cache Purge, Cache Reserve, Images et R2.
Le 24-01-2023 à 19h51, les jetons de service de tous les comptes affectés par l'incident ont été restaurés à partir d'une sauvegarde de la base de données. L'incident a pris fin.
Quelles données ont été publiées, et comment ont-elles provoqué l'incident ?
L'équipe d'Access déployait une nouvelle modification des jetons de service, permettant d'ajouter un champ « dernier accès le ». Il s'agissait d'une demande de fonctionnalité populaire, qui faciliterait l'identification des jetons de service activement utilisés.
Que s’est il passé ?
La valeur « dernier accès le » était obtenue en analysant tous les nouveaux événements de connexion dans la file d'attente Kafka des événements de connexion d'un compte. Si un événement de connexion utilisant un jeton de service était détecté, une mise à jour de la valeur « dernier accès le » du jeton de service correspondant était initiée.
Pour mettre à jour la valeur « dernier accès le » du jeton de service, une transaction de lecture/écriture était exécutée, afin de collecter les informations sur le jeton de service correspondant. Les requêtes de lecture du jeton de service supprimaient, par défaut, la valeur « secret client », pour des raisons de sécurité. La mise à jour « dernier accès le » du jeton de service utilisait ensuite les informations issues de la lecture, qui n'incluaient pas le « secret client » et, lors de l'écriture, mettait à jour le jeton de service avec un « secret client » vide.
Un exemple des valeurs correctes et incorrectes du jeton de service est présenté ci-dessous :
Exemple de valeurs de jeton de service d'Access
La base de données de « secrets client » du jeton de service appliquait une vérification de type « non nul », mais dans cette situation, une chaîne de texte vide n'était pas considérée comme une valeur nulle.
{
"1a4ddc9e-a1234-4acc-a623-7e775e579c87": {
"client_id": "6b12308372690a99277e970a3039343c.access",
"client_secret": "<hashed-value>", <-- what you would expect
"expires_at": 1698331351
},
"23ade6c6-a123-4747-818a-cd7c20c83d15": {
"client_id": "1ab44976dbbbdadc6d3e16453c096b00.access",
"client_secret": "", <--- this is the problem
"expires_at": 1670621577
}
}
En raison de ce bug, pour tout compte Cloudflare utilisant un jeton de service pour s'authentifier pendant les 10 minutes durant lesquelles la version avec « dernier accès le » était publiée, la valeur du « secret client » était définie sur une chaîne vide. Le jeton de service devait ensuite être modifié, de sorte que la valeur « secret client » vide soit utilisée lors de l'authentification. Au total, quatre comptes, tous internes à Cloudflare, se trouvaient dans cet état.
Comment avons-nous résolu le problème ?
À titre de solution temporaire, nous avons pu restaurer manuellement les valeurs correctes des jetons de service pour les comptes dont les jetons de service avaient été écrasés. Cela a mis fin aux répercussions immédiates pour les services Cloudflare affectés.
L'équipe responsable de la base de données a ensuite pu mettre en œuvre une solution afin de restaurer, depuis une ancienne copie de la base de données, les jetons de service de tous les comptes affectés. Ceci a mis fin à toute répercussion liée à cet incident.
Pourquoi cet incident a-t-il affecté d'autres services Cloudflare ?
Les jetons de service affectent la capacité des comptes à s'authentifier, et deux des comptes concernés sont utilisés par plusieurs services Cloudflare. Lorsque les jetons de service de ces comptes ont été écrasés, les services fonctionnant sur ces comptes ont commencé à être affectés par des échecs de requêtes et d'autres erreurs inattendues.
Inscription à Cloudflare WARP
Cloudflare fournit un proxy de transfert pour appareils mobiles et postes de travail, Cloudflare WARP (notre application « 1.1.1.1 »), que tout utilisateur peut installer sur un appareil afin d'améliorer la confidentialité de son trafic Internet. Toute personne peut installer ce service sans avoir besoin d'un compte Cloudflare, et nous ne conservons pas de journaux reliant l'activité à un utilisateur.
Lorsqu'un utilisateur se connecte avec WARP, Cloudflare valide l'inscription d'un appareil en faisant appel à un service qui reçoit et valide les clés de l'appareil. À son tour, ce service communique avec un autre système, qui informe notre réseau qu'il doit autoriser l'appareil nouvellement inscrit à accéder à notre réseau.
Pendant l'incident, le service d'inscription ne pouvait plus communiquer avec les systèmes de notre réseau qui assuraient la validation de l'appareil. Par conséquent, les utilisateurs ne pouvaient plus enregistrer de nouveaux appareils et/ou installer l'application sur un nouvel appareil, et pouvaient rencontrer des difficultés s'ils effectuaient une mise à niveau vers une nouvelle version de l'application (qui déclenche également un nouvel enregistrement).
Niveau de sécurité des appareils et politiques de réauthentification de Cloudflare Zero Trust
Cloudflare fournit une solution Zero Trust complète, que les clients peuvent déployer avec ou sans agent résidant sur l'appareil. Certains scénarios d'utilisation sont uniquement disponibles lorsque l'agent Cloudflare est présent sur l'appareil. L'agent est une version pour entreprise de la solution Cloudflare WARP, et était affecté de manière similaire chaque fois qu'il devait envoyer ou recevoir des informations d'état de l'appareil. Cela a affecté trois scénarios d'utilisation de Cloudflare Zero Trust.
Tout d'abord, à l'instar du produit grand public, de nouveaux appareils ne pouvaient pas être inscrits, et les appareils existants ne pouvaient pas être révoqués. Par ailleurs, les administrateurs ne pouvaient pas modifier les paramètres des appareils inscrits. Dans tous les cas, des erreurs étaient présentées à l'utilisateur.
Deuxièmement, de nombreux clients qui substituent la solution Zero Trust de Cloudflare à leur réseau privé existant peuvent ajouter des règles permettant de valider continuellement l'identité d'un utilisateur, par l'application de politiques de durée de session. L'objectif de ces règles est d'obliger les utilisateurs à se réauthentifier, afin d'empêcher les sessions expirées de conserver un accès permanent aux systèmes internes. L'agent résidant sur l'appareil invite l'utilisateur à se réauthentifier en fonction des signaux provenant du plan de contrôle de Cloudflare. Pendant l'incident, les signaux n'étaient pas envoyés, et les utilisateurs ne pouvaient pas se réauthentifier avec succès.
Enfin, les clients utilisant les règles de niveau de sécurité des appareils ont également été affectés par l'incident. Les règles de niveau de sécurité des appareils permettent aux clients utilisant les politiques Access ou Gateway de se fier à l'agent WARP pour s'assurer en permanence qu'un appareil est conforme aux règles de conformité de l'entreprise.
L'agent communique ces signaux à un service Cloudflare chargé de gérer l'état de l'appareil. Le produit de contrôle d'accès Zero Trust de Cloudflare utilise un jeton de service pour recevoir ce signal et l'évaluer avec d'autres règles, afin de déterminer si un utilisateur est autorisé à accéder à une ressource donnée. Pendant cet incident, ces règles ont été définies, par défaut, sur une action de blocage ; le trafic modifié par ces politiques semblait donc interrompu pour l'utilisateur. Dans certains cas, cela signifiait que tout le trafic destiné à Internet provenant d'un appareil était complètement bloqué, et que les utilisateurs ne pouvaient plus accéder à quelque ressource que ce soit.
Cloudflare Gateway met en cache l'état du niveau de sécurité des appareils pour les utilisateurs toutes les 5 minutes, afin d'appliquer les politiques Gateway. L'état du niveau de sécurité des appareils est mis en cache, afin de permettre à Gateway d'appliquer des politiques sans devoir vérifier l'état de l'appareil à chaque requête. Selon le type de politique Gateway correspondant, l'utilisateur obtenait deux résultats différents. Si l'utilisateur correspondait à une politique réseau, sa connexion était interrompue, et s'il correspondait à une politique HTTP, il voyait s'afficher une page d'erreur 5XX. Nous avons atteint un pic de plus de 50 000 erreurs 5XX/minute de plus que la valeur de référence et avons constaté plus de 10,5 millions d'erreurs de lecture du niveau de sécurité jusqu'à la résolution de l'incident.
Erreurs 5XX par minute de Gateway
Nombre total d'erreurs de niveau de sécurité des appareils de Gateway
Cloudflare R2 Storage et Cache Reserve
Cloudflare R2 Storage permet aux développeurs de stocker de grands volumes de données non structurées sans devoir s'acquitter des frais de trafic sortant élevés que comportent habituellement les offres de stockage dans le cloud.
Pendant l'incident, le service R2 n'a pas été en mesure de transmettre des requêtes sortantes de l'API à d'autres parties de l'infrastructure Cloudflare. Par conséquent, les utilisateurs de R2 ont constaté un taux élevé d'échec des requêtes transmises à R2.
De nombreux produits Cloudflare dépendent également de R2 pour le stockage des données, et ont également été affectés. Par exemple, les utilisateurs de Cache Reserve ont été affectés pendant la durée de l'incident, et ont constaté une augmentation de la charge d'origine pour tout élément ne se trouvant pas dans le cache primaire. La majorité des opérations de lecture et d'écriture dans le service Cache Reserve ont été affectées pendant cet incident, entraînant une défaillance des entrées et sorties de Cache Reserve. Toutefois, lorsque Cache Reserve détecte une erreur R2, le service se replie sur le serveur d'origine du client ; par conséquent, le trafic utilisateur était toujours pris en charge pendant la durée de l'incident.
Cloudflare Cache Purge
Le réseau de diffusion de contenu (CDN) de Cloudflare met en cache le contenu des propriétés Internet hébergées sur notre réseau dans nos datacenters, situés dans le monde entier, afin de réduire la distance que doit parcourir la requête d'un utilisateur pour obtenir une réponse. Dans certains cas, les clients peuvent souhaiter purger les données que nous mettons en cache et les remplacer par des données différentes.
Le plan de contrôle Cloudflare (c'est-à-dire l'endroit depuis lequel un administrateur interagit avec notre réseau) utilise un jeton de service pour s'authentifier et joindre le service Cache Purge. Pendant l'incident, de nombreuses requêtes de purge ont échoué tant que le jeton de service était invalide. Nous avons observé un taux d'échec moyen de 20 requêtes de purge/seconde, avec un taux d'échec maximum atteignant 70 requêtes/seconde.
Que faisons-nous pour éviter que cela ne se reproduise ?
Nous prenons ce type d'incident au sérieux et nous sommes conscients de ses répercussions. Nous avons identifié plusieurs dispositions que nous pouvons prendre pour éviter qu'un problème similaire ne se reproduise à l'avenir. Suite à cet incident, nous mettons en œuvre le plan d'action correctif suivant :
Tester : l'équipe d'ingénierie d'Access ajoutera des tests individuels qui permettront de détecter automatiquement d'éventuels problèmes similaires, liés à l'écrasement de jetons de service, préalablement au lancement de toute nouvelle fonctionnalité.
Alerte : l'équipe Access mettra en œuvre une alerte automatique en cas d'augmentation considérable du nombre d'échecs de requêtes d'authentification par jeton de service, afin de détecter d'éventuels problèmes avant qu'ils ne se manifestent pleinement.
Remédier : l'équipe Access a identifié des améliorations de processus qui permettront d'effectuer des restaurations plus rapides pour des tables de base de données spécifiques.
Mise en œuvre : tous les champs pertinents des bases de données seront mis à jour pour inclure des vérifications des chaînes vides, en plus des vérifications « non nul » existantes.
Nous sommes désolés pour les perturbations que cet incident a entraînées pour nos clients, et qui ont affecté plusieurs services Cloudflare. Nous nous employons activement à apporter ces améliorations, afin de garantir une meilleure stabilité à l'avenir et d'éviter que ce problème ne se reproduise.