Configurer un accès basé sur les ressources

Cet article explique comment gérer l'accès à des ressources spécifiques à l'aide de liaisons de rôle conditionnelles dans vos stratégies Cloud Identity and Access Management (Cloud IAM). Les attributs de ressources situés dans une expression de condition vous permettent d'accorder un sous-champ d'application de la liaison de rôle sur la base du nom de ressource, du type de ressource et/ou du service Google Cloud.

Avant de commencer

  • Consultez la page Présentation des conditions Cloud IAM pour comprendre les principes de base des liaisons de rôles conditionnelles Cloud IAM.
  • Examinez les attributs de ressources 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 :
    • Cloud Spanner
    • Cloud Storage
    • Compute Engine
    • Cloud IAP
    • Cloud Key Management Service
    • Resource Manager (type de ressource et service de ressource uniquement)
    • Secret Manager

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

Une liaison de rôle conditionnelle permet d'accorder aux membres l'accès aux ressources dont les noms correspondent à un préfixe, par exemple 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 gérer 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 qui gèrent des données sensibles. Pour atteindre cet objectif, les instances de VM qui gèrent des données sensibles sont dotées du préfixe sensitiveAccess et les autres instances de VM du préfixe devAccess. Ensuite, les liaisons de rôle conditionnelles permettent aux développeurs de rester productifs avec des instances de VM devAccess normales, tout en limitant l'accès aux instances de VM sensitiveAccess.

S'il est possible d'utiliser l'attribut de condition resource.name seul pour gérer l'accès, il est courant d'utiliser également les attributs resource.type et resource.service. Lorsque vous utilisez ces attributs supplémentaires, vous réduisez les chances qu'une condition affecte l'accès à différents types de ressources portant des noms similaires. Dans l'exemple de cette section, les attributs resource.name et resource.type permettent de contrôler l'accès.

Pour accorder un accès basé sur un préfixe de nom à des disques et des instances Compute Engine d'un projet, procédez comme suit :

Console

  1. Dans Cloud Console, accédez à la page IAM.

    Accéder à la page "IAM"

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

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

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

  5. 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 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 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 ajouter une clause à l'expression.
    6. Dans la liste déroulante Type de condition, sélectionnez Ressource > Nom.
    7. Dans le 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 ensemble de conditions groupées.
    11. Dans le menu déroulant Type de condition, sélectionnez Ressource > Type.
    12. Dans le menu déroulant Opérateur, sélectionnez 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 clause à l'expression.
    15. Dans la liste déroulante Type de condition, sélectionnez Ressource > Nom.
    16. Dans le 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 groupé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é, le créateur 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 votre stratégie 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 d'effectuer une analyse lint de 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 votre stratégie Cloud IAM.

gcloud

Les stratégies 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 stratégie Cloud IAM actuelle du projet. Dans l'exemple suivant, la version JSON de la stratégie est téléchargée dans un chemin sur le disque.

Commande :

gcloud projects get-iam-policy project-id --format=json > filepath

Le format JSON de la stratégie Cloud IAM est téléchargé :

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

Pour configurer la stratégie avec une condition basée sur le préfixe du nom de ressource, ajoutez l'expression de condition mise en évidence ci-dessous. Si vous n'utilisez pas la version 263.0.0 ni une version plus récente de l'outil gcloud, vérifiez que vous avez mis à jour la valeur version vers 3. Si vous utilisez une version plus récente de l'outil gcloud, la valeur maximale du règlement est automatiquement définie :

{
  "bindings": [
    {
      "members": [
        "user:project-owner@example.com"
      ],
      "role": "roles/owner"
    },
    {
      "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 stratégie en exécutant la commande gcloud projects set-iam-policy :

gcloud projects set-iam-policy project-id filepath

La nouvelle liaison de rôle conditionnelle accordera les autorisations devs@example.com de la façon suivante :

  • Toutes les autorisations concernant les disques et les instances 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.

REST

Utilisez le modèle lecture-modification-écriture pour autoriser l'accès à des ressources spécifiques.

Tout d'abord, lisez la stratégie Cloud IAM du projet :

La méthode projects.getIamPolicy de l'API Resource Manager permet d'obtenir la stratégie IAM d'un projet.

Avant d'utiliser les données de requête ci-dessous, effectuez les remplacements suivants :

Méthode HTTP et URL :

POST https://cloudresourcemanager.googleapis.com/v1/projects/project-id:getIamPolicy

Corps JSON de la requête :

{
  "options": {
    "requestedPolicyVersion": policy-version
  }
}

Pour envoyer votre requête, développez l'une des options suivantes :

Vous devriez recevoir une réponse JSON de ce type :

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

Ensuite, modifiez la stratégie de sorte qu'elle autorise l'accès à des ressources spécifiques. Veillez à remplacer la valeur du champ version par la valeur 3 :

{
  "version": 3,
  "etag": "BwWKmjvelug=",
  "bindings": [
    {
      "role": "roles/owner",
      "members": [
        "user:project-owner@example.com"
      ]
    },
    {
      "role": "roles/compute.instanceAdmin",
      "members": [
        "group:devs@example.com"
      ],
      "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')"
      }
    }
  ]
}

Enfin, écrivez la stratégie mise à jour :

La méthode projects.setIamPolicy de l'API Resource Manager définit la stratégie de la requête en tant que nouvelle stratégie IAM du projet.

Avant d'utiliser les données de requête ci-dessous, effectuez les remplacements suivants :

  • project-id : ID de votre projet Google Cloud.

Méthode HTTP et URL :

POST https://cloudresourcemanager.googleapis.com/v1/projects/project-id:setIamPolicy

Corps JSON de la requête :

{
  "policy": {
    "version": 3,
    "etag": "BwWKmjvelug=",
    "bindings": [
      {
        "role": "roles/owner",
        "members": [
          "user:project-owner@example.com"
        ]
      },
      {
        "role": "roles/compute.instanceAdmin",
        "members": [
          "group:devs@example.com"
        ],
        "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')"
        }
      }
    ]
  }
}

Pour envoyer votre requête, développez l'une des options suivantes :

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 ressource ou le début du nom de ressource et une autre valeur. Toutefois, dans certains cas, vous devrez peut-être comparer une valeur avec une partie spécifique du nom de 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 ressource sous forme de 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 la comparer à d'autres valeurs.

Les exemples suivants montrent des expressions de condition qui utilisent la fonction extract(). Pour en savoir plus sur la fonction extract(), consultez la documentation de référence sur les attributs de conditions Cloud IAM.

Exemple : mise en correspondance des commandes des 30 derniers jours

Supposons que vous stockiez des informations sur les commandes dans plusieurs buckets Cloud Storage et que les objets de chacun de ces buckets soient organisés par date. Un nom d'objet type peut ressembler à ceci :

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 en savoir plus 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 mettre en correspondance une VM Compute Engine de n'importe quel emplacement et dont le nom commence par dev-. Le nom de ressource d'une VM se présente dans un format semblable à projects/project-id/zones/zone-id/instances/instance-name. La condition suivante renvoie 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 ressource extraite à des fins de comparaison. Dans cet exemple, le modèle d'extraction extrait les caractères situés entre la première occurrence de la chaîne /instances/ et l'occurrence suivante de la chaîne /.

Consignes d'utilisation importantes concernant les ressources

Lorsque vous ajoutez une condition basée sur les ressources, il est important de tenir compte de la façon dont la condition affecte les autorisations des membres.

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 autorise l'utilisateur à créer des instances de VM, mais uniquement dans un projet dont le nom de ressource commence par le préfixe staging, en utilisant des disques portant le même préfixe de nom.

Pour atteindre cet objectif, vérifiez que le rôle accordé contient les autorisations requises pour créer une instance de VM, c'est-à-dire des autorisations sur les types de ressources "disque" et "instance". Assurez-vous ensuite que l'expression de condition vérifie le nom de la ressource aussi bien pour les disques que pour 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îne un comportement inattendu. Les autorisations permettant de gérer des VM Compute Engine sont bloquées :

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 les disques et les instances, et gère l'accès basé sur le nom de ressource pour ces deux types :

(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 les disques et les instances, et gère l'accès basé sur le nom de ressource pour ces deux types. Pour tout autre type de ressource, l'expression de condition attribue le rôle quel que soit le nom de ressource :

(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 sur 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 des autorisations *.*.list lors de l'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. Reprenant l'exemple Compute Engine mentionné précédemment, l'expression suivante interdit l'octroi des 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.

(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 les autres autorisations associées aux opérations courantes sur la ressource. Dans ce cas, vous pouvez étendre le niveau d'accès au type cloudresourcemanager.googleapis.com/Project uniquement ou à toutes les autres autorisations n'étant pas dotées du type "instance" ou "disque".

(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

(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')