Esecuzione di query sulle appartenenze ai gruppi

Questa guida illustra 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à sono utili per i seguenti casi d'uso:

  • I proprietari delle risorse possono prendere decisioni più consapevoli sulle modifiche all'ACL delle risorse comprendendo quali gruppi e membri sono interessati dalle modifiche.
  • I proprietari di gruppi possono valutare l'impatto dell'aggiunta o della rimozione di un gruppo da un gruppo relativo al controllo ACL e risolvere più facilmente i problemi relativi all'appartenenza.
  • I revisori della sicurezza possono controllare in modo più efficace i criteri di accesso perché è visibile la struttura dei membri ampliata dell'intera organizzazione.
  • I revisori della sicurezza possono valutare il rischio per la sicurezza di un membro visualizzando tutte le loro iscrizioni dirette e indirette ai gruppi o verificando se un membro appartiene a un gruppo specifico.

L'appartenenza a un gruppo può appartenere a un individuo, a un account di servizio o a un altro gruppo.

L'account utente o di servizio che esegue la query deve disporre dell'autorizzazione per visualizzare le iscrizioni di tutti i gruppi che fanno parte della query, altrimenti la richiesta avrà esito negativo. Se la query restituisce un errore "PERMISSION_DENIED", è 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

Attiva l'API Cloud Identity.

Abilita l'API

Ricerca di tutte le iscrizioni a un gruppo

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

REST

Per visualizzare un elenco di tutte le iscrizioni in un gruppo, chiama il numero groups.memberships.searchTransitiveMemberships() con l'ID del gruppo principale.

Python

Per eseguire l'autenticazione su Cloud Identity, configura Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare 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()

Ricerca di tutte le iscrizioni al gruppo di un membro

REST

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

Python

Per eseguire l'autenticazione su Cloud Identity, configura Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

Questo codice restituisce tutti i gruppi a cui appartiene un membro (tranne quelli con mappatura delle 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()

Verifica dell'appartenenza 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 su Cloud Identity, configura Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare 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()

Recupero del grafico delle iscrizioni per un membro

REST

Per ottenere il grafico delle iscrizioni 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 adiacente.

Python

Per eseguire l'autenticazione su Cloud Identity, configura Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

Il seguente codice restituisce il grafico delle iscrizioni di un membro specificato in un gruppo Google (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()

Creazione di una rappresentazione visiva del grafico delle iscrizioni

Di seguito è riportato un esempio di risposta dal codice Python riportato sopra. In questo esempio, i gruppi 000, 111 e 222 sono collegati come segue (le frecce vanno dall'elemento padre all'elemento figlio): 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')

genera 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 adiacente rappresenta un gruppo e i suoi membri diretti (edge) e la risposta include anche i dettagli di tutti i gruppi nel grafico di appartenenza. Può essere analizzato per generare rappresentazioni alternative (ad esempio, un grafico DOT) che possono essere utilizzate per visualizzare il grafico delle iscrizioni.

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:

Esempio di grafico delle iscrizioni relativo alla conversione DOT