Configura el acceso basado en recursos

En este tema, se describe cómo administrar el acceso a recursos específicos mediante vinculaciones de roles condicionales en tus políticas de permisos. Mediante el uso de atributos de recursos en una expresión de condición, puedes otorgar un subpermiso de la vinculación de la función según el nombre del recurso, el tipo de recurso o el servicio de Google Cloud.

Antes de comenzar

  • Lee la descripción general de las Condiciones de Identity and Access Management (IAM) para comprender los conceptos básicos de las vinculaciones de roles condicionales de IAM.
  • Revisa los atributos de recursos que se pueden usar en una expresión de condición.
  • El atributo del nombre del recurso puede controlar el acceso a los siguientes servicios de Google Cloud:
    • Apigee
    • Application Integration
    • Servicio Backup and DR
    • BigQuery
    • API de BigQuery Reservation
    • Bigtable
    • Autorización binaria
    • Cloud Deploy
    • Cloud Key Management Service
    • Cloud Logging
    • Cloud SQL
    • Cloud Storage
    • Compute Engine
    • Dataform
    • Google Kubernetes Engine
    • Conectores de Integration
    • Google Cloud Managed Service para Apache Kafka
    • Pub/Sub Lite
    • Secret Manager
    • Spanner

Roles obligatorios

Para obtener los permisos que necesitas a fin de administrar las vinculaciones de roles condicionales, pídele a tu administrador que te otorgue los siguientes roles de IAM:

  • Para administrar el acceso a los proyectos: Administrador de IAM del proyecto (roles/resourcemanager.projectIamAdmin) en el proyecto
  • Para administrar el acceso a las carpetas: Administrador de carpetas (roles/resourcemanager.folderAdmin) en la carpeta
  • Para administrar el acceso a los proyectos, las carpetas y las organizaciones: Administrador de la organización (roles/resourcemanager.organizationAdmin) en la organización
  • Para administrar el acceso a casi todos los recursos de Google Cloud: Administrador de seguridad (roles/iam.securityAdmin) en el proyecto, la carpeta o la organización a cuyos recursos deseas administrar el acceso

Para obtener más información sobre cómo otorgar roles, consulta Administra el acceso a proyectos, carpetas y organizaciones.

Estos roles predefinidos contienen los permisos necesarios para administrar las vinculaciones de roles condicionales. Para ver los permisos exactos que son necesarios, expande la sección Permisos requeridos:

Permisos necesarios

Los siguientes permisos son necesarios para administrar las vinculaciones de roles condicionales:

  • Para administrar el acceso a los proyectos:
    • resourcemanager.projects.getIamPolicy en el proyecto
    • resourcemanager.projects.setIamPolicy en el proyecto
  • Para administrar el acceso a las carpetas:
    • resourcemanager.folders.getIamPolicy en la carpeta
    • resourcemanager.folders.setIamPolicy en la carpeta
  • Para administrar el acceso a las organizaciones:
    • resourcemanager.organizations.getIamPolicy en la organización
    • resourcemanager.organizations.setIamPolicy en la organización

También puedes obtener estos permisos con roles personalizados o con otros roles predefinidos.

Otorga acceso a un grupo de recursos según los prefijos del nombre de los recursos

Una vinculación de función condicional se puede usar con el fin de otorgar a las principales acceso a los recursos cuyos nombres coincidan con un prefijo, como las instancias de máquina virtual (VM) de Compute Engine cuyos nombres comiencen con una string determinada. Por lo general, el prefijo del nombre del recurso se usa para agrupar recursos que están destinados a ciertas funciones o que tienen ciertas propiedades.

Considera el siguiente ejemplo: la empresa de software ExampleCo ejecuta cargas de trabajo en determinadas instancias de VM que puede que operen con datos sensibles de atención médica. En el mismo proyecto, se deben ejecutar otras cargas de trabajo que no son confidenciales, y ExampleCo quiere asegurarse de que sus desarrolladores tengan acceso limitado a las instancias de VM que operen con datos sensibles. Para lograr este objetivo, las instancias de VM con datos sensibles se nombran con un prefijo sensitiveAccess y las otras instancias de VM se nombran con un prefijo devAccess. Luego, las vinculaciones de funciones condicionales se usan para garantizar que los desarrolladores puedan seguir siendo productivos con instancias de VM devAccess normales, sin otorgarles acceso a las instancias de VM sensitiveAccess.

Si bien puedes usar solo el atributo de condición resource.name para administrar el acceso, es común usar también los atributos resource.type y resource.service. Cuando usas estos atributos adicionales, disminuyes la probabilidad de que una condición afecte el acceso a distintos tipos de recursos con nombres similares. En el ejemplo de esta sección, se controla el acceso mediante los atributos resource.name y resource.type.

Para otorgar el acceso en función de un prefijo de nombre a instancias y discos de Compute Engine en un proyecto, haz lo siguiente:

Console

  1. En la consola de Google Cloud, ve a la página IAM.

    Ir a la página IAM

  2. En la lista de principales, busca la deseada y haz clic en el botón .

  3. Desde el panel Editar permisos, ubica la función deseada para configurar una condición. Luego, en Condición de IAM (opcional), haz clic en Agregar condición de IAM.

  4. En el panel Editar condición, ingresa un título y una descripción opcional para la condición.

  5. Puedes agregar una expresión de condición mediante el Creador de condiciones o el Editor de condiciones. El creador de condiciones proporciona una interfaz interactiva en la que puedes seleccionar el tipo de condición y el operador deseados, así como otros detalles aplicables sobre la expresión. El editor de condiciones proporciona una interfaz basada en texto en la que puedes ingresar una expresión de forma manual mediante la sintaxis CEL.

    Creador de condiciones:

    1. Haz clic en el menú desplegable Agregar y, luego, en Condiciones agrupadas.
    2. En el menú desplegable Tipo de condición (Condition type), selecciona Recurso > Tipo (Resource > Type).
    3. En el menú desplegable Operador (Operator), selecciona es (is).
    4. En el menú desplegable Resource type (Tipo de recurso), selecciona compute.googleapis.com/Disk.
    5. Haz clic en el primer botón Agregar (Add) que se encuentra justo debajo de la condición que acabas de ingresar para agregar otra cláusula a la expresión.
    6. En el menú desplegable Tipo de condición (Condition type), selecciona Recurso > Nombre (Resource > Name).
    7. En el menú desplegable Operador (Operator), selecciona Comienza con (Starts with).
    8. En el campo Value (Valor), ingresa el nombre del recurso en el formato adecuado, como projects/project-123/zones/us-central1-a/disks/devAccess para un disco cuyo nombre comienza con devAccess.
    9. A la izquierda de cada tipo de condición, haz clic en And (Y) para asegurar que ambas cláusulas deban ser verdaderas.
    10. Haz clic en el botón Agregar (Add) justo arriba del botón Guardar para agregar otro conjunto agrupado de condiciones.
    11. En el menú desplegable Tipo de condición (Condition type), selecciona Recurso > Tipo (Resource > Type).
    12. En el menú desplegable Operador (Operator), selecciona es (is).
    13. En el menú desplegable Resource type (Tipo de recurso), selecciona compute.googleapis.com/Instance.
    14. Haz clic en el primer botón Agregar (Add) que se encuentra justo debajo de la condición que acabas de ingresar para agregar otra cláusula a la expresión.
    15. En el menú desplegable Tipo de condición (Condition type), selecciona Recurso > Nombre (Resource > Name).
    16. En el menú desplegable Operador (Operator), selecciona Comienza con (Starts with).
    17. En el campo Value (Valor), ingresa el nombre del recurso en el formato adecuado, como projects/project-123/zones/us-central1-a/instances/devAccess para una instancia cuyo nombre comienza con devAccess.
    18. A la izquierda de cada tipo de condición, haz clic en And (Y) para asegurar que ambas cláusulas deban ser verdaderas.
    19. Haz clic en el botón Agregar (Add) que se encuentra justo arriba del botón Guardar para agregar el tercer conjunto agrupado de condiciones.
    20. Para asegurarte de que esta condición no afecte a otros recursos, también agrega las siguientes cláusulas: en el menú desplegable Tipo de condición (Condition type), selecciona Recurso > Tipo (Resource > Type).
    21. En el menú desplegable Operador (Operator), selecciona no es (is not).
    22. En el menú desplegable Resource type (Tipo de recurso), selecciona compute.googleapis.com/Disk.
    23. Haz clic en el primer botón Agregar (Add) que se encuentra justo debajo de la condición que acabas de ingresar para agregar otra cláusula a la expresión.
    24. En el menú desplegable Tipo de condición (Condition type), selecciona Recurso > Tipo (Resource > Type).
    25. En el menú desplegable Operador (Operator), selecciona no es (is not).
    26. En el menú desplegable Resource type (Tipo de recurso), selecciona compute.googleapis.com/Instance.
    27. A la izquierda de cada tipo de condición, haz clic en And (Y) para asegurar que ambas cláusulas deban ser verdaderas.

      Cuando hayas terminado, el generador de condiciones debería verse como el que se muestra a continuación:

    28. Haz clic en Guardar para aplicar la condición.

    29. Una vez que el panel Editar condición esté cerrado, vuelve a hacer clic en Guardar desde el panel Editar permisos para actualizar la política de permisos.

    Editor de condiciones:

    1. Haz clic en la pestaña Editor de condiciones y, luego, ingresa la siguiente expresión:

      (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. Después de ingresar la expresión, podrás optar por analizar con lint la sintaxis CEL si haces clic en Ejecutar Linter arriba del cuadro de texto en la parte superior derecha.

    3. Haz clic en Guardar para aplicar la condición.

    4. Una vez que el panel Editar condición esté cerrado, vuelve a hacer clic en Guardar desde el panel Editar permisos para actualizar la política de permisos.

gcloud

Las políticas de permisos se establecen mediante el patrón de lectura-modificación-escritura.

Ejecuta el comando gcloud projects get-iam-policy a fin de obtener la política de permisos actual para el proyecto. En el siguiente ejemplo, la versión JSON de la política de permisos se descarga en una ruta de acceso en el disco.

Comando:

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

Se descarga el formato JSON de la política de permisos:

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

Para configurar la política de permisos con una condición de prefijo del nombre del recurso, debes agregar la siguiente expresión de condición destacada. La CLI de gcloud actualiza la versión de forma automática:

{
  "bindings": [
    {
      "members": [
        "user:my-user@example.com"
      ],
      "role": "roles/owner"
    },
    {
      "members": [
        "group:my-group@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
}

A continuación, configura la política de permisos nueva mediante la ejecución del comando gcloud projects set-iam-policy:

gcloud projects set-iam-policy project-id filepath

La nueva vinculación de roles condicionales otorga los permisos del grupo de la siguiente manera:

  • Todos los permisos de discos y de instancias se otorgan solo si el nombre del recurso comienza con devAccess.

  • Todos los demás permisos de la función de administrador de instancias se otorgan a todos los demás tipos de recursos.

REST

Usa el patrón read-modify-write para permitir el acceso a recursos específicos.

Primero, lee la política de permisos para el proyecto:

El método projects.getIamPolicy de la API de Resource Manager obtiene la política de permisos de un proyecto.

Antes de usar cualquiera de los datos de solicitud a continuación, realiza los siguientes reemplazos:

  • PROJECT_ID: El ID del proyecto de Google Cloud Los ID de proyecto son strings alfanuméricas, como my-project.
  • POLICY_VERSION: Es la versión de la política que se mostrará. Las solicitudes deben especificar la versión de política más reciente, que es la versión de política 3. Consulta Especifica una versión de política cuando obtienes una política para obtener más detalles.

Método HTTP y URL:

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

Cuerpo JSON de la solicitud:

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

Para enviar tu solicitud, expande una de estas opciones:

Deberías recibir una respuesta JSON similar a la que se muestra a continuación:

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

A continuación, modifica la política para que permita el acceso a recursos específicos. Asegúrate de cambiar el campo version al valor 3:

{
  "version": 3,
  "etag": "BwWKmjvelug=",
  "bindings": [
    {
      "role": "roles/owner",
      "members": [
        "user:my-user@example.com"
      ]
    },
    {
      "role": "roles/compute.instanceAdmin",
      "members": [
        "group:my-group@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 último, escribe la política de permisos actualizada:

El método projects.setIamPolicy de la API de Resource Manager establece la política de permisos en la solicitud como la nueva política de permisos del proyecto.

Antes de usar cualquiera de los datos de solicitud a continuación, realiza los siguientes reemplazos:

  • PROJECT_ID: El ID del proyecto de Google Cloud Los ID de proyecto son strings alfanuméricas, como my-project.

Método HTTP y URL:

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

Cuerpo JSON de la solicitud:

{
  "policy": {
    "version": 3,
    "etag": "BwWKmjvelug=",
    "bindings": [
      {
        "role": "roles/owner",
        "members": [
          "user:my-user@example.com"
        ]
      },
      {
        "role": "roles/compute.instanceAdmin",
        "members": [
          "group:my-group@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 tu solicitud, expande una de estas opciones:

La respuesta contiene la política de permisos actualizada:


Extrae valores de nombres de recursos

En los ejemplos anteriores, se muestran comparaciones booleanas entre el nombre del recurso, o su comienzo, y otro valor. Sin embargo, en algunos casos, es posible que debas comparar un valor con una parte específica del nombre del recurso que no esté al principio del nombre.

Puedes usar la función extract() y especificar una plantilla de extracción para extraer la parte relevante del nombre del recurso como una string. Si es necesario, puedes convertir la string que se extrajo en otro tipo, como una marca de tiempo. Después de extraer un valor del nombre del recurso, puedes compararlo con otros valores.

En los siguientes ejemplos, se muestran expresiones de condición en las que se usa la función extract(). Para obtener detalles sobre la función extract(), consulta la referencia de atributos de las Condiciones de IAM.

Ejemplo: Haz coincidir los pedidos de los últimos 30 días

Supongamos que almacenas información de pedidos en varios bucket s de Cloud Storage y que los objetos de cada bucket están organizados por fecha. Un nombre de objeto típico puede ser similar al siguiente ejemplo:

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

Deseas permitir que una principal acceda a cualquier pedido de los últimos 30 días. La siguiente condición coincide con los objetos de Cloud Storage de estos pedidos. Usa las funciones duration() y date() para restar 30 días (2,592,000 segundos) del tiempo de la solicitud y, luego, compara esa marca de tiempo con la fecha del pedido:

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

Para obtener más detalles sobre las funciones date() y duration(), consulta la referencia del atributo de fecha y hora.

Ejemplo: Haz coincidir VM de Compute Engine en cualquier ubicación

Supongamos que deseas otorgar una función a nivel de proyecto a una principal para cualquier VM de Compute Engine cuyo nombre comience con dev-, sin importar la ubicación de la VM. También quieres que la principal pueda usar esa función para todos los demás tipos de recursos.

El nombre de recurso de una VM usa un formato similar a projects/project-id/zones/zone-id/instances/instance-name. La siguiente condición se evalúa como true para las VM con un nombre de instancia que comienza con la string dev- y para todos los tipos de recursos que no son VM:

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

El texto entre llaves identifica la parte del nombre del recurso que se extrae para la comparación. En este ejemplo, la plantilla de extracción extrae cualquier carácter después del primer caso de la string /instances/.

Consideraciones de uso importantes para las condiciones basadas en recursos

Cuando se agrega una condición basada en recursos, es importante considerar cómo afectará la condición a los permisos de las principales.

Funciones personalizadas

Considera el siguiente ejemplo, en el que se incluyen funciones personalizadas. Un administrador desea crear una función personalizada que otorgue acceso para crear instancias de VM, pero que solo permita al usuario crear instancias de VM en un proyecto que tenga un nombre de recurso que comience con el prefijo de nombre staging, mediante el uso de los discos que tienen el mismo nombre de prefijo.

Si deseas lograr este objetivo, debes asegurarte de que la función que se otorga contenga los permisos necesarios para crear una instancia de VM, lo que significa que debe contener permisos de los tipos de recursos de instancias y de discos. Luego, asegúrate de que la expresión de condición verifique el nombre del recurso de los discos y las instancias. Además de estos dos tipos, no se otorgan otros permisos en la función.

La siguiente expresión de condición tendrá como resultado un comportamiento inesperado. Se bloquean los permisos para operar en las VM de Compute Engine:

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

La siguiente expresión de condición incluye instancias y discos, y se usará para administrar el acceso en función del nombre del recurso de estos dos 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'))

La siguiente expresión de condición incluye instancias y discos, y se usará para administrar el acceso en función del nombre del recurso de estos dos tipos. En el caso de cualquier otro tipo de recurso, la expresión de condición otorga la función, sin importar el nombre del 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')

Permisos solo para superiores

En la jerarquía de recursos de Google Cloud, algunos de los permisos de una función que afectan a un recurso secundario están diseñados para aplicarse de forma forzosa solo a nivel del superior. Por ejemplo, para enumerar claves criptográficas de Cloud KMS, se debe otorgar al usuario el permiso cloudkms.cryptokeys.list en el llavero de claves que contiene las claves criptográficas, no en las claves en sí. Estos tipos de permisos se denominan permisos solo para superiores y se aplican solo en operaciones list.

Para otorgar el acceso a los permisos *.*.list de forma adecuada cuando se usan condiciones, se deben establecer los atributos resource.service y resource.type mediante la expresión de condición en función del tipo de recurso superior de los recursos de destino que se enumerarán.

Considera los siguientes ejemplos: Mediante el uso del ejemplo anterior de Compute Engine, la siguiente expresión impide el acceso a los permisos compute.disks.list y compute.instances.list, ya que el recurso en el que se verifican estos permisos tiene un 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'))

Es común que estos permisos list se otorguen junto con otros permisos para las operaciones regulares en el recurso. En este caso, si deseas aumentar el permiso de la concesión, puedes extenderlo solo al tipo cloudresourcemanager.googleapis.com/Project o extenderlo a todos los demás permisos que no sean del tipo de instancias o discos.

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

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