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 d'autorisation. 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 basé sur le nom de ressource, le type de ressource et/ou le service Google Cloud.

Avant de commencer

  • Consultez la page Présentation des conditions Identity and Access Management (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 :
    • Apigee
    • Application Integration
    • BigQuery
    • Autorisation binaire
    • Bigtable
    • Cloud Key Management Service
    • Cloud Logging
    • Spanner
    • Cloud SQL
    • Cloud Storage
    • Compute Engine
    • Dataform
    • Google Kubernetes Engine
    • Integration Connectors
    • Pub/Sub Lite
    • Secret Manager

Rôles requis

Pour obtenir les autorisations nécessaires pour gérer les liaisons de rôle conditionnelles, demandez à votre administrateur de vous accorder les rôles IAM suivants :

  • Pour gérer l'accès aux projets : Administrateur de projet IAM (roles/resourcemanager.projectIamAdmin) sur le projet
  • Pour gérer l'accès aux dossiers : Administrateur de dossier (roles/resourcemanager.folderAdmin) sur le dossier
  • Pour gérer l'accès aux projets, aux dossiers et aux organisations : Administrateur de l'organisation (roles/resourcemanager.organizationAdmin) sur l'organisation
  • Pour gérer l'accès à presque toutes les ressources Google Cloud : Administrateur de sécurité (roles/iam.securityAdmin) sur le projet, le dossier ou l'organisation dont vous souhaitez gérer l'accès

Pour en savoir plus sur l'attribution de rôles, consultez la section Gérer les accès.

Ces rôles prédéfinis contiennent les autorisations requises pour gérer les liaisons de rôles conditionnelles. Pour afficher les autorisations exactes requises, développez la section Autorisations requises :

Autorisations requises

Les autorisations suivantes sont requises pour gérer les liaisons de rôles conditionnelles :

  • Pour gérer l'accès aux projets :
    • resourcemanager.projects.getIamPolicy sur le projet
    • resourcemanager.projects.setIamPolicy sur le projet
  • Pour gérer l'accès aux dossiers :
    • resourcemanager.folders.getIamPolicy sur le dossier
    • resourcemanager.folders.setIamPolicy sur le dossier
  • Pour gérer l'accès aux organisations :
    • resourcemanager.organizations.getIamPolicy sur l'organisation
    • resourcemanager.organizations.setIamPolicy sur l'organisation

Vous pouvez également obtenir ces autorisations avec des rôles personnalisés ou d'autres rôles prédéfinis.

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 aux comptes principaux 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 la console Google Cloud, accédez à la page IAM.

    Accéder à la page "IAM"

  2. Dans la liste des comptes principaux, localisez le compte principal souhaité, puis cliquez sur le bouton .

  3. Dans le panneau Modifier les autorisations, localisez le rôle pour lequel vous souhaitez configurer une condition. Puis sous Condition IAM (facultatif), cliquez sur Ajouter une condition IAM.

  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 d'autorisation.

    É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 d'autorisation.

gcloud

Les stratégies d'autorisation 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 d'autorisation actuelle du projet. Dans l'exemple suivant, la version JSON de la stratégie d'autorisation 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 d'autorisation 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 d'autorisation avec une condition basée sur le préfixe du nom de ressource, ajoutez l'expression de condition mise en évidence ci-dessous. gcloud CLI met automatiquement à jour la version :

{
  "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 d'autorisation 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 d'autorisation du projet :

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

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

  • PROJECT_ID : ID de votre projet Google Cloud. Les ID de projet sont des chaînes alphanumériques, telles que my-project.
  • POLICY_VERSION : version de la stratégie à renvoyer. Les requêtes doivent spécifier la version de stratégie la plus récente, qui est la version 3. Pour plus d'informations, consultez la section Spécifier une version de stratégie lors de l'obtention d'une stratégie.

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 d'autorisation 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 d'autorisation mise à jour :

La méthode projects.setIamPolicy de l'API Resource Manager définit la stratégie d'autorisation de la requête en tant que nouvelle stratégie d'autorisation 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. Les ID de projet sont des chaînes alphanumériques, telles que my-project.

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 d'autorisation 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/objects/data_lake/orders/order_date=2019-11-03/aef87g87ae0876

Vous souhaitez autoriser un compte principal à accéder à n'importe quelle commande passée au cours des 30 derniers jours. La condition suivante correspond aux objets Cloud Storage de 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 :

resource.type == 'storage.googleapis.com/Object' &&
  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 souhaitiez attribuer un rôle au niveau du projet à un compte principal pour toute VM Compute Engine dont le nom commence par dev-, quel que soit son emplacement. Vous souhaitez également que le compte principal puisse utiliser ce rôle pour tous les autres types de ressources.

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 pour les VM dont le nom d'instance commence par la chaîne dev- et pour tous les types de ressources autres que les VM :

resource.type != 'compute.googleapis.com/Instance' ||
  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 après la première occurrence de la chaîne /instances/.

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 comptes principaux.

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