Esecuzione di query sulle appartenenze ai gruppi

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

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

  • I proprietari delle risorse possono prendere decisioni più consapevoli sulle modifiche alle ACL delle risorse capendo quali gruppi e membri sono interessati dalle modifiche.
  • I proprietari di gruppi possono valutare l'impatto dell'aggiunta o della rimozione di un gruppo gruppo correlato al controllo ACL e risolvere più facilmente i problemi di appartenenza.
  • I revisori della sicurezza possono controllare più efficacemente i criteri di accesso perché sia visibile la struttura estesa dell'abbonamento 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 controllando se un membro appartiene a un gruppo specifico.

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

L'account utente o di servizio che esegue la query deve avere l'autorizzazione per visualizzare l'appartenenza a tutti i gruppi che fanno parte della query, altrimenti la richiesta non andrà a buon fine. Se la query restituisce un valore "PERMISSION_DENIED" è probabile che tu non abbia le autorizzazioni corrette per uno dei gruppi nidificati, soprattutto se uno di loro è un gruppo di proprietà di un altro dell'organizzazione.

Prima di iniziare

Enable the Cloud Identity API.

Enable the API

Ricerca di tutte le iscrizioni a un gruppo

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

REST

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

Python

Per autenticarti a Cloud Identity, configura le 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 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 autenticarti a Cloud Identity, configura le credenziali predefinite dell'applicazione. Per ulteriori informazioni, vedi Configura l'autenticazione per un ambiente di sviluppo locale.

Questo codice restituisce tutti i gruppi a cui appartiene un membro (tranne i gruppi mappati alle 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 di appartenenza per un abbonato

REST

Per ottenere il grafo 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 corrispondenza.

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 di appartenenza 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 dell'appartenenza

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 da gruppo principale a gruppo secondario): 000 -> 111 -> 222. Una chiamata al codice campione per recuperare grafico completo per il gruppo 222:

get_membership_graph(service, 'groups/-', '[email protected]')

genera la seguente risposta:

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

Ogni elemento dell'elenco di adiacenze rappresenta un gruppo e i relativi membri diretti (lati) e la risposta include anche i dettagli di tutti i gruppi nel grafo di 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='[email protected] (MEMBER)'];
#   'group0' -> 'group2' [label='[email protected] (MEMBER)'];
#   'group1' -> 'group3' [label='[email protected] (MEMBER)'];
#   'group3' -> 'group4' [label='[email protected] (MEMBER)'];
#   'group2' -> 'group3' [label='[email protected] (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 adesione di esempio dalla conversione DOT