Esecuzione di query sulle appartenenze ai gruppi

Questa guida mostra come eseguire query transitive sulle iscrizioni ai gruppi e recuperare il grafico delle iscrizioni di un membro.

Oltre a elencare i membri diretti di un gruppo, puoi cercare in modo transitivo le iscrizioni dirette e indirette e visualizzare il grafico delle iscrizioni di un membro specifico. Queste funzionalità riguardano i seguenti casi d'uso:

  • I proprietari delle risorse possono prendere decisioni più informate in merito alle modifiche agli elenchi di controllo degli accessi delle risorse comprendendo quali gruppi e membri sono interessati dalle modifiche.
  • I proprietari del gruppo possono valutare l'impatto dell'aggiunta o della rimozione di un gruppo da un gruppo correlato al controllo ACL e risolvere più facilmente i problemi di appartenenza.
  • I revisori della sicurezza possono controllare in modo più efficace la policy di accesso perché è visibile la struttura di appartenenza estesa dell'intera organizzazione.
  • Gli auditor della sicurezza possono valutare il rischio per la sicurezza di un membro visualizzando tutte le sue iscrizioni dirette e indirette ai gruppi o verificando se un membro appartiene a un gruppo specifico.

Un'appartenenza a un gruppo può appartenere a un singolo, a un account di servizio o a un altro gruppo.

L'utente o il account di servizio che esegue la query deve disporre dell'autorizzazione per visualizzare le appartenenze di tutti i gruppi che fanno parte della query, altrimenti la richiesta non andrà a buon fine. Se la query restituisce un errore "PERMISSION_DENIED" (AUTORIZZAZIONE NEGATA), è probabile che tu non disponga delle autorizzazioni corrette per uno dei gruppi nidificati, soprattutto se uno di questi è un gruppo di proprietà di un'altra organizzazione.

Prima di iniziare

Enable the Cloud Identity API.

Roles required to enable APIs

To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

Enable the API

Cercare tutte le iscrizioni a un gruppo

Questo codice restituisce tutte le iscrizioni di un gruppo. La risposta include il tipo di iscrizione (diretta, indiretta o entrambe) per ogni iscrizione.

REST

Per ottenere un elenco di tutte le iscrizioni a un gruppo, chiama groups.memberships.searchTransitiveMemberships() con l'ID del gruppo principale.

Python

Per eseguire l'autenticazione in Cloud Identity, configura le Credenziali predefinite dell'applicazione. Per ulteriori informazioni, consulta Configura l'autenticazione per un ambiente di sviluppo locale.

import googleapiclient.discovery
from urllib.parse import urlencode

def search_transitive_memberships(service, parent, page_size):
  try:
    memberships = []
    next_page_token = ''
    while True:
      query_params = urlencode(
        {
          "page_size": page_size,
          "page_token": next_page_token
        }
      )
      request = service.groups().memberships().searchTransitiveMemberships(parent=parent)
      request.uri += "&" + query_params
      response = request.execute()

      if 'memberships' in response:
        memberships += response['memberships']

      if 'nextPageToken' in response:
        next_page_token = response['nextPageToken']
      else:
        next_page_token = ''

      if len(next_page_token) == 0:
        break;

    print(memberships)
  except Exception as e:
    print(e)

def main():

  service = googleapiclient.discovery.build('cloudidentity', 'v1')

  # Return results with a page size of 50
  search_transitive_memberships(service, 'groups/GROUP_ID', 50)

if __name__ == '__main__':
    main()

Cercare tutte le appartenenze ai gruppi di un membro

REST

Per trovare tutti i gruppi a cui appartiene un membro, chiama groups.memberships.searchTransitiveGroups() con la chiave del membro (ad esempio, l'indirizzo email del membro).

Python

Per eseguire l'autenticazione in Cloud Identity, configura le Credenziali predefinite dell'applicazione. Per ulteriori informazioni, consulta Configura l'autenticazione per un ambiente di sviluppo locale.

Questo codice restituisce tutti i gruppi a cui appartiene un membro (ad eccezione dei gruppi con mapping dell'identità), sia direttamente che indirettamente.

import googleapiclient.discovery
from urllib.parse import urlencode

def search_transitive_groups(service, member, page_size):
  try:
    groups = []
    next_page_token = ''
    while True:
      query_params = urlencode(
        {
          "query": "member_key_id == '{}' && 'cloudidentity.googleapis.com/groups.discussion_forum' in labels".format(member),
          "page_size": page_size,
          "page_token": next_page_token
        }
      )
      request = service.groups().memberships().searchTransitiveGroups(parent='groups/-')
      request.uri += "&" + query_params
      response = request.execute()

      if 'memberships' in response:
        groups += response['memberships']

      if 'nextPageToken' in response:
        next_page_token = response['nextPageToken']
      else:
        next_page_token = ''

      if len(next_page_token) == 0:
        break;

    print(groups)
  except Exception as e:
    print(e)

def main():

  service = googleapiclient.discovery.build('cloudidentity', 'v1')

  # Return results with a page size of 50
  search_transitive_groups(service, 'MEMBER_EMAIL_ADDRESS', 50)

if __name__ == '__main__':
    main()

Controllare l'iscrizione a un gruppo

REST

Per verificare se un membro appartiene a un gruppo specifico (direttamente o indirettamente), chiama checkTransitiveMembership() con l'ID del gruppo principale e la chiave del membro (ad esempio, l'indirizzo email del membro).

Python

Per eseguire l'autenticazione in Cloud Identity, configura le Credenziali predefinite dell'applicazione. Per ulteriori informazioni, consulta Configura l'autenticazione per un ambiente di sviluppo locale.

Il seguente codice determina se il membro appartiene a un gruppo specifico:

import googleapiclient.discovery
from urllib.parse import urlencode

def check_transitive_membership(service, parent, member):
  try:
    query_params = urlencode(
      {
        "query": "member_key_id == '{}'".format(member)
      }
    )
    request = service.groups().memberships().checkTransitiveMembership(parent=parent)
    request.uri += "&" + query_params
    response = request.execute()
    print(response['hasMembership'])
  except Exception as e:
    print(e)

def main():

  service = googleapiclient.discovery.build('cloudidentity', 'v1')

  check_transitive_membership(service, 'groups/GROUP_ID', 'MEMBER_EMAIL_ADDRESS')

if __name__ == '__main__':
    main()

Recuperare il grafico delle iscrizioni per un membro

REST

Per ottenere il grafico dell'appartenenza di un membro (tutti i gruppi a cui appartiene un membro, insieme alle informazioni sul percorso), chiama groups.memberships.getMembershipGraph() con l'ID del gruppo principale e la chiave del membro (ad esempio, l'indirizzo email del membro). Il grafico viene restituito come elenco di adiacenza.

Python

Per eseguire l'autenticazione in Cloud Identity, configura le Credenziali predefinite dell'applicazione. Per ulteriori informazioni, consulta Configura l'autenticazione per un ambiente di sviluppo locale.

Il seguente codice restituisce il grafico dell'appartenenza di un membro specificato in un Google Gruppo (questa query viene filtrata in base al tipo di gruppo utilizzando l'etichetta):

import googleapiclient.discovery
from urllib.parse import urlencode

def get_membership_graph(service, parent, member):
  try:
    query_params = urlencode(
      {
        "query": "member_key_id == '{}' && 'cloudidentity.googleapis.com/groups.discussion_forum' in labels".format(member)
      }
    )
    request = service.groups().memberships().getMembershipGraph(parent=parent)
    request.uri += "&" + query_params
    response = request.execute()
    print(response['response'])
  except Exception as e:
    print(e)

def main()

  service = googleapiclient.discovery.build('cloudidentity', 'v1')

  # Specify parent group as 'groups/-' to get ALL the groups of a member
  # along with path information
  get_membership_graph(service, 'groups/GROUP_ID', 'MEMBER_KEY')

if __name__ == '__main__':
    main()

Creare una rappresentazione visiva del grafico delle iscrizioni

Di seguito è riportato un esempio di risposta del codice Python riportato sopra. In questo esempio, i gruppi 000, 111 e 222 sono collegati come segue (le frecce vanno dal gruppo principale al gruppo secondario): 000 -> 111 -> 222. Una chiamata al codice campione per recuperare il grafico completo per il gruppo 222:

get_membership_graph(service, 'groups/-', 'group-2@example.com')

restituisce la seguente risposta:

{
  "@type": "type.googleapis.com/google.apps.cloudidentity.groups.v1.GetMembershipGraphResponse",
  "adjacencyList": [
    {
      "edges": [
        {
          "name": "groups/000/memberships/111",
          "preferredMemberKey": {
            "id": "group-1@example.com"
          },
          "roles": [
            {
              "name": "MEMBER"
            }
          ]
        }
      ],
      "group": "groups/000"
    },
    {
      "edges": [
        {
          "name": "groups/111/memberships/222",
          "preferredMemberKey": {
            "id": "group-2@example.com"
          },
          "roles": [
            {
              "name": "MEMBER"
            }
          ]
        }
      ],
      "group": "groups/111"
    }
  ],
  "groups": [
    {
      "name": "groups/000",
      "groupKey": {
        "id": "group-0@example.com"
      },
      "displayName": "Group - 0",
      "description": "Group - 0",
      "labels": {
        "cloudidentity.googleapis.com/groups.discussion_forum": ""
      }
    },
    {
      "name": "groups/111",
      "groupKey": {
        "id": "group-1@example.com"
      },
      "displayName": "Group - 1",
      "description": "Group - 1",
      "labels": {
        "cloudidentity.googleapis.com/groups.discussion_forum": ""
      }
    },
    {
      "name": "groups/222",
      "groupKey": {
        "id": "group-2@example.com"
      },
      "displayName": "Group - 2",
      "description": "Group - 2",
      "labels": {
        "cloudidentity.googleapis.com/groups.discussion_forum": ""
      }
    }
  ]
}

Ogni elemento nell'elenco di adiacenza rappresenta un gruppo e i suoi membri diretti (archi) e la risposta include anche i dettagli di tutti i gruppi nel grafico dell'appartenenza. Può essere analizzato per generare rappresentazioni alternative (ad esempio, un grafico DOT) che possono essere utilizzate per visualizzare il grafico dell'appartenenza.

Questo script di esempio può essere utilizzato per convertire la risposta in un grafico DOT:

#
# Generates output in a dot format. Invoke this method using
# response['response'] from get_membership_graph()
#
# Save the output to a .dot file (say graph.dot)
# Use the dot tool to generate a visualization of the graph
# Example:
# dot -Tpng -o graph.png graph.dot
#
# Generates output like below:
#
# digraph {
#   'group0' [label='groups/000 (GROUP 0)'];
#   'group1' [label='groups/111 (GROUP 1)'];
#   'group2' [label='groups/222 (GROUP 2)'];
#   'group3' [label='groups/333 (GROUP 3)'];
#   'group4' [label='groups/444 (GROUP 4)'];
#
#   'group0' -> 'group1' [label='group-1@example.com (MEMBER)'];
#   'group0' -> 'group2' [label='group-2@example.com (MEMBER)'];
#   'group1' -> 'group3' [label='group-3@example.com (MEMBER)'];
#   'group3' -> 'group4' [label='group-4@example.com (MEMBER)'];
#   'group2' -> 'group3' [label='group-3@example.com (MEMBER)'];
# }
#
def convert_to_dot_format(graph):
  output = "digraph {\n"
  try:
    # Generate labels for the group nodes
    for group in graph['groups']:
      if 'displayName' in group:
        label = '{} ({})'.format(group['name'], group['displayName'])
      else:
        label = group['name']
      output += '  "{}" [label="{}"];\n'.format(group['name'].split('/')[1], label)

    output += '\n'

    # Generate edges
    for item in graph['adjacencyList']:
      group_id = item['group'].split('/')[1]
      for edge in item['edges']:
        edge_to = edge['name'].split('/')[3]
        edge_key = edge['preferredMemberKey']['id']
        # Collect the roles
        roles = []
        for role in edge['roles']:
          roles.append(role['name'])
        output += '  "{}" -> "{}" [label="{} ({})"];\n'.format(group_id,
                                                               edge_to,
                                                               edge_key,
                                                               ','.join(roles))

    output += "}\n"
    print(output)
  except Exception as e:
    print(e)

Di seguito è riportata la gerarchia visiva risultante per la risposta di esempio:

Grafico di esempio degli abbonamenti dalla conversione DOT