BeyondProd : une nouvelle approche de la sécurité cloud native

Google a rédigé plusieurs livres blancs décrivant les projets développés en interne qui contribuent à améliorer la sécurité. BeyondProd reprend délibérément les concepts de BeyondCorp : de la même façon qu'un modèle de périmètre de sécurité ne fonctionne plus pour les utilisateurs finaux, il ne fonctionne plus pour les microservices. Ainsi, une adaptation de l'article original sur BeyondCorp aux microservices donnerait : "les hypothèses clés de ce modèle ne sont plus valides : le périmètre ne se limite plus à l'emplacement physique de l'entreprise [du centre de données]. L'intérieur du périmètre n'est plus un espace sûr et sécurisé pour héberger des appareils informatiques personnels et des applications d'entreprise [des microservices]."

Dans ce livre blanc, nous expliquons comment plusieurs éléments de l'infrastructure Google fonctionnent ensemble pour protéger les charges de travail, selon une architecture désormais connue sous le nom d'"architecture cloud native". Pour en savoir plus sur la sécurité de Google, consultez le livre blanc Présentation de la sécurité sur l'infrastructure de Google.

Le contenu du présent livre blanc est réputé correct et représente l'état des connaissances à sa date de rédaction, soit décembre 2019. Les règles et les systèmes de sécurité de Google Cloud peuvent évoluer à mesure que nous améliorons la protection de nos utilisateurs.

Glossaire

Les définitions suivantes sont utilisées dans ce document :

  • Un microservice sépare les tâches individuelles d'une application en services distincts, chacun pouvant être développé et géré indépendamment, avec ses propres API, déploiement, scaling et gestion des quotas. Dans une architecture plus moderne, une application, telle qu'un site Web, peut être exécutée comme un ensemble de microservices et non comme un service monolithique unique. Les microservices sont indépendants, modulaires, dynamiques et éphémères. Ils peuvent être répartis sur de nombreux hôtes, clusters ou même dans le cloud.

  • Une charge de travail est une tâche unique accomplie par une application. Dans une architecture de microservices, une charge de travail peut correspondre à un ou plusieurs microservices.

  • Une tâche est une instance unique d'un microservice qui exécute une partie d'une application.

  • Un microservice utilise une identité de service pour s'authentifier auprès des autres services exécutés dans l'infrastructure.

  • Un maillage de services est une couche dédiée de l'infrastructure pour la communication entre les services, permettant de contrôler le trafic, d'appliquer des règles et de surveiller les appels de service de manière centralisée. Lorsque vous utilisez une architecture de microservices, les services individuels ne sont plus obligés de mettre en œuvre ces commandes, permettant une gestion simplifiée et centralisée pour de nombreux microservices.

Résumé à l'intention des responsables informatiques

  • L'infrastructure de Google déploie les charges de travail sous forme de microservices individuels dans des conteneurs et gère ces charges de travail à l'aide de Borg, notre système d'orchestration de conteneurs. Il s'agit d'une source d'inspiration et d'un modèle pour ce que l'on appelle aujourd'hui une "architecture cloud native".

  • L'infrastructure de Google a été conçue dès le départ dans un souci de sécurité. Elle n'accorde aucune confiance a priori entre les services.

  • Google protège ses microservices grâce à une initiative baptisée BeyondProd. Cette protection inclut la modification du code et l'accès aux données utilisateur dans les microservices. BeyondProd applique des concepts tels que les points de terminaison de service mutuellement authentifiés, la sécurité des données en transit, la terminaison avec équilibrage de charge global et la protection en cas de déni de service, la provenance de code de bout en bout, et l'isolation (bac à sable) de l'environnement d'exécution.

  • Pour passer d'un modèle de sécurité traditionnel à un modèle de sécurité cloud native, nous avons dû apporter des modifications dans deux domaines principaux : notre infrastructure et notre processus de développement. La création de composants partagés dans une structure partagée enveloppant et connectant tous les microservices, également appelée maillage de services, a facilité le déploiement des modifications et l'obtention d'une sécurité homogène entre les services.

Motivations

Google a opté pour des conteneurs et l'orchestration de conteneurs afin d'optimiser l'utilisation des ressources, de créer des applications hautement disponibles et de simplifier le travail des développeurs Google. Mais notre passage à une infrastructure conteneurisée avait également un autre objectif : aligner nos contrôles de sécurité sur notre architecture. Il était devenu clair pour nous qu'un modèle de sécurité périmétrique n'était pas suffisamment sécurisé. Si un pirate venait à percer le périmètre, il serait libre de se déplacer dans le réseau. Nous avions besoin de renforcer les contrôles de sécurité de notre infrastructure, mais nous souhaitions également faciliter l'écriture et le déploiement d'applications sécurisées pour les développeurs Google.

Le passage des applications monolithiques aux microservices distribués déployés à partir de conteneurs à l'aide d'un système d'orchestration offre des avantages opérationnels tangibles : une évolutivité et une gestion simplifiée. Cette architecture cloud native a nécessité un modèle de sécurité et des outils différents pour protéger les déploiements alignés sur les avantages des microservices en matière de gestion et d'évolutivité.

Ce document décrit la mise en œuvre du modèle de sécurité cloud native au sein de Google, appelé ici BeyondProd : ce que le passage à une infrastructure cloud native implique pour la sécurité, les principes de sécurité d'une telle architecture, les systèmes conçus pour répondre à ces exigences et des conseils pour aborder vous-même un changement similaire.

La sécurité cloud native chez Google

Microservices conteneurisés

Dès ses débuts, Google a décidé de développer la capacité de son centre de données à partir de serveurs peu coûteux, plutôt que d'investir dans du matériel à disponibilité élevée et plus cher. Notre principe directeur pour la fiabilité est que la défaillance d'une partie d'un système ne doit pas affecter la disponibilité des services visibles par l'utilisateur. Pour atteindre cette disponibilité, il était nécessaire d'exécuter des instances de services redondantes de sorte qu'une simple défaillance n'entraîne pas d'interruption. Le développement des conteneurs, des microservices et de l'orchestration des conteneurs a ainsi permis de gérer de manière évolutive le déploiement de ces systèmes hautement redondants et distribués.

Une infrastructure conteneurisée signifie que chaque charge de travail est déployée sous la forme d'un ensemble unique de conteneurs immuables, mobiles et planifiables. Pour gérer ces conteneurs en interne, nous avons développé un système d'orchestration de conteneurs appelé Borg1, que nous utilisons encore aujourd'hui pour le déploiement de plusieurs milliards de conteneurs par semaine.

Les conteneurs facilitent la répartition des charges de travail et les replanifient sur les machines. Les microservices facilitent le développement et le débogage des différentes parties d'une application. Utilisés conjointement, les microservices et les conteneurs permettent de diviser les charges de travail en unités plus petites, plus gérables pour la maintenance et la découverte. Le passage à une infrastructure conteneurisée avec une architecture de microservices permet d'obtenir ce que l'on appelle une "infrastructure cloud native". Les services sont exécutés dans des conteneurs déployés par Borg. Cette architecture adapte les charges de travail selon les besoins : en cas de forte demande pour une charge de travail spécifique, plusieurs machines exécutent des copies du même service afin de répondre à l'ampleur de la charge de travail requise.

Nous insistons sur le fait que nous avons pris en compte la sécurité dans toutes les évolutions de notre architecture. Le concept d'architecture de sécurité cloud native le plus récent est comparable à celui utilisé par Google pendant de nombreuses années pour sécuriser notre infrastructure. Avec cette architecture de microservices et processus de développement, notre objectif est de résoudre les problèmes de sécurité le plus tôt possible dans le cycle de développement et de déploiement (lorsque la résolution des problèmes est moins coûteuse), et de façon uniforme et cohérente. Cela permet ainsi aux développeurs de passer moins de temps sur des tâches de sécurité tout en obtenant des résultats plus sécurisés.

Migrer vers une architecture cloud native

Les architectures de sécurité modernes ont évolué au-delà d'un modèle de sécurité périmétrique traditionnel, où un mur protège le périmètre et où tous les utilisateurs et services sont entièrement fiables. BeyondCorp a été la réponse à un changement du mode de fonctionnement des entreprises modernes. Aujourd'hui, les utilisateurs sont mobiles et opèrent généralement en dehors du périmètre de sécurité traditionnel d'une organisation, par exemple depuis un café, un avion ou ailleurs. Dans BeyondCorp, nous avons renoncé à l'idée d'un réseau d'entreprise privilégié pour autoriser l'accès uniquement en fonction des identifiants et des attributs des utilisateurs et des appareils, indépendamment de la localisation du réseau.

La sécurité cloud native répond à la même préoccupation, pour les services comme pour les utilisateurs : dans un monde cloud natif, nous ne pouvons pas nous contenter d'un pare-feu pour protéger le réseau de production, tout comme nous ne pouvons pas compter sur un pare-feu pour protéger le réseau de l'entreprise. De la même manière que les utilisateurs n'utilisent pas tous le même emplacement physique ou le même appareil, les développeurs ne déploient pas tous le code dans le même environnement. Avec BeyondProd, les microservices peuvent fonctionner non seulement dans un centre de données protégé par un pare-feu, mais également dans des clouds publics, des clouds privés ou des services hébergés par des tiers, et ils doivent être sécurisés à tout moment.

À l'image des utilisateurs qui se déplacent, utilisent des appareils différents et se connectent depuis différents lieux, les microservices se déplacent également et sont déployés dans différents environnements, sur des hôtes hétérogènes. Tandis que dans le cas de BeyondCorp "la confiance de l'utilisateur doit dépendre de caractéristiques telles que l'état contextuel des appareils et non de la possibilité de se connecter au réseau d'entreprise", avec BeyondProd "la confiance du service doit dépendre de caractéristiques telles que l'origine du code et l'identité du service, pas de l'emplacement dans le réseau de production, tel que l'adresse IP ou l'identité du nom d'hôte".

Cloud natif et développement d'applications

Un modèle de sécurité plus traditionnel, axé sur la sécurité périmétrique, ne peut pas protéger seul une architecture cloud native. Prenons l'exemple suivant : une application monolithique utilisant une architecture à trois niveaux est déployée dans un centre de données privé disposant de suffisamment de capacité pour gérer la charge maximale des événements critiques. Les applications présentant des exigences spécifiques en termes de matériel ou de réseau sont volontairement déployées sur des machines spécifiques qui, en général, disposent d'adresses IP fixes. Les déploiements sont peu fréquents, volumineux et difficiles à coordonner, car les modifications qui en résultent affectent simultanément de nombreuses parties de l'application. Cela conduit à des applications de très longue durée qui sont mises à jour moins fréquemment et pour lesquelles les correctifs de sécurité sont généralement appliqués de manière moins fréquente.

Toutefois, dans un modèle cloud natif, les conteneurs dissocient les binaires requis par votre application du système d'exploitation hôte sous-jacent, rendant les applications plus portables. Les conteneurs sont conçus pour être utilisés de manière immuable, ce qui signifie qu'une fois déployés, ils ne changent pas. Ils sont donc fréquemment reconstruits et redéployés. Les tâches évoluent pour gérer la charge : de nouvelles tâches sont déployées lorsque la charge augmente et des tâches existantes sont supprimées lorsque la charge diminue. Les conteneurs étant redémarrés, supprimés ou reprogrammés fréquemment, la réutilisation et le partage du matériel et des réseaux sont plus fréquents. Avec un processus de conception et de distribution standard, le processus de développement est plus homogène et uniforme entre les équipes, même si les équipes gèrent indépendamment le développement de leurs microservices. Par conséquent, les considérations de sécurité (par exemple, les examens de sécurité, l'analyse des codes et la gestion des failles) peuvent intervenir plus tôt dans le cycle de développement.

Implications pour la sécurité

Nous avons beaucoup parlé de la façon dont le modèle de périmètre intérieur non approuvé, avec des utilisateurs dans BeyondCorp, peut également s'appliquer aux microservices dans BeyondProd. Mais à quoi ressemble ce changement ? Le tableau 1 fournit une comparaison entre les aspects de la sécurité traditionnelle de l'infrastructure et leurs similitudes dans une architecture cloud native. Le tableau indique également les conditions requises pour passer de l'une à l'autre. Le reste de cette section fournit des informations supplémentaires sur chaque ligne du tableau.

Sécurité traditionnelle de l'infrastructure Sécurité cloud native Exigences implicites relatives à la sécurité cloud native
Sécurité basée sur le périmètre (par exemple, pare-feu), avec des communications internes considérées comme fiables. Sécurité "zéro confiance", avec la vérification des communications entre les services, et sans confiance implicite pour les services de l'environnement. Protection du réseau en périphérie (reste applicable) et pas de confiance mutuelle inhérente entre les services.
Adresses IP et matériel fixes pour certaines applications. Meilleure utilisation, réutilisation et partage des ressources, y compris des adresses IP et du matériel. Machines fiables exécutant un code de provenance connue.
Identité basée sur l'adresse IP. Identité basée sur le service.
Les services sont exécutés à un emplacement connu et attendu. Les services, y compris les déploiements hybrides entre le cloud public et les centres de données privés, peuvent être exécutés n'importe où dans l'environnement.
Exigences spécifiques à la sécurité intégrées dans chaque application et appliquées séparément. Exigences de sécurité partagées intégrées dans des piles de service, conformément à une politique d'application centralisée. Des goulots d'étranglement pour assurer une application cohérente des règles dans les différents services.
Restrictions limitées concernant la conception et l'examen des services. Exigences de sécurité appliquées systématiquement à tous les services.
Surveillance limitée des composants de sécurité. Vue centralisée des règles de sécurité et du respect des règles.
Déploiements spécialisés et peu fréquents. Processus standard de compilation et de déploiement avec des modifications plus fréquentes de chaque microservice. Déploiement simple, automatisé et standardisé des modifications.
Les charges de travail sont généralement déployées sous forme de VM ou sur des hôtes physiques en utilisant une machine physique ou un hyperviseur pour fournir une isolation. Les charges de travail réparties et leurs processus s'exécutent dans un système d'exploitation partagé, nécessitant un mécanisme pour isoler les charges de travail. Isolement entre les charges de travail partageant un système d'exploitation.

Tableau 1 : Exigences implicites relatives à la sécurité lors de la migration vers une architecture cloud native.

De la sécurité périmétrique à la sécurité "zéro confiance"

Dans un modèle de sécurité traditionnel, les applications d'une organisation peuvent dépendre d'un pare-feu externe entourant son centre de données privé pour le protéger du trafic entrant. Dans un environnement cloud natif, bien que le périmètre du réseau doive encore être protégé comme dans le modèle BeyondCorp, un modèle de sécurité basé sur le périmètre ne suffit plus. Ce modèle n'entraîne pas de nouveau problème de sécurité, mais à l'évidence, si un pare-feu ne protège pas entièrement le réseau d'entreprise, il ne pourra pas non plus protéger entièrement le réseau de production. Avec un modèle de sécurité "zéro confiance", vous ne pouvez plus faire confiance implicitement au trafic interne. D'autres contrôles de sécurité sont nécessaires, tels que l'authentification et le chiffrement. Parallèlement à cela, la transition vers les microservices offre l'occasion de revoir le modèle de sécurité traditionnel. En ne dépendant plus d'un seul périmètre de réseau (par exemple un pare-feu), il est possible de segmenter davantage le réseau par service. Pour aller plus loin, il est possible de mettre en œuvre la segmentation au niveau du service, sans confiance inhérente entre les services. Avec les microservices, le trafic peut avoir différents niveaux de confiance et différents contrôles. Vous ne comparez désormais plus uniquement le trafic interne au trafic externe.

Des adresses IP et matériel fixes à des ressources partagées plus importantes

Dans un modèle de sécurité traditionnel, les applications d'une organisation étaient déployées sur des machines spécifiques, et les adresses IP de ces machines changeaient rarement. Cela signifiait que les outils de sécurité pouvaient se baser sur un schéma d'architecture relativement statique associant des applications de manière prévisible (les règles de sécurité des outils, tels que les pare-feu, utilisant des adresses IP comme identifiants).

Toutefois, dans un monde cloud natif, avec des hôtes partagés et des tâches qui changent fréquemment, l'utilisation d'un pare-feu pour contrôler l'accès entre les microservices ne fonctionne pas. On ne peut plus compter sur le fait qu'une adresse IP spécifique est liée à un service particulier. Par conséquent, au lieu de baser l'identité sur une adresse IP ou un nom d'hôte, on base la demande sur un service.

Des implémentations de sécurité spécifiques aux applications aux exigences de sécurité partagées intégrées aux piles de services

Dans un modèle de sécurité traditionnel, les applications individuelles étaient chacune responsables de leurs propres exigences de sécurité indépendamment des autres services. Ces exigences comprenaient la gestion des identités, la résiliation SSL/TLS et la gestion des accès aux données. Cela entraînait souvent des mises en œuvre incohérentes ou des problèmes de sécurité non résolus, car ces problèmes devaient être résolus en de nombreux endroits, compliquant l'application des correctifs.

Dans le monde cloud natif, les composants sont beaucoup plus souvent réutilisés entre les services et il existe des goulots d'étranglement qui permettent d'appliquer les règles de manière cohérente dans les services. Il est possible d'appliquer différentes règles à l'aide de différents services de sécurité. Plutôt que d'exiger que chaque application mette en œuvre des services de sécurité critiques distinctement, vous pouvez séparer les différentes règles en des microservices distincts (par exemple, une règle pour sécuriser l'accès aux données utilisateur et une autre pour assurer l'utilisation de suites TLS chiffrées à jour).

Des processus de déploiement spécialisés et peu fréquents aux processus standardisés avec des déploiements plus fréquents

Dans un modèle de sécurité traditionnel, les services partagés étaient limités. Un code plus distribué, associé au développement local, rendait difficile l'évaluation de l'impact d'un changement qui affectait de nombreuses parties d'une application. Par conséquent, les déploiements étaient peu fréquents et difficiles à coordonner. Pour apporter une modification, les développeurs pouvaient être amenés à mettre à jour chaque composant directement (par exemple, en passant en SSH dans une machine virtuelle pour mettre à jour une configuration). Dans l'ensemble, cela a conduit à des applications de très longue durée. Du point de vue de la sécurité, plus le code était distribué, plus il était difficile de le vérifier et surtout, lors de la correction d'une faille, de s'assurer que celle-ci était corrigée partout. La migration vers le cloud natif, où les déploiements sont fréquents et standardisés, permet à la sécurité d'effectuer un shift left2 pendant le cycle de développement du logiciel. Cela permet une application plus simple et plus cohérente de l'hygiène de sécurité, y compris l'application régulière de correctifs de sécurité.

Des charges de travail isolées à l'aide de machines physiques ou d'hyperviseurs aux charges de travail réparties sur la même machine nécessitant une isolation plus importante

Dans un modèle de sécurité traditionnel, les charges de travail étaient planifiées sur leurs propres instances, sans ressources partagées. Une application était bien délimitée par les limites de la machine et du réseau, et l'isolation de la charge de travail reposait uniquement sur la séparation physique des hôtes, les hyperviseurs et les pare-feu traditionnels.

Dans un monde cloud natif, les charges de travail sont conteneurisées, et réparties sur des hôtes et des ressources partagés. Par conséquent, il est nécessaire de renforcer l'isolation entre les charges de travail. Les charges de travail peuvent être séparées en microservices qui sont isolés les uns des autres en utilisant les contrôles réseau et les technologies d'isolation.

Principes de sécurité

En développant une architecture cloud native, nous souhaitions renforcer simultanément notre sécurité. Nous avons donc développé et optimisé les principes de sécurité suivants :

  • Protection du réseau à la périphérie, de sorte que les charges de travail soient isolées des attaques réseau et du trafic non autorisé provenant d'Internet. Même si une approche basée sur un mur protecteur n'est pas un concept nouveau pour le cloud natif, elle reste une bonne pratique en termes de sécurité. Dans un monde cloud native, une approche périmétrique protège autant d'infrastructures que possible contre le trafic non autorisé et les attaques potentielles sur Internet, par exemple, les attaques de type déni de service.

  • Aucune confiance mutuelle inhérente entre les services, de sorte que seuls les appelants connus, approuvés et autorisés peuvent utiliser un service. Cela empêche les pirates informatiques d'utiliser un code non approuvé pour accéder à un service. Si un service est piraté, il empêche l'attaquant d'effectuer des actions qui lui permettent d'élargir sa portée. Cette méfiance mutuelle permet de limiter le rayon d'action d'un piratage.

  • Des machines fiables exécutant des codes avec une provenance connue, afin que les identités de service soient obligées d'utiliser uniquement des codes et des configurations autorisés, uniquement dans des environnements autorisés et vérifiés.

  • Des goulots d'étranglement pour assurer une application cohérente des règles dans les différents services. Par exemple, un goulot d'étranglement pour vérifier les demandes d'accès aux données utilisateur, de sorte que l'accès d'un service repose sur une demande validée d'un utilisateur final autorisé et que l'accès d'un administrateur requiert la justification de l'entreprise.

  • Déploiement de modifications simple, automatisé et standardisé, permettant de contrôler facilement l'impact sur la sécurité des modifications apportées à l'infrastructure et de déployer les correctifs de sécurité sans trop d'impact sur la production.

  • Isolement entre les charges de travail partageant un système d'exploitation. Par conséquent, si un service est compromis, il ne peut pas affecter la sécurité d'une autre charge de travail exécutée sur le même hôte. Cela limite le rayon d'action d'un piratage potentiel.

Dans l'ensemble de notre infrastructure, notre objectif est de garantir une sécurité automatisée qui ne dépend pas des individus. La sécurité doit évoluer de la même manière que les services. Les services doivent être sécurisés par défaut et non sécurisés par exception. Les actions humaines doivent être effectuées par exception, et non de manière routinière, et doivent pouvoir être contrôlées lorsqu'elles se produisent. Nous pouvons ensuite authentifier un service en fonction du code et de la configuration déployés pour le service, et non des personnes ayant déployé le service.

La mise en œuvre de ces principes de sécurité signifie que les conteneurs et les microservices internes peuvent être déployés, communiquer et fonctionner côte à côte sans affaiblir les propriétés d'une architecture cloud native (par exemple, gestion facile des charges de travail, évolution no-ops et distribution efficace). Tout cela peut être réalisé sans accabler les développeurs de microservices avec les détails de sécurité et de mise en œuvre de l'infrastructure sous-jacente.

Services de sécurité internes de Google

Pour protéger l'infrastructure cloud native de Google, nous avons conçu et développé plusieurs outils et services internes. Les services de sécurité répertoriés ci-dessous fonctionnent conjointement pour respecter les principes de sécurité définis dans la section Principes de sécurité :

  • Google Front End (GFE) : met fin à la connexion de l'utilisateur final et fournit un point central pour appliquer les bonnes pratiques TLS. Même si nous ne privilégions plus la sécurité périmétrique, le GFE constitue toujours un élément important de notre stratégie de protection des services internes contre les attaques par déni de service. GFE est le premier point d'entrée pour une connexion utilisateur à Google. Une fois dans notre infrastructure, GFE est également chargé de l'équilibrage des charges et de rediriger le trafic entre les régions, si nécessaire. Dans notre infrastructure, GFE est le proxy de périphérie qui dirige le trafic vers le microservice approprié.

  • Application Layer Transport Security (ALTS)  : ce système est utilisé pour l'authentification, l'intégrité et le chiffrement RPC. ALTS est un système d'authentification mutuelle et de chiffrement des données en transit pour les services de l'infrastructure Google. Les identités sont généralement liées à des services et non à un nom de serveur ou un hôte spécifique. Cela facilite la réplication transparente de microservices, l'équilibrage de charge et la replanification entre les hôtes.

  • L'autorisation binaire pour Borg et l'intégrité de l'hôte sont utilisées pour la vérification de l'intégrité du microservice et de la machine, respectivement :

    • Autorisation binaire pour Borg (BAB) : vérifie le respect du temps de déploiement assurant que le code répond aux exigences de sécurité interne avant son déploiement. Les vérifications BAB incluent la vérification des modifications par un deuxième ingénieur, l'envoi du code à notre dépôt de code source et la création de binaires de manière vérifiable sur une infrastructure dédiée. Dans notre infrastructure, l'autorisation binaire pour Borg limite le déploiement de microservices non autorisés.
    • Intégrité de l'hôte (HINT) : vérifie l'intégrité du logiciel hôte via un processus de démarrage sécurisé. Elle est protégée par un microcontrôleur sécurisé, lorsque cela est possible. Les vérifications HINT incluent la vérification des signatures numériques sur le BIOS, le contrôleur BMC, le bootloader et le noyau OS.
  • Les Règles d'accès aux services et les Demandes de contexte de l'utilisateur final permettent de restreindre l'accès aux données :

    • Règles d'accès aux services : elles limitent la façon dont les données sont accessibles entre les services. Lorsqu'un RPC est envoyé d'un service à un autre, les règles d'accès au service définissent les règles d'authentification, d'autorisation et d'audit requises pour accéder aux données du service destinataire. Cela limite la façon dont les données sont accessibles, accorde le niveau minimal d'accès requis et indique comment cet accès peut être contrôlé. Dans l'infrastructure de Google, les règles d'accès au service limitent l'accès d'un microservice aux données d'un autre microservice et permettent des analyses globales des contrôles d'accès.
    • Demandes de contexte de l'utilisateur final (EUC) : ces demandes sont émises par un service d'authentification de l'utilisateur final et fournissent des services avec une identité utilisateur, distincte de leur identité de service. Il s'agit d'identifiants transmissibles, émis au niveau central, dont l'intégrité est protégée et attestant de l'identité d'un utilisateur final qui a demandé le service. Cela réduit le besoin de confiance entre les services, car l'identité de pair via ALTS est souvent insuffisante pour accorder l'accès, ces décisions d'autorisation étant généralement également basées sur l'identité de l'utilisateur final.
  • Outils Borg pour déploiements bleu-vert 3 : cet outil permet de migrer des charges de travail en cours d'exécution en effectuant des tâches de maintenance. Une nouvelle tâche Borg est déployée en plus de la tâche Borg existante, et un équilibreur de charge déplace progressivement le trafic de l'une vers l'autre. Cela permet de mettre à jour un microservice sans temps d'arrêt et sans que l'utilisateur s'en aperçoive. Cet outil permet d'appliquer des mises à niveau lorsque nous ajoutons de nouvelles fonctionnalités et d'appliquer des mises à jour de sécurité critiques sans temps d'arrêt (par exemple, Heartbleed et Spectre/Meltdown. Pour les modifications affectant l'infrastructure Google Cloud, nous utilisons la migration à chaud pour nous assurer que les charges de travail des VM ne sont pas affectées.

  • gVisor, pour l'isolation de la charge de travail. gVisor utilise un noyau d'espace utilisateur pour intercepter et gérer les appels système, réduisant ainsi l'interaction avec l'hôte et la surface d'attaque potentielle. Ce noyau fournit la plupart des fonctionnalités requises pour exécuter une application et limite la surface du noyau hôte accessible à l'application. Dans l'infrastructure Google, gVisor est l'un des principaux outils utilisés pour isoler les charges de travail internes et les charges de travail Google Cloud des clients exécutées sur le même hôte.

Le tableau 2 présente chaque principe décrit dans la section Principes de sécurité avec l'outil correspondant utilisé par Google pour mettre en œuvre ce principe.

Principe de sécurité Outil ou service de sécurité interne de Google
Protection du réseau en périphérie Google Front End (GFE), pour la gestion des terminaisons TLS et des règles relatives au trafic entrant
Pas de confiance mutuelle inhérente entre les services Application Layer Transport Security (ALTS), pour l'authentification RPC, l'intégrité, le chiffrement et les identités de service
Machines fiables exécutant un code de provenance connue Autorisation binaire pour Borg (BAB), pour la vérification de la provenance du code

Intégrité de l'hôte (HINT), pour la vérification de l'intégrité de la machine

Goulots d'étranglement pour assurer une application cohérente des règles dans les différents services Règles d'accès au service, pour limiter la façon dont les données sont accessibles entre les services

Demandes de contexte de l'utilisateur final (EUC), pour attester de l'identité du demandeur d'origine.

Déploiement simple, automatisé et standardisé des modifications Outils Borg, pour les déploiements bleu-vert
Isolement entre les charges de travail partageant un système d'exploitation gVisor, pour l'isolation de la charge de travail

Tableau 2 : principes et outils de sécurité pour la mise en œuvre de la sécurité cloud native chez Google

Synthèse

Dans cette section, nous décrivons comment les composants dont nous avons parlé jusqu'ici s'intègrent pour répondre aux demandes des utilisateurs dans un monde cloud natif. Nous utilisons deux exemples : tout d'abord, nous traçons une demande de renseignements sur un utilisateur standard depuis sa création jusqu'à sa livraison à sa destination. Ensuite, nous traçons un changement de code du développement à la production. Toutes les technologies répertoriées ici ne sont pas utilisées dans tous les éléments de l'infrastructure de Google : elles dépendent des services et des charges de travail.

Accès aux données des utilisateurs

Comme le montre la Figure 1, lorsque GFE reçoit une demande d'un utilisateur (étape 1), il interrompt la connexion TLS et transmet la demande à l'interface du service approprié via ALTS4 (étape 2). L'interface de l'application authentifie la demande de l'utilisateur via un service central d'authentification de l'utilisateur final (EUA) et, en cas de réussite, reçoit une demande de contexte de l'utilisateur (EUC) chiffrée de courte durée (étape 3).

schéma

Figure 1 : contrôles de sécurité de l'architecture cloud native de Google - Accès aux données utilisateur

L'interface de l'application effectue ensuite un RPC via ALTS vers un service de backend de stockage, en transférant la demande EUC dans la requête d'interface (étape 4). Le service de backend utilise des règles d'accès au service pour garantir que :

  1. l'identité ALTS du service d'interface est autorisée à envoyer des requêtes au service de backend et à présenter une demande EUC ;
  2. l'identité de l'interface est protégée par notre autorisation binaire pour Borg (BAB) ;
  3. la demande EUC est valide.

Le service de backend vérifie alors que l'utilisateur de la demande EUC est autorisé à accéder aux données demandées. Si l'une de ces vérifications échoue, la demande est refusée. Dans la plupart des cas, une chaîne d'appels backend est établie et chaque service intermédiaire effectue une vérification des règles d'accès au service sur les appels RPC entrants, et la demande EUC est transférée sur les appels RPC sortants. Si ces vérifications réussissent, les données sont renvoyées à l'interface de l'application autorisée et transmises à l'utilisateur autorisé.

Chaque machine dispose d'un identifiant ALTS provisionné via le système HINT, qui ne peut être déchiffré que si HINT a vérifié que le démarrage de la machine a réussi. La plupart des services Google fonctionnent comme des microservices au-dessus de Borg, et ces microservices possèdent chacun leur propre identité ALTS. Le Borgmaster5 accorde ces identifiants de microservice ALTS aux charges de travail en fonction de l'identité du microservice, comme décrit dans la figure 1. Les certificats ALTS de la machine constituent le canal sécurisé pour la création des identifiants de microservice. Ainsi, seules les machines ayant réussi le processus de démarrage validé HINT peuvent héberger des charges de travail.

Modifier un code

Comme le montre la figure 2, lorsqu'un Googleur modifie un microservice protégé par un BAB suffisamment puissant, la modification doit être envoyée à notre dépôt de code central qui vérifie le code. Une fois approuvée, la modification est envoyée au système central de compilation de confiance qui génère un package avec un certificat manifeste de compilation vérifiable et signé (étape 1). Au moment du déploiement, l'autorisation binaire pour Borg vérifie que ce processus a été suivi par la validation du certificat signé à partir du pipeline de compilation (étape 2).

schéma

Figure 2 : contrôles de sécurité de l'architecture cloud native de Google - Modification du code

Toutes les mises à jour des charges de travail sont gérées via des déploiements bleu-vert, qu'il s'agisse d'un déploiement de routine ou d'un correctif de sécurité d'urgence (étape 3). GFE équilibre la charge du trafic sur le nouveau déploiement afin d'assurer la continuité des opérations.

Toutes les charges de travail nécessitent une isolation. Si la charge de travail est moins fiable, par exemple si elle est mutualisée ou si le code source provient de l'extérieur de Google, elle peut être déployée dans un environnement protégé gVisor ou elle peut utiliser d'autres couches d'isolation. Cette isolation garantit que si une instance de l'application est compromise, aucune des autres instances n'est affectée.

Application de BeyondProd

Tout y passe

En adoptant le cloud natif et en sécurisant de façon appropriée cette infrastructure, Google peut offrir des propriétés de sécurité très performantes pour ses charges de travail internes et externes (Google Cloud).

En créant des composants partagés, la charge imposée aux développeurs pour répondre aux exigences de sécurité les plus courantes est minime. Idéalement, la fonctionnalité de sécurité ne devrait nécessiter aucune intégration ou presque dans chaque application, et être fournie plutôt comme un tissu enveloppant et reliant tous les microservices. C'est ce que l'on appelle généralement un maillage de services. Cela signifie également que la sécurité peut être gérée et mise en œuvre indépendamment des activités de développement ou de déploiement habituelles.

Passage au cloud natif

La transition de Google vers le cloud natif nécessitait des changements dans deux domaines principaux : dans notre infrastructure et dans notre processus de développement. Nous avons abordé ces changements simultanément, mais ils pourraient être dissociés et traités séparément.

Modification de notre infrastructure

Nous avons commencé par créer une base solide d'identité, d'authentification et d'autorisation des services. Le fait de disposer d'identités de service fiables nous a permis de mettre en œuvre des fonctionnalités de sécurité de niveau supérieur en validant ces identités de service, telles que les règles d'accès aux services et les demandes EUC. Pour faciliter la transition des nouveaux services et des services existants, ALTS a d'abord été fourni sous la forme d'une bibliothèque avec un seul daemon d'assistance. Ce daemon a été exécuté sur l'hôte appelé par chaque service et a évolué au fil du temps dans une bibliothèque utilisant les identifiants de service. La bibliothèque ALTS a été intégrée de manière transparente dans la bibliothèque RPC principale. Cela a facilité son adoption à grande échelle, sans peser excessivement sur les équipes de développement individuelles. Le déploiement ALTS était une condition préalable au déploiement des règles d'accès aux services et des demandes EUC.

Modification de nos processus de développement

Pour Google, il était essentiel de mettre en place un processus fiable de compilation et d'examen du code. Cela nous a permis de nous assurer à la fois de l'intégrité des services en cours d'exécution et du caractère significatif des identités utilisées par ALTS. Nous avons mis en place un processus de compilation centralisé qui nous a permis de commencer à appliquer des conditions nécessaires, telles qu'un examen du code par deux personnes et des tests automatisés au moment de la compilation et du déploiement. Pour plus d'informations sur le déploiement, consultez le livre blanc L'autorisation binaire pour Borg.

Une fois les principes de base en place, nous avons commencé à répondre au besoin d'exécuter un code externe non approuvé dans nos environnements. Pour atteindre cet objectif, nous avons commencé l'isolation, d'abord avec ptrace, puis plus tard avec gVisor. De même, les déploiements bleu-vert ont offert un avantage significatif en termes de sécurité (par exemple, application de correctifs) et de fiabilité.

Nous avons rapidement constaté qu'il était plus facile qu'un service démarre par la journalisation des cas de non-respect des règles plutôt que par leur blocage. Cette approche offrait deux avantages. Tout d'abord, elle a permis aux propriétaires de services de tester la modification et d'évaluer l'impact éventuel de l'adoption d'un environnement cloud native sur leur service. Ensuite, elle nous a permis de corriger les bugs éventuels et d'identifier les fonctionnalités supplémentaires que nous devrions éventuellement fournir aux équipes de service. Par exemple, lorsqu'un service est intégré à l'autorisation binaire pour Borg, les propriétaires de service activent le mode audit uniquement. Cela leur permet d'identifier le code ou les workflows qui ne répondent pas à leurs besoins. Une fois qu'ils ont résolu les problèmes signalés par le mode audit uniquement, les propriétaires de services passent en mode d'application. Dans gVisor, nous avons effectué cela en isolant d'abord les charges de travail, malgré des écarts de compatibilité dans les fonctionnalités d'isolation, puis en comblant systématiquement ces écarts pour améliorer l'isolation.

Avantages de la modification

De la même manière que BeyondCorp nous a aidés à évoluer au-delà d'un modèle de sécurité périmétrique, BeyondProd représente un bond en avant dans notre approche de la sécurité de production. L'approche BeyondProd décrit une architecture de sécurité cloud native qui n'accorde aucune confiance a priori entre les services, isole les charges de travail, vérifie que seules les applications centralisées sont déployées, automatise la gestion des failles et applique des contrôles d'accès rigides aux données critiques. L'architecture BeyondProd a conduit Google à innover plusieurs nouveaux systèmes afin de répondre à ces exigences.

Trop souvent, la sécurité est "appelée" en dernier, lorsque la décision de migrer vers une nouvelle architecture a déjà été prise. En faisant appel à votre équipe de sécurité dès la première heure et en vous concentrant sur les avantages du nouveau modèle de sécurité, comme une gestion simplifiée des correctifs et des contrôles d'accès plus stricts, une architecture cloud native peut apporter des avantages significatifs à la fois aux équipes de développement d'applications et de sécurité. Lorsque vous appliquez les principes de sécurité décrits dans cet article à votre infrastructure cloud native, vous pouvez renforcer le déploiement de vos charges de travail, la sécurité des communications de vos charges de travail et leur impact sur d'autres charges de travail.

Remarques

1Borg est le système de gestion des clusters de Google pour planifier et exécuter des charges de travail à grande échelle. Borg était le premier système unifié de gestion des conteneurs de Google, et a inspiré Kubernetes.

2"Shifting left" fait référence aux étapes précédentes du cycle de développement du logiciel, qui peuvent inclure des étapes telles que code, compilation, test, validation et déploiement. Les schémas du cycle de vie sont fréquemment tracés de gauche à droite, de sorte que la gauche indique une étape précédente.

3Un déploiement bleu-vert permet de déployer une modification d'une charge de travail sans affecter le trafic entrant, de sorte que l'utilisateur final ne remarque aucun temps d'arrêt en accédant à l'application.

4Pour mieux comprendre comment le trafic est acheminé à l'intérieur de l'infrastructure de Google, du GFE à un service, consultez la section Routage du trafic de notre livre blanc Chiffrement en transit.

5Borgmaster est le contrôleur centralisé de Borg. Il gère la planification des tâches et transmet le statut des tâches en cours d'exécution.