Configurar o acesso com base em recursos

Neste tópico, descrevemos como gerenciar o acesso a recursos específicos usando vinculações de papéis condicionais nas suas políticas de permissão. Ao usar atributos de recurso em uma expressão de condição, é possível conceder um subescopo da vinculação de papel com base no nome, tipo e/ou serviço do recurso do Google Cloud.

Antes de começar

  • Leia a Visão geral das condições do Identity and Access Management (IAM) para entender os princípios básicos das vinculações de papéis condicionais do IAM.
  • Consulte os atributos de recurso que podem ser usados em uma expressão de condição.
  • O atributo de nome do recurso pode controlar o acesso aos seguintes serviços do Google Cloud:
    • Apigee
    • Application Integration
    • BigQuery
    • Autorização binária
    • Bigtable
    • Cloud Key Management Service
    • Cloud Logging
    • Spanner
    • Cloud SQL
    • Cloud Storage
    • Compute Engine
    • Dataform
    • Google Kubernetes Engine
    • Conectores de integração
    • Pub/Sub Lite
    • Secret Manager

Funções exigidas

Para conseguir as permissões necessárias para gerenciar vinculações de papéis condicionais, peça ao administrador para conceder a você os seguintes papéis do IAM:

  • Para gerenciar o acesso aos projetos: Administrador do IAM do projeto (roles/resourcemanager.projectIamAdmin) no projeto.
  • Para gerenciar o acesso às pastas: Administrador de pastas (roles/resourcemanager.folderAdmin) na pasta
  • Para gerenciar o acesso a projetos, pastas e organizações: Administrador de organização (roles/resourcemanager.organizationAdmin) na organização
  • Para gerenciar o acesso a quase todos os recursos do Google Cloud: Administrador de segurança (roles/iam.securityAdmin) no projeto, na pasta ou na organização com os recursos que você quer gerenciar.

Para mais informações sobre como conceder papéis, consulte Gerenciar acesso.

Esses papéis predefinidos contêm as permissões necessárias para gerenciar vinculações de papéis condicionais. Para ver as permissões exatas necessárias, expanda a seção Permissões necessárias:

Permissões necessárias

As permissões a seguir são necessárias para gerenciar vinculações de papéis condicionais:

  • Para gerenciar o acesso aos projetos:
    • resourcemanager.projects.getIamPolicy no projeto
    • resourcemanager.projects.setIamPolicy no projeto
  • Para gerenciar o acesso às pastas:
    • resourcemanager.folders.getIamPolicy na pasta
    • resourcemanager.folders.setIamPolicy na pasta
  • Para gerenciar o acesso a organizações:
    • resourcemanager.organizations.getIamPolicy na organização
    • resourcemanager.organizations.setIamPolicy na organização

Essas permissões também podem ser concedidas com papéis personalizados ou outros papéis predefinidos.

Conceder acesso a um grupo de recursos com base em prefixos de nomes de recursos

Uma vinculação de função condicional pode ser usada para conceder acesso a participantes de recursos com nomes que correspondam a um prefixo, como instâncias de máquina virtual (VM) do Compute Engine com nomes que começam com uma determinada string. O prefixo do nome do recurso é normalmente usado para agrupar recursos destinados a determinadas funcionalidades ou que têm propriedades específicas.

Considere o seguinte exemplo: a empresa de software ExampleCo executa cargas de trabalho em determinadas instâncias de VM que podem operar em dados confidenciais de assistência médica. Outras cargas de trabalho não confidenciais precisam ser executadas no mesmo projeto, e a ExampleCo quer garantir que os desenvolvedores dela tenham acesso limitado a instâncias de VM que operam em dados confidenciais. Para atingir essa meta, as instâncias de VM com dados confidenciais são nomeadas com um prefixo sensitiveAccess e outras instâncias de VM são nomeadas com um prefixo devAccess. Em seguida, as vinculações de papel condicionais são usadas para garantir que os desenvolvedores possam continuar produtivos com instâncias de VM devAccess normais, mas sem conceder a eles acesso a instâncias de VM sensitiveAccess.

É possível usar só o atributo de condição resource.name para gerenciar o acesso, mas é comum usar os atributos resource.type e resource.service. Ao usar esses outros atributos, é menos provável que uma condição afete o acesso a diferentes tipos de recursos com nomes semelhantes. O exemplo nesta seção controla o acesso usando os atributos resource.name e resource.type.

Para conceder acesso com base em um prefixo de nome para discos e instâncias do Compute Engine em um projeto:

Console

  1. No console do Google Cloud, abra a página IAM.

    Acessar a página do IAM

  2. Na lista de participantes, localize o participante desejado e clique no botão .

  3. No painel Editar permissões, localize o papel desejado para configurar uma condição. Em seguida, em Condição do IAM (opcional), clique em Adicionar condição do IAM.

  4. No painel Editar condição, insira um título e uma descrição opcional para a condição.

  5. É possível adicionar uma expressão de condição usando o Criador de condições ou o Editor da condição. O criador de condições fornece uma interface interativa para selecionar o tipo de condição desejado, o operador e outros detalhes aplicáveis sobre a expressão. O editor da condição fornece uma interface baseada em texto para inserir manualmente uma expressão usando a sintaxe CEL.

    Criador de condições:

    1. Clique na lista suspensa Adicionar e em Condições agrupadas.
    2. Na lista suspensa Tipo de condição, selecione Recurso > Tipo.
    3. Na lista suspensa Operador, selecione é.
    4. Na lista suspensa Tipo de recurso, selecione compute.googleapis.com/Disk.
    5. Clique no primeiro botão Adicionar logo abaixo da condição que você acabou de inserir para adicionar outra cláusula à expressão.
    6. Na lista suspensa Tipo de condição, selecione Recurso > Nome.
    7. Na lista suspensa Operador, selecione Começa com.
    8. No campo Valor, insira o nome do recurso no formato apropriado, como projects/project-123/zones/us-central1-a/disks/devAccess, para um disco com nome que começa com devAccess.
    9. À esquerda de cada tipo de condição, clique em E para garantir que as duas cláusulas sejam verdadeiras.
    10. Clique no botão Adicionar logo acima do botão Salvar para adicionar outro conjunto agrupado de condições.
    11. Na lista suspensa Tipo de condição, selecione Recurso > Tipo.
    12. Na lista suspensa Operador, selecione é.
    13. Na lista suspensa Tipo de recurso, selecione compute.googleapis.com/Instance.
    14. Clique no primeiro botão Adicionar logo abaixo da condição que você acabou de inserir e adicione outra cláusula à expressão.
    15. Na lista suspensa Tipo de condição, selecione Recurso > Nome.
    16. Na lista suspensa Operador, selecione Começa com.
    17. No campo Valor, insira o nome do recurso no formato apropriado, como projects/project-123/zones/us-central1-a/instances/devAccess, para uma instância com nome que começa com devAccess.
    18. À esquerda de cada tipo de condição, clique em E para garantir que as duas cláusulas sejam verdadeiras.
    19. Clique no botão Adicionar logo acima do botão Salvar para adicionar o terceiro conjunto agrupado de condições.
    20. Para garantir que essa condição não afete outros recursos, adicione também as seguintes cláusulas: na lista suspensa Tipo de condição, selecione Recurso > Tipo.
    21. Na lista suspensa Operador, selecione não é.
    22. Na lista suspensa Tipo de recurso, selecione compute.googleapis.com/Disk.
    23. Clique no primeiro botão Adicionar logo abaixo da condição que você acabou de inserir e adicione outra cláusula à expressão.
    24. Na lista suspensa Tipo de condição, selecione Recurso > Tipo.
    25. Na lista suspensa Operador, selecione não é.
    26. Na lista suspensa Tipo de recurso, selecione compute.googleapis.com/Instance.
    27. À esquerda de cada tipo de condição, clique em E para garantir que as duas cláusulas sejam verdadeiras.
    28. Ao terminar, o criador de condições será semelhante ao seguinte:

    29. Clique em Salvar para aplicar a condição.

    30. Quando o painel Editar condição for fechado, clique em Salvar novamente no painel Editar permissões para atualizar a política do IAM.

    Editor da condição:

    1. Clique na guia Editor da condição e digite a seguinte expressão:

      (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. Depois de inserir a expressão, é possível inspecionar a sintaxe CEL clicando em Executar linter acima da caixa de texto na parte superior direita.

    3. Clique em Salvar para aplicar a condição.

    4. Quando o painel Editar condição for fechado, clique em Salvar novamente no painel Editar permissões para atualizar a política do IAM.

gcloud

As políticas de permissão são definidas usando o padrão read-modify-write.

Execute o comando gcloud projects get-iam-policy para descobrir a política atual de permissão para o projeto. No exemplo a seguir, a versão JSON da política de permissão é transferida por download para um caminho no disco.

Comando:

gcloud projects get-iam-policy project-id --format=json > filepath

É feito o download da política de permissão no formato JSON:

{
  "bindings": [
    {
      "members": [
        "user:project-owner@example.com"
      ],
      "role": "roles/owner"
    },
    {
      "members": [
        "group:devs@example.com"
      ],
      "role": "roles/compute.instanceAdmin"
    }
  ],
  "etag": "BwWKmjvelug=",
  "version": 1
}

Para configurar a política com uma condição de prefixo de nome de recurso, adicione a seguinte expressão de condição destacada. A CLI gcloud atualiza a versão automaticamente:

{
  "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
}

Em seguida, execute o comando gcloud projects set-iam-policy para definir a nova política:

gcloud projects set-iam-policy project-id filepath

A nova vinculação de papel condicional concederá permissões devs@example.com da seguinte maneira:

  • Todas as permissões de disco e instância serão concedidas somente se o nome do recurso começar com devAccess.

  • Todas as outras permissões no papel Administrador de instâncias são concedidas para todos os outros tipos de recursos.

REST

Use o padrão read-mod-write para permitir o acesso a recursos específicos.

Primeiro, leia a política de permissão para o projeto:

O método projects.getIamPolicy da API Resource Manager recebe a política do IAM de um projeto.

Antes de usar os dados da solicitação abaixo, faça as substituições a seguir:

  • PROJECT_ID: o ID do projeto do Google Cloud. Os IDs do projeto são strings alfanuméricas, como my-project.
  • POLICY_VERSION: a versão da política a ser retornada. As solicitações precisam especificar a versão mais recente da política, que é a versão 3 da política. Para saber mais detalhes, consulte Como especificar uma versão da política ao receber uma política.

Método HTTP e URL:

POST https://cloudresourcemanager.googleapis.com/v1/projects/PROJECT_ID:getIamPolicy

Corpo JSON da solicitação:

{
  "options": {
    "requestedPolicyVersion": POLICY_VERSION
  }
}

Para enviar a solicitação, expanda uma destas opções:

Você receberá uma resposta JSON semelhante a esta:

{
  "version": 1,
  "etag": "BwWKmjvelug=",
  "bindings": [
    {
      "role": "roles/owner",
      "members": [
        "user:project-owner@example.com"
      ]
    },
    {
      "members": [
        "group:devs@example.com"
      ],
      "role": "roles/compute.instanceAdmin"
    }
  ]
}

Em seguida, modifique a política para permitir o acesso a recursos específicos. Altere o campo version para o valor 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')"
      }
    }
  ]
}

Por fim, escreva a política de permissão atualizada:

O método projects.setIamPolicy da API Resource Manager define a política na solicitação como a nova política do IAM do projeto.

Antes de usar os dados da solicitação abaixo, faça as substituições a seguir:

  • PROJECT_ID: o ID do projeto do Google Cloud. Os IDs do projeto são strings alfanuméricas, como my-project.

Método HTTP e URL:

POST https://cloudresourcemanager.googleapis.com/v1/projects/PROJECT_ID:setIamPolicy

Corpo JSON da solicitação:

{
  "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')"
        }
      }
    ]
  }
}

Para enviar a solicitação, expanda uma destas opções:

A resposta contém a política de permissão atualizada.


Extrair valores de nomes de recursos

Os exemplos anteriores mostram comparações booleanas entre o nome do recurso ou o início do nome do recurso e outro valor. Em alguns casos, talvez seja necessário comparar um valor com uma parte específica do nome do recurso que não esteja no início do nome.

É possível usar a função extract() e especificar um modelo de extração para extrair a parte relevante do nome do recurso como uma string. Se necessário, é possível converter a string extraída em outro tipo, como um carimbo de data/hora. Depois de extrair um valor do nome do recurso, é possível comparar esse valor com outros valores.

Os exemplos a seguir mostram expressões de condição que usam a função extract(). Para detalhes sobre a função extract(), consulte a referência do atributo Condições do IAM.

Exemplo: fazer a correspondência de pedidos dos últimos 30 dias

Suponha que você armazene informações de pedidos em vários buckets do Cloud Storage e que os objetos em cada bucket estejam organizados por data. Um nome de objeto típico pode ser semelhante a este exemplo:

projects/_/buckets/acme-orders-aaa/objects/data_lake/orders/order_date=2019-11-03/aef87g87ae0876

Você quer permitir que um diretor acesse qualquer pedido dos últimos 30 dias. A condição a seguir corresponde aos objetos do Cloud Storage desses pedidos. Ela usa as funções duration() e date() para subtrair 30 dias (2.592.000 segundos) do tempo de solicitação e comparar esse carimbo de data/hora com a data do pedido:

resource.type == 'storage.googleapis.com/Object' &&
  request.time - duration('2592000s') < date(resource.name.extract('/order_date={date_str}/'))

Para detalhes sobre as funções date() e duration(), consulte a referência do atributo de data/hora.

Exemplo: fazer a correspondência de VMs do Compute Engine em qualquer local

Suponha que você queira conceder um papel no nível do projeto a um diretor para qualquer VM do Compute Engine com um nome que comece com dev-, independentemente do local da VM. Você também quer que o diretor possa usar esse papel para todos os outros tipos de recursos.

O nome do recurso para uma VM usa um formato semelhante a projects/project-id/zones/zone-id/instances/instance-name. A condição a seguir é avaliada como true para VMs com um nome de instância que começa com a string dev- e para todos os tipos de recursos, exceto VMs:

resource.type != 'compute.googleapis.com/Instance' ||
  resource.name.extract('/instances/{name}').startsWith('dev-')

O texto entre chaves identifica a parte do nome do recurso que é extraída para comparação. Neste exemplo, o modelo de extração retira todos os caracteres após a primeira ocorrência da string /instances/.

Considerações importantes sobre o uso de condições baseadas em recursos

Ao adicionar uma condição baseada em recurso, é importante considerar como a condição afetará as permissões do participante.

Papéis personalizados

Considere o exemplo a seguir, que envolve papéis personalizados. Um administrador quer criar um papel personalizado que concede acesso para criar instâncias de VM, mas só permite que o usuário crie instâncias de VM em um projeto com um nome de recurso que comece com o prefixo staging, usando os discos com o mesmo prefixo de nome.

Para atingir essa meta, verifique se o papel concedido contém as permissões necessárias para criar uma instância de VM, o que significa permissões em tipos de recurso de instância e disco. Em seguida, confirme se a expressão de condição verifica o nome do recurso para ambos: discos e instâncias. Além desses dois tipos, outras permissões no papel não são concedidas.

A seguinte expressão de condição resultará em um comportamento inesperado. As permissões para operar em VMs do Compute Engine estão bloqueadas:

resource.type == 'compute.googleapis.com/Disk' &&
 resource.name.startsWith('projects/project-123/regions/us-central1/disks/staging')

A expressão de condição a seguir inclui discos e instâncias e controlará o acesso com base no nome do recurso para esses dois tipos:

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

A expressão de condição a seguir inclui discos e instâncias e controlará o acesso com base no nome do recurso para esses dois tipos. Para qualquer outro tipo de recurso, a expressão de condição concederá o papel independentemente do nome do recurso:

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

Permissões somente para pai

Na hierarquia de recursos do Google Cloud, algumas das permissões em um papel que afetam um recurso filho precisam ser aplicadas somente no nível pai. Por exemplo, para listar as chaves de criptografia do Cloud KMS, o usuário precisa receber a permissão cloudkms.cryptokeys.list no keyring que contém as chaves criptográficas, não as chaves propriamente ditas. Esses tipos de permissões são chamados de permissões somente para pai e se aplicam apenas a operações list.

Para conceder acesso adequadamente às permissões *.*.list ao usar condições, a expressão de condição deve definir os atributos resource.service e resource.type de acordo com o tipo de recurso pai dos recursos de destino a serem listados.

Veja estes exemplos. Usando o exemplo do Compute Engine acima, a expressão a seguir impede o acesso às permissões compute.disks.list e compute.instances.list porque o recurso em que as permissões são verificadas tem o valor de atributo 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'))

É comum que essas permissões list sejam concedidas com outras permissões para operações regulares no recurso. Para aumentar o escopo da permissão nesse caso, estenda o escopo somente para o tipo cloudresourcemanager.googleapis.com/Project ou o escopo para todas as outras permissões que não sejam do tipo instância ou disco.

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