Configurer un accès basé sur les ressources

Cet article explique comment définir des restrictions d'accès basées sur les ressources à l'aide de liaisons de rôles conditionnelles dans vos règles Cloud IAM (Cloud Identity and Access Management). À l'aide des attributs de ressource situés dans une expression de condition, vous pouvez accorder un sous-champ d'application de la liaison de rôle basée sur le nom de ressource, le type de ressource et/ou le service Google Cloud.

Avant de commencer

  • Consultez la présentation des conditions Cloud IAM pour comprendre les principes de base des règles conditionnelles Cloud IAM.
  • Examinez les attributs de ressource qui peuvent être utilisés dans une expression de condition.
  • L'attribut de nom de ressource peut contrôler l'accès aux services Google Cloud suivants :
    • Compute Engine
    • Cloud Key Management Service
    • Cloud Storage
    • Cloud Spanner

Accorder l'accès à un groupe de ressources en fonction des préfixes des noms de ressources

Une liaison de rôle conditionnelle permet d'accorder l'accès aux membres pour les ressources dont les noms correspondent à un préfixe, comme les instances de machine virtuelle (VM) Compute Engine dont le nom commence par une chaîne spécifique. Le préfixe du nom de la ressource permet généralement de regrouper des ressources destinées à certaines fonctionnalités ou possédant certaines propriétés.

Prenons l'exemple suivant : la société de logiciels ExampleCo exécute des charges de travail sur certaines instances de VM susceptibles de fonctionner avec des données médicales sensibles. Les autres charges de travail non sensibles doivent être exécutées dans le même projet et ExampleCo veut s'assurer que ses développeurs disposent d'un accès limité aux instances de VM compatibles avec des données sensibles. Pour atteindre cet objectif, les instances de VM sensibles aux données sont dotées du préfixe sensitiveAccess et les autres instances de VM du préfixe devAccess. Ensuite, les liaisons de rôles conditionnelles permettent aux développeurs de rester productifs avec des instances de VM devAccess standards tout en limitant l'accès aux instances de VM sensitiveAccess.

Vous pouvez utiliser l'attribut de condition resource.name seul pour restreindre l'accès, mais il est courant de lui associer des attributs resource.type et resource.service spécifiques pour réduire les risques d'attribution en excès ou de sous-attribution sur des ressources portant des noms semblables, mais dotées de types différents. L'exemple de cette section spécifie des restrictions d'accès à l'aide des attributs resource.name et resource.type.

Pour accorder un accès basé sur un préfixe de nom aux disques et aux instances Compute Engine dans un projet :

Console

  1. Ouvrez la page "IAM" dans Cloud Console.

    Ouvrir la page IAM

  2. Cliquez sur Sélectionner un projet, choisissez un projet et cliquez sur Ouvrir.

  3. Dans la liste des membres, localisez le membre souhaité, puis cliquez sur le bouton .

  4. Dans le panneau Modifier les autorisations, localisez le rôle pour lequel vous souhaitez configurer une condition. Sous Condition, cliquez sur Ajouter une condition.

  5. Dans le panneau Modifier la condition, saisissez un titre et une description facultative pour la condition.

  6. Vous pouvez ajouter une expression de condition à l'aide du Créateur de conditions ou de l'Éditeur de conditions. L'outil Créateur de conditions fournit une interface interactive permettant de sélectionner le type de condition, l'opérateur et d'autres informations applicables concernant l'expression. L'outil Éditeur de conditions fournit une interface textuelle permettant de saisir manuellement une expression à l'aide de la syntaxe CEL.

    Créateur de conditions

    1. Cliquez sur le menu déroulant Ajouter, puis cliquez sur Conditions groupées.
    2. Dans le menu déroulant Type de condition, sélectionnez Ressource Type.
    3. Dans le menu déroulant Opérateur, sélectionnez c'est.
    4. Dans le menu déroulant Type de ressource, sélectionnez compute.googleapis.com/Disk.
    5. Cliquez sur le premier bouton Ajouter juste en dessous de la condition que vous venez d'ajouter pour inclure une clause à l'expression.
    6. Dans le menu déroulant Type de condition, sélectionnez Ressource Nom.
    7. À partir du menu déroulant Opérateur, sélectionnez Commence par.
    8. Dans le champ Valeur, saisissez le nom de la ressource au format approprié, tel que projects/project-123/zones/us-central1-a/disks/devAccess pour un disque dont le nom commence par devAccess.
    9. À gauche de chaque type de condition, cliquez sur Et pour vous assurer que les deux clauses doivent être vraies.
    10. Cliquez sur le bouton Ajouter situé juste au-dessus du bouton Enregistrer pour ajouter un autre ensemble de conditions.
    11. Dans le menu déroulant Type de condition, sélectionnez Ressource Type.
    12. Dans le menu déroulant Opérateur, sélectionnez c'est.
    13. Dans le menu déroulant Type de ressource, sélectionnez compute.googleapis.com/Instance.
    14. Cliquez sur le premier bouton Ajouter juste en dessous de la condition que vous venez d'ajouter pour ajouter une autre clause à l'expression.
    15. Dans le menu déroulant Type de condition, sélectionnez Ressource Nom.
    16. À partir du menu déroulant Opérateur, sélectionnez Commence par.
    17. Dans le champ Valeur, saisissez le nom de la ressource au format approprié, tel que projects/project-123/zones/us-central1-a/instances/devAccess pour une instance dont le nom commence par devAccess.
    18. À gauche de chaque type de condition, cliquez sur Et pour vous assurer que les deux clauses doivent être vraies.
    19. Cliquez sur le bouton Ajouter situé juste au-dessus du bouton Enregistrer pour ajouter le troisième ensemble de conditions regroupées.
    20. Pour vous assurer que cette condition n'a pas d'incidence sur les autres ressources, ajoutez également les clauses suivantes : dans le menu déroulant Type de condition, sélectionnez Ressource Type.
    21. Dans le menu déroulant Opérateur, sélectionnez n'est pas.
    22. Dans le menu déroulant Type de ressource, sélectionnez compute.googleapis.com/Disk.
    23. Cliquez sur le premier bouton Ajouter juste en dessous de la condition que vous venez d'ajouter pour ajouter une clause à l'expression.
    24. Dans le menu déroulant Type de condition, sélectionnez Ressource Type.
    25. Dans le menu déroulant Opérateur, sélectionnez n'est pas.
    26. Dans le menu déroulant Type de ressource, sélectionnez compute.googleapis.com/Instance.
    27. À gauche de chaque type de condition, cliquez sur Et pour vous assurer que les deux clauses doivent être vraies.
    28. Lorsque vous avez terminé, l'outil de création de conditions doit se présenter comme suit :

    29. Cliquez sur Enregistrer pour appliquer la condition.

    30. Une fois le panneau Modifier la condition fermé, cliquez à nouveau sur Enregistrer dans le panneau Modifier les autorisations pour mettre à jour vos règles Cloud IAM.

    Éditeur de conditions :

    1. Cliquez sur l'onglet Éditeur de conditions, puis saisissez l'expression suivante :

      (resource.type == "compute.googleapis.com/Disk" &&
          resource.name.startsWith("projects/project-123/regions/us-central1/disks/devAccess")) ||
          (resource.type == "compute.googleapis.com/Instance" &&
          resource.name.startsWith("projects/project-123/zones/us-central1-a/instances/devAccess")) ||
          (resource.type != "compute.googleapis.com/Disk" &&
          resource.type != "compute.googleapis.com/Instance")
    2. Après avoir saisi votre expression, vous pouvez choisir de lint la syntaxe CEL en cliquant sur Exécuter l'outil lint au-dessus de la zone de texte en haut à droite.

    3. Cliquez sur Enregistrer pour appliquer la condition.

    4. Une fois le panneau Modifier la condition fermé, cliquez à nouveau sur Enregistrer dans le panneau Modifier les autorisations pour mettre à jour vos règles Cloud IAM.

Commande gcloud

Les règles Cloud IAM sont définies à l'aide du modèle lecture-modification-écriture.

Exécutez la commande gcloud projects get-iam-policy pour obtenir la règle Cloud IAM actuelle du projet. Dans l'exemple suivant, la version JSON de la règle est téléchargée dans un chemin sur le disque.

Commande :

    gcloud projects get-iam-policy [PROJECT-ID] --format json > [FILE-PATH]
    

Le format JSON de la règle Cloud IAM est téléchargé :

{
      "bindings": [
        {
          "members": [
            "group:devs@example.com"
          ],
          "role": "roles/compute.instanceAdmin"
        }
      ],
      "etag": "BwWKmjvelug=",
      "version": 1
    }
    

Pour configurer la règle avec une condition du préfixe de nom de ressource, ajoutez l'expression de condition en surbrillance suivante. Si vous n'utilisez pas la version 263.0.0 ou une version plus récente de l'outil gcloud, vérifiez que vous avez modifié la valeur version en 3. Si vous utilisez une version plus récente de l'outil gcloud, la valeur maximale du règlement est automatiquement définie pour vous :

    {
      "bindings": [
        {
          "members": [
            "group:devs@example.com"
          ],
          "role": "roles/compute.instanceAdmin",
          "condition": {
              "title": "Dev_access_only",
              "description": "Only access to devAccess* VMs",
              "expression":
                "(resource.type == 'compute.googleapis.com/Disk' &&
                resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
                (resource.type == 'compute.googleapis.com/Instance' &&
                resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
                (resource.type != 'compute.googleapis.com/Instance' &&
                resource.type != 'compute.googleapis.com/Disk')"
          }
        }
      ],
      "etag": "BwWKmjvelug=",
      "version": 3
    }
    

Ensuite, définissez la nouvelle règle conditionnelle en exécutant la commande gcloud projects set-iam-policy :

    gcloud projects set-iam-policy [PROJECT-ID] [FILE-PATH]
    

La nouvelle association de rôles conditionnels accordera les autorisations devs@example.com de la façon suivante :

  • Toutes les autorisations du disque et de l'instance ne sont accordées que si le nom de la ressource commence par devAccess

  • Toutes les autres autorisations du rôle Administrateur d'instances sont accordées pour tous les autres types de ressources

API REST

Appelez projects.getIamPolicy() pour obtenir la règle Cloud IAM actuelle du projet.

    POST https://cloudresourcemanager.googleapis.com/v1/projects/[PROJECT-ID]:getIamPolicy
    

Le corps de la réponse contiendra la stratégie Cloud IAM du projet :

{
      "bindings": [
        {
          "members": [
            "user:example@gmail.com"
          ],
          "role": "roles/compute.instanceAdmin"
        }
      ],
      "etag": "BwWKmjvelug=",
      "version": 1
    }
    

Pour configurer la règle avec un accès basé sur les ressources, ajoutez l'expression de condition en surbrillance suivante. Assurez-vous que vous avez mis à jour la valeur version vers 3 :

    {
      "bindings": [
        {
          "members": [
            "group:devs@example.com"
          ],
          "role": "roles/compute.instanceAdmin",
          "condition": {
              "title": "Dev_access_only",
              "description": "Only access to devAccess* VMs",
              "expression":
                "(resource.type == 'compute.googleapis.com/Disk' &&
                resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
                (resource.type == 'compute.googleapis.com/Instance' &&
                resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
                (resource.type != 'compute.googleapis.com/Instance' &&
                resource.type != 'compute.googleapis.com/Disk')"
          }
        }
      ],
      "etag": "BwWKmjvelug=",
      "version": 3
    }
    

Appelez projects.setIamPolicy() pour définir la nouvelle règle Cloud IAM conditionnelle pour le projet, y compris la règle mise à jour dans le corps de la requête :

    POST https://cloudresourcemanager.googleapis.com/v1/projects/[PROJECT-ID]:setIamPolicy
    

La réponse contient la stratégie mise à jour.

Extraire des valeurs à partir des noms de ressources

Les exemples précédents montrent des comparaisons booléennes entre le nom de la ressource, ou le début du nom de la ressource, et une autre valeur. Dans certains cas, vous devrez peut-être comparer une valeur avec une partie spécifique du nom de la ressource qui ne se trouve pas au début du nom.

Vous pouvez utiliser la fonction extract() et spécifier un modèle d'extraction pour extraire la partie pertinente du nom de la ressource en tant que chaîne. Si nécessaire, vous pouvez convertir la chaîne extraite vers un type différent, tel qu'un horodatage. Après avoir extrait une valeur du nom de ressource, vous pouvez comparer cette valeur à d'autres.

Les exemples suivants montrent des expressions de condition qui utilisent la fonction extract(). Pour plus d'informations sur la fonction extract(), reportez-vous à la documentation de référence sur les attributs de conditions Cloud IAM.

Exemple : Correspondance des commandes des 30 derniers jours

Supposons que vous stockiez des informations de commande dans plusieurs buckets Cloud Storage, et que les objets de chaque bucket soient organisés par date. Un nom d'objet standard peut ressembler à cet exemple :

projects/_/buckets/acme-orders-aaa/data_lake/orders/order_date=2019-11-03/aef87g87ae0876

Vous souhaitez mettre en correspondance n'importe quelle commande issue des 30 derniers jours. La condition suivante correspond à ces commandes. Elle utilise les fonctions duration() et date() pour soustraire 30 jours (2 592 000 secondes) de l'heure de la requête, puis compare cet horodatage à la date de la commande :

request.time - duration('2592000s') < date(resource.name.extract('/order_date={date_str}/'))

Pour plus d'informations sur les fonctions date() et duration(), consultez la documentation de référence sur l'attribut Date/Heure.

Exemple : Mise en correspondance des VM Compute Engine dans n'importe quel emplacement

Supposons que vous deviez faire correspondre une VM Compute Engine dans un emplacement dont le nom commence par dev-. Le nom de ressource d'une VM utilise un format semblable à projects/[PROJECT]/zones/[ZONE]/instances/[INSTANCE_NAME]. La condition suivante est définie sur true si le nom de l'instance commence par la chaîne dev- :

resource.name.extract('/instances/{name}/').startsWith('dev-')

Le texte entre accolades identifie la partie du nom de la ressource extraite à des fins de comparaison. Dans cet exemple, le modèle d'extraction extrait les caractères entre la première occurrence de la chaîne /instances/ et la prochaine occurrence de la chaîne /.

Consignes d'utilisation importantes concernant les ressources

Lorsque vous ajoutez une condition basée sur une ressource, il est important de tenir compte de la manière dont cette condition affectera les autorisations accordées.

Rôles personnalisés

Prenons l'exemple suivant, qui implique des rôles personnalisés. Un administrateur souhaite créer un rôle personnalisé qui accorde l'accès permettant de créer des instances de VM, mais uniquement dans un projet doté d'un nom de ressource commençant par le préfixe staging, à l'aide de disques dotés de ce même préfixe.

Pour atteindre cet objectif, vérifiez que le rôle accordé contient les autorisations requises pour créer une instance de VM, soit des autorisations sur le disque et sur les instances. Ensuite, assurez-vous que l'expression de condition applique également les restrictions concernant le type de ressource pour à la fois les disques et les instances. Au-delà de ces deux types, les autres autorisations du rôle ne sont pas accordées.

L'expression de condition suivante entraînera un comportement inattendu. Les autorisations de fonctionnement sur les VM Compute Engine sont bloquées :

"expression":
    "resource.type == 'compute.googleapis.com/Disk' &&
     resource.name.startsWith('projects/project-123/regions/us-central1/disks/staging')"
    

L'expression de condition suivante inclut à la fois des disques et des instances, et appliquera correctement la restriction de dénomination pour ces deux types :

"expression":
    "(resource.type == 'compute.googleapis.com/Disk' &&
      resource.name.startsWith('projects/project-123/regions/us-central1/disks/staging')) ||
     (resource.type == 'compute.googleapis.com/Instance' &&
      resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/staging'))"
    

L'expression de condition suivante inclut à la fois des disques et des instances, et appliquera correctement la restriction de dénomination pour ces deux types (sans restreindre davantage l'accès aux autres autorisations dans le même rôle) :

"expression":
    "(resource.type == 'compute.googleapis.com/Disk' &&
      resource.name.startsWith('projects/project-123/regions/us-central1/disks/staging')) ||
     (resource.type == 'compute.googleapis.com/Instance' &&
      resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/staging')) ||
     (resource.type != 'compute.googleapis.com/Disk' &&
      resource.type != 'compute.googleapis.com/Instance')"
    

Autorisations de niveau parent uniquement

Dans la hiérarchie des ressources de Google Cloud, certaines des autorisations d'un rôle qui affectent une ressource enfant sont destinées à être appliquées uniquement au niveau parent. Par exemple, pour répertorier les clés de chiffrement pour Cloud KMS, l'utilisateur doit obtenir l'autorisation cloudkms.cryptokeys.list sur le trousseau de clés contenant les clés de chiffrement, et non les clés elles-mêmes. Ces types d'autorisations sont appelés autorisations de niveau parent uniquement et ne s'appliquent qu'aux opérations list.

Pour accorder correctement l'accès aux autorisations *.*.list en cas d'utilisation de conditions, l'expression de condition doit définir les attributs resource.service et resource.type en fonction du type de ressource parente des ressources cibles à répertorier.

Prenons les exemples suivants : L'exemple suivant interdit l'accès aux autorisations compute.disks.list et compute.instances.list, car la ressource sur laquelle ces autorisations sont vérifiées possède la valeur d'attribut resource.type de cloudresourcemanager.googleapis.com/Project.

"expression":
    "(resource.type == 'compute.googleapis.com/Disk' &&
      resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
     (resource.type == 'compute.googleapis.com/Instance' &&
      resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess'))"
    

Il est fréquent que ces autorisations list soient accordées avec d'autres autorisations pour les opérations courantes sur la ressource. Dans ce cas, vous pouvez étendre le champ d'application vers le type cloudresourcemanager.googleapis.com/Project uniquement ou étendre le champ d'application vers toutes les autres autorisations n'étant pas dotées du type "instance" ou "disque".

"expression":
    "(resource.type == 'compute.googleapis.com/Disk' &&
      resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
     (resource.type == 'compute.googleapis.com/Instance' &&
      resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
     resource.type == 'cloudresourcemanager.googleapis.com/Project'"
    

ou

"expression":
    "(resource.type == 'compute.googleapis.com/Disk' &&
      resource.name.startsWith('projects/project-123/regions/us-central1/disks/devAccess')) ||
     (resource.type == 'compute.googleapis.com/Instance' &&
      resource.name.startsWith('projects/project-123/zones/us-central1-a/instances/devAccess')) ||
     (resource.type != 'compute.googleapis.com/Disk' &&
      resource.type != 'compute.googleapis.com/Instance')"