Consultar membros do grupo

Este guia demonstra como consultar transitivamente as associações a grupos e obter o gráfico de associações de um membro.

Além de listar os membros diretos de um grupo, pode pesquisar transitivamente membros diretos e indiretos, e ver o gráfico de membros de um membro específico. Estas capacidades abordam os seguintes exemplos de utilização:

  • Os proprietários de recursos podem tomar decisões mais informadas sobre as alterações às ACLs de recursos, compreendendo que grupos e membros são afetados pelas alterações.
  • Os proprietários do grupo podem avaliar o impacto da adição ou remoção de um grupo de um grupo relacionado com o controlo da LCA e resolver mais facilmente problemas de inscrição.
  • Os auditores de segurança podem auditar a política de acesso de forma mais eficaz porque a estrutura de associação expandida de toda a organização é visível.
  • Os auditores de segurança podem avaliar o risco de segurança de um membro através da visualização de todas as respetivas associações a grupos diretas e indiretas ou verificando se um membro pertence a um grupo específico.

Uma associação a um grupo pode pertencer a um indivíduo, a uma conta de serviço ou a outro grupo.

O utilizador ou a conta de serviço que está a fazer a consulta tem de ter permissão para ver as associações de todos os grupos que fazem parte da consulta. Caso contrário, o pedido falha. Se a consulta devolver um erro "PERMISSION_DENIED", é provável que não tenha as autorizações corretas para um dos grupos aninhados, especialmente se um deles for um grupo pertencente a outra organização.

Antes de começar

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

Pesquisar todas as associações num grupo

Este código devolve todas as associações de um grupo. A resposta inclui o tipo de subscrição (direta, indireta ou ambas) para cada subscrição.

REST

Para receber uma lista de todas as associações num grupo, chame groups.memberships.searchTransitiveMemberships() com o ID do grupo principal.

Python

Para se autenticar no Cloud ID, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento local.

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

Pesquisar todos os registos de membro de um membro

REST

Para encontrar todos os grupos aos quais um membro pertence, chame groups.memberships.searchTransitiveGroups() com a chave do membro (por exemplo, o endereço de email do membro).

Python

Para se autenticar no Cloud ID, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento local.

Este código devolve todos os grupos aos quais um membro pertence (exceto grupos mapeados por identidade), tanto direta como indiretamente.

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

Verificar a subscrição de um grupo

REST

Para verificar se um membro pertence a um grupo específico (direta ou indiretamente), chame checkTransitiveMembership() com o ID do grupo principal e a chave do membro (por exemplo, o endereço de email do membro).

Python

Para se autenticar no Cloud ID, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento local.

O código seguinte determina se o membro pertence a um grupo específico:

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

Obter o gráfico de associação de um membro

REST

Para obter o gráfico de associação de um membro (todos os grupos aos quais um membro pertence, juntamente com as informações do caminho), chame groups.memberships.getMembershipGraph() com o ID do grupo principal e a chave do membro (por exemplo, o endereço de email do membro). O gráfico é devolvido como uma lista de adjacências.

Python

Para se autenticar no Cloud ID, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento local.

O código seguinte devolve o gráfico de associação de um membro especificado num grupo Google (esta consulta é filtrada por tipo de grupo através da etiqueta):

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

Criar uma representação visual do gráfico de associação

Segue-se um exemplo de resposta do código Python acima. Neste exemplo, os grupos 000, 111 e 222 estão ligados da seguinte forma (as setas indicam a ligação do grupo principal ao grupo secundário): 000 -> 111 -> 222. Uma chamada ao código de exemplo para obter o gráfico completo do grupo 222:

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

resulta na seguinte resposta:

{
  "@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": ""
      }
    }
  ]
}

Cada item na lista de adjacências representa um grupo e os respetivos membros diretos (arestas), e a resposta também inclui detalhes de todos os grupos no gráfico de associação. Pode ser analisado para gerar representações alternativas (por exemplo, um gráfico DOT) que podem ser usadas para visualizar o gráfico de associação.

Este script de exemplo pode ser usado para converter a resposta num gráfico 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)

Segue-se a hierarquia visual resultante para a resposta de exemplo:

Gráfico de adesão de exemplo da conversão DOT