Configura el acceso basado en recursos

En este tema, se describe cómo administrar el acceso a recursos específicos mediante vinculaciones de funciones condicionales en tus políticas de administración de identidades y accesos (IAM). 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 IAM para comprender los conceptos básicos de las vinculaciones de funciones 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:
    • Cloud Spanner
    • Cloud Storage
    • Compute Engine
    • Identity-Aware Proxy
    • Cloud Key Management Service
    • Resource Manager (solo tipo de recurso y servicio de recurso)
    • Secret Manager

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 los miembros 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 Cloud Console, ve a la página IAM.

    Ir a la página IAM

  2. En la lista de miembros, busca el miembro deseado 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, haz clic en Agregar condición.

  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 condición. 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.
    28. Cuando hayas terminado, el creador de condiciones debería verse como el que se muestra a continuación:

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

    30. 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 IAM.

    Editor de condición:

    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 Lint 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 IAM.

gcloud

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

Ejecuta el comando gcloud projects get-iam-policy a fin de obtener la política de IAM actual para el proyecto. En el siguiente ejemplo, la versión JSON de la política 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 IAM:

{
  "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 la política con una condición de prefijo del nombre del recurso, debes agregar la siguiente expresión de condición destacada. Si no usas la versión 263.0.0 o posterior de la herramienta de gcloud, asegúrate de actualizar el valor version3. Si usas una versión más reciente de la herramienta de gcloud, el valor máximo de la política se establecerá de forma automática para ti:

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

A continuación, configura la política 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 función condicional otorgará permisos a devs@example.com 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 lectura-modificación-escritura para permitir el acceso a recursos específicos.

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

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

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

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:project-owner@example.com"
      ]
    },
    {
      "members": [
        "group:devs@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: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 último, escribe la política actualizada:

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

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

  • project-id: El ID de tu proyecto de Google Cloud.

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: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 tu solicitud, expande una de estas opciones:

La respuesta contiene la política 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 depósitos de Cloud Storage y que los objetos de cada depósito están organizados por fecha. Un nombre de objeto típico puede ser similar al siguiente ejemplo:

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

Quieres hacer coincidir cualquier pedido de los últimos 30 días. La siguiente condición coincide con 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:

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 necesitas hacer coincidir cualquier VM de Compute Engine en cualquier ubicación cuyo nombre comience con dev-. 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 si el nombre de la instancia comienza con la string dev-:

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 que se encuentre entre la primera aparición de la string /instances/ y la siguiente aparición de la string /.

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 otorgados.

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:

"expression":
"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:

"expression":
"(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:

"expression":
"(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.

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

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.

"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 == 'cloudresourcemanager.googleapis.com/Project'"

o

"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/Disk' &&
  resource.type != 'compute.googleapis.com/Instance')"