Análisis de políticas con lint

En este tema, se describe cómo analizar con lint, o validar, las políticas de permisos de Identity and Access Management (IAM).

Antes de comenzar

Funciones requeridas

A fin de analizar con lint la política de permisos de un recurso, necesitas permisos para obtener el recurso y obtener y establecer la política de permisos del recurso. Estos permisos tienen el siguiente formato, en el que SERVICE es el nombre del servicio que posee el recurso y RESOURCE_TYPE es el nombre del tipo de recurso al que deseas administrar el acceso:

  • SERVICE.RESOURCE_TYPE.get
  • SERVICE.RESOURCE_TYPE.getIamPolicy
  • SERVICE.RESOURCE_TYPE.setIamPolicy

Por ejemplo, para analizar con lint la política de permisos de un proyecto, necesitas los siguientes permisos:

  • resourcemanager.projects.get
  • resourcemanager.projects.getIamPolicy
  • resourcemanager.projects.setIamPolicy

Para obtener los permisos necesarios, pídele a tu administrador que te otorgue una función predefinida o personalizada que incluya los permisos. Por ejemplo, el administrador podría otorgarte el rol Security Admin (roles/iam.securityAdmin), que incluye permisos para obtener casi todos los recursos de Google Cloud y administrar sus políticas de permisos.

Comprende el análisis con lint para las políticas de permisos

En el contexto de las políticas de permisos, el análisis con lint es un método para examinar una política de permisos nueva o existente y verificar si tiene problemas específicos. Entre estos problemas se incluye el siguiente rango de posibilidades:

  • Sugerencias
  • Advertencias
  • Información que puede ayudar a mejorar la intención de la política de permisos, como una sintaxis o una semántica más adecuadas
  • Errores sintácticos o semánticos que no permitirán que se completen correctamente las operaciones setIamPolicy

Si intentas actualizar una política de permisos y recibes un error, puedes analizar con lint la política de permisos para encontrar la causa del error. También puedes usar linter para garantizar que una vinculación de rol condicional tenga el efecto deseado.

Análisis de una condición con lint

Las expresiones de condición pueden ser complejas, en especial en situaciones que requieren varias cláusulas y operadores lógicos para administrar el acceso de manera adecuada. Si una expresión de condición contiene una lógica no válida o si la sintaxis infringe las restricciones de una expresión de condición, no puedes agregar la condición a una política de permisos.

Además, incluso si una expresión de condición usa la sintaxis correcta, puede contener errores semánticos, que pueden evitar que tus políticas de permisos y vinculaciones de roles funcionen como se espera. Los errores semánticos comunes incluyen los siguientes:

  • Uso de funciones no recomendadas
  • Uso de tipos de recursos heredados o nombres de servicios heredados
  • Condiciones ineficaces, como una fecha o un intervalo de tiempo inaplicables

Cuando lint una condición con lint, el linter inspecciona la expresión de condición y, luego, informa los errores de sintaxis. También informa posibles errores semánticos que podrían causar resultados inesperados.

Antes de que intentes establecer una nueva vinculación de función condicional, te recomendamos que analices la expresión con lint. En esta sección, se explica cómo analizar una expresión de condición con lint mediante la consola de Google Cloud, Google Cloud CLI o la API de REST.

Para analizar una expresión de condición con lint, haz lo siguiente:

Console

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

    Ir a IAM

  2. Haz clic en Seleccionar un proyecto, elige uno y haz clic en Abrir.

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

  4. En el panel Editar permisos, busca la función que deseas analizar con lint. Luego, en Condición de IAM (opcional), haz clic en el nombre de la condición.

  5. En el Editor de condición, agrega o edita una expresión de condición de forma manual.

  6. Para validar la sintaxis de CEL, haz clic en Ejecutar lint.

    Si la sintaxis tiene errores, aparecerá un ícono de Error junto a la línea incorrecta. Para ver los detalles de cada error, mantén el cursor sobre el ícono.

    Si la condición usa la sintaxis correcta, pero linter encuentra un posible problema, aparece un ícono de Advertencia junto a la línea con el problema. Para ver los detalles de cada advertencia, mantén el puntero sobre el ícono.

  7. Realiza los cambios necesarios en la expresión de condición. Después de hacer clic en Ejecutar linter, el linter se ejecuta de forma automática en segundo plano mientras editas la expresión.

    Debes corregir todos los errores antes de guardar la expresión de condición. Te recomendamos que también corrijas todas las advertencias.

  8. Cuando no haya errores ni advertencias, haz clic en Guardar para aplicar la condición.

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

Ejecuta el comando gcloud alpha iam policies lint-condition para analizar con lint una expresión de condición determinada. Para ejecutar este comando puedes crear un archivo de texto que contenga la condición o especificar marcas para el título, la descripción y la expresión de la condición.

En el siguiente ejemplo, se usa un archivo de texto que contiene la siguiente condición:

condition.json

{
  "title": "1_less_than_2",
  "description": "",
  "expression": "1 <"
}

Ejecuta el siguiente comando:

gcloud alpha iam policies lint-condition --condition-from-file="condition.json"

El resultado del comando contiene lo siguiente:

lintResults:
- debugMessage: |-
    ERROR: Parse expression:1:3: mismatched input '<EOF>' expecting {'[', '{', '(', '.', '-', '!', 'true', 'false', 'null', NUM_FLOAT, NUM_INT, NUM_UINT, STRING, BYTES, IDENTIFIER}
      | 1 >
      | ...^
  fieldName: condition.expression
  level: CONDITION
  locationOffset: 3
  severity: ERROR
  validationUnitName: LintValidationUnits/ConditionCompileCheck
...

Cada uno de los resultados del análisis con lint contiene un debugMessage que se puede usar para ayudar a localizar el problema de la expresión de condición. Si la condición no se compiló, es posible que veas muchos tipos de validationUnitName diferentes con el siguiente texto de debugMessage:

The validation unit is skipped due to absence of a required object: CheckedExpr

Realiza cambios para que la expresión se compile y, luego, vuelve a analizar la condición con lint.

REST

El método iamPolicies.lintPolicy analiza con lint, o valida, una expresión de condición en una política de permisos.

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

  • condition: Un objeto Expr que representa la condición para analizar con lint. Por ejemplo:

    "title": "1_less_than_2",
    "description": "",
    "expression": "1 <"
    

    Para obtener más información sobre el formato de un objeto Expr, consulta la referencia del esquema Expr.

Método HTTP y URL:

POST https://iam.googleapis.com/v1/iamPolicies:lintPolicy

Cuerpo JSON de la solicitud:

{
  "condition": {
    condition
  }
}

Para enviar tu solicitud, expande una de estas opciones:

El cuerpo de la respuesta contiene uno o más objetos LintResult, como los siguientes:

{
  "lint_results": {
    "level": "CONDITION",
    "validation_unit_name": "LintValidationUnits/ConditionCompileCheck",
    "severity": "ERROR",
    "field_name": "condition.expression",
    "location_offset": "2",
    "debug_message": "ERROR: Parse expression:1:2: mismatched input \'<EOF>\' expecting {\'[\', \'{\', \'(\', \'.\', \'-\', \'!\', \'true\', \'false\', \'null\', NUM_FLOAT, NUM_INT, NUM_UINT, STRING, BYTES, IDENTIFIER}\n  | 1<\n  | ..^"
  },
  "lint_results": {
    "level": "CONDITION",
    "validation_unit_name": "LintValidationUnits/ConditionComplexityCheck",
    "severity": "NOTICE",
    "field_name": "condition.expression",
    "debug_message": "The validation unit is skipped due to absence of a required object: CheckedExpr"
  }
}

Cada uno de los resultados de lint contiene un debug_message que se puede usar para ayudar a localizar el problema de la expresión de condición. Si no se pudo compilar la condición, es posible que veas muchos tipos de validation_unit_name diferentes con el siguiente texto de debugMessage:

The validation unit is skipped due to absence of a required object: CheckedExpr

Realiza cambios para que la expresión se compile y, luego, vuelve a analizar la condición con lint.

Unidades de validación compatibles

Como se describió anteriormente, una unidad de validación es un tipo de lint individual que evalúa la expresión para problemas sintácticos. En la siguiente tabla, se resumen las unidades de validación compatibles, cada una con el nivel de análisis con lint previsto, la gravedad de los resultados del análisis con lint y una breve descripción.

Unidad de validación Nivel de análisis con lint Gravedad Descripción
ConditionCompileCheck CONDITION ERROR La expresión de condición tiene un error de compilación como resultado de una sintaxis CEL no válida.
ConditionComplexityCheck CONDITION ERROR La expresión de condición tiene más de 12 operadores lógicos, que es la cantidad máxima.
DateTimeCheck CONDITION WARNING

La expresión de condición especifica una comparación de marca de tiempo que siempre se evalúa como verdadera o falsa debido a uno de estos problemas:

DateTimeRangeCheck CONDITION WARNING Valor fuera del rango para la función de marca de tiempo avanzada deseada y la expresión de comparación. Consulta los valores válidos para las funciones avanzadas de marca de tiempo.
DrgGetAttributeDefaultValueCheck CONDITION ERROR La expresión de condición llama a api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', V), en la que V es cualquier valor que no sea una lista vacía, []. Para este atributo de la API, V siempre debe ser una lista vacía.
EffectiveTimeRangeCheck CONDITION WARNING En un uso más complejo de funciones de marca de tiempo y comparación, la expresión devuelve un intervalo de tiempo efectivo vacío y, por lo tanto, resulta efectivamente falso. Como alternativa el intervalo de tiempo abarca un rango completo y, por lo tanto, resulta efectivamente verdadero.
HasOnlyListConstCheck CONDITION ERROR La expresión de condición llama a hasOnly(List<T>), en la que el tipo T no es un tipo constante, como una string o un número entero. La función hasOnly() solo acepta una lista de constantes.
HasOnlyListLengthCheck CONDITION ERROR La expresión de condición llama a hasOnly(List<T>), y List<T> contiene más de 10 elementos como máximo.
ResourceServiceLiteralCheck CONDITION WARNING No se admite el valor resource.service especificado. La expresión que usa ese valor literal de string para la comparación de igualdad es efectivamente falsa. Usa un valor admitido.
ResourceTypeLiteralCheck CONDITION WARNING No se admite el valor resource.type especificado. La expresión que usa ese valor literal de string para la comparación de igualdad es efectivamente falsa. Usa un valor admitido.
RestrictedAttributesCheck CONDITION WARNING La expresión usa un atributo que está restringido o que no es compatible. Es posible que no se pueda realizar la configuración de la expresión de condición. Consulta la lista de atributos.

Ejemplos de análisis con lint

En esta sección, se muestran ejemplos de condiciones que hacen que cada unidad de validación informe problemas. Cada ejemplo ilustra el análisis con lint empleando Google Cloud CLI.

No hay problemas de validación

Ejemplo de condición:

{
  "title": "1_less_than_2",
  "description": "",
  "expression": "1 < 2"
}

Ejecuta el siguiente comando:

gcloud alpha iam policies lint-condition --condition-from-file="condition.json"

Resultado de lint:

{}

ConditionCompileCheck

Ejemplo de condición:

{
  "title": "Condition not compiling",
  "description": "",
  "expression": "true=false"
}

Ejecuta el siguiente comando:

gcloud alpha iam policies lint-condition --condition-from-file="condition.json"

Resultado de lint:

lintResults:
- debugMessage: |-
    ERROR: Parse expression:1:4: token recognition error at: '=f'
      | true=false
      | ....^
  fieldName: condition.expression
  level: CONDITION
  locationOffset: 4
  severity: ERROR
  validationUnitName: LintValidationUnits/ConditionCompileCheck

ConditionComplexityCheck

Ejemplo de condición:

{
  "title": "Condition not compiling",
  "description": "",
  "expression":
    "1<2 || 2<3 || 3<4 || 4<5 || 5<6 || 6<7 || 7<8 || 8<9 || 9<10 || 10<11 || 11<12 || 12<13 || 13<14 || 14<15"
}

Ejecuta el siguiente comando:

gcloud alpha iam policies lint-condition --condition-from-file="condition.json"

Resultado de lint:

lintResults:
- debugMessage: Logical operators count must not be more than 12
  fieldName: condition.expression
  level: CONDITION
  severity: ERROR
  validationUnitName: LintValidationUnits/ConditionComplexityCheck

DateTimeCheck

Ejemplo de condición:

{
  "title": "Condition not compiling",
  "description": "",
  "expression": "request.time < timestamp('2000-01-01T00:00:00Z')"
}

Ejecuta el siguiente comando:

gcloud alpha iam policies lint-condition --condition-from-file="condition.json"

Resultado de lint:

lintResults:
- debugMessage: Ineffective date time value 2000-01-01T00:00:00+00:00 parsed
    from "2000-01-01T00:00:00Z"; condition is effectively False. Time expired
    already.
  fieldName: condition.expression
  level: CONDITION
  locationOffset: 25
  severity: WARNING
  validationUnitName: LintValidationUnits/DateTimeCheck

DateTimeRangeCheck

Ejemplo de condición:

{
  "title": "Time function out of range",
  "description": "",
  "expression": "request.time.getMonth() > 13"
}

Ejecuta el siguiente comando:

gcloud alpha iam policies lint-condition --condition-from-file="condition.json"

Resultado de lint:

lintResults:
- debugMessage: The value being compared to the specified timestamp function
    (getMonth) must be in range [0, 11].
  fieldName: condition.expression
  level: CONDITION
  locationOffset: 26
  severity: WARNING
  validationUnitName: LintValidationUnits/DateTimeRangeCheck

DrgGetAttributeDefaultValueCheck

Ejemplo de condición:

{
  "title": "DRG condition takes non empty list as default value",
  "description": "",
  "expression":
    "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', ['roles/viewer']).hasOnly(['roles/editor'])"
}

Ejecuta el siguiente comando:

gcloud alpha iam policies lint-condition --condition-from-file="condition.json"

Resultado de lint:

lintResults:
- debugMessage: api.getAttribute call on
    'iam.googleapis.com/modifiedGrantsByRole' can only
    accept empty list ('[]') as default value.
  fieldName: condition.expression
  level: CONDITION
  locationOffset: 60
  severity: ERROR
  validationUnitName: LintValidationUnits/DrgGetAttributeDefaultValueCheck

EffectiveTimeRangeCheck

Ejemplo de condición:

{
  "title": "Empty time range",
  "description": "",
  "expression": "request.time.getMonth() > 5 && request.time.getMonth() < 4"
}

Ejecuta el siguiente comando:

gcloud alpha iam policies lint-condition --condition-from-file="condition.json"

Resultado de lint:

lintResults:
- debugMessage: The aggregate of time functions [getMonth] results in empty ranges.
  fieldName: condition.expression
  level: CONDITION
  severity: WARNING
  validationUnitName: LintValidationUnits/EffectiveTimeRangeCheck

HasOnlyListConstCheck

Ejemplo de condición:

{
  "title": "hasOnly contains more than constant value",
  "description": "",
  "expression":
    "api.getAttribute('somekey', []).hasOnly(['somevalue', resource.name])"
}

Ejecuta el siguiente comando:

gcloud alpha iam policies lint-condition --condition-from-file="condition.json"

Resultado de lint:

lintResults:
- debugMessage: hasOnly() expects an argument of type list containing only const
      values, but a non-const expression was found in the list.
  fieldName: condition.expression
  level: CONDITION
  locationOffset: 59
  severity: ERROR
  validationUnitName: LintValidationUnits/HasOnlyListConstCheck

HasOnlyListLengthCheck

Ejemplo de condición:

{
  "title": "hasOnly contains more than 10 elements",
  "description": "",
  "expression":
    "api.getAttribute('somekey', []).hasOnly([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])"
}

Ejecuta el siguiente comando:

gcloud alpha iam policies lint-condition --condition-from-file="condition.json"

Resultado de lint:

lintResults:
- debugMessage: The list argument to hasOnly() cannot have more than 10 elements
  fieldName: condition.expression
  level: CONDITION
  locationOffset: 39
  severity: ERROR
  validationUnitName: LintValidationUnits/HasOnlyListLengthCheck

ResourceServiceLiteralCheck

Ejemplo de condición:

{
  "title": "Condition with unsupported resource service string",
  "description": "",
  "expression": "resource.service == 'resourcemanager'"
}

Ejecuta el siguiente comando:

gcloud alpha iam policies lint-condition --condition-from-file="condition.json"

Resultado de lint:

lintResults:
- debugMessage: 'resource.service : resourcemanager is not supported. Using this
    value in condition may lead to unintended consequences. Check user guide at
    https://cloud.google.com/iam/docs/conditions-resource-attributes#resource_service_values
    for supported values for resource.service.'
  fieldName: condition.expression
  level: CONDITION
  locationOffset: 20
  severity: WARNING
  validationUnitName: LintValidationUnits/ResourceServiceLiteralCheck

ResourceTypeLiteralCheck

Ejemplo de condición:

{
  "title": "Condition with legacy resource type",
  "description": "",
  "expression": "resource.type == 'resourcemanager.projects'"
}

Ejecuta el siguiente comando:

gcloud alpha iam policies lint-condition --condition-from-file="condition.json"

Resultado de lint:

lintResults:
- debugMessage: 'resource.type : resourcemanager.projects is not supported.
    Using this value in condition may lead to unintended consequences. Check
    user guide at https://cloud.google.com/iam/docs/conditions-resource-attributes#resource_type_values
    for supported values for resource.type.'
  fieldName: condition.expression
  level: CONDITION
  locationOffset: 17
  severity: WARNING
  validationUnitName: LintValidationUnits/ResourceTypeLiteralCheck

RestrictedAttributesCheck

Ejemplo de condición:

{
  "title": "Condition with restricted attribute",
  "description": "",
  "expression": "'accessPolicies/123/accesslevels/TRUSTED' in request.auth.access_levels"
}

Ejecuta el siguiente comando:

gcloud alpha iam policies lint-condition --condition-from-file="condition.json"

Resultado de lint:

lintResults:
- debugMessage: Condition attribute `request.auth.access_levels` is restricted
    or unsupported. Please check https://cloud.google.com/iam/docs/conditions-overview
    for the full list of supported attributes
  fieldName: condition.expression
  level: CONDITION
  locationOffset: 57
  severity: WARNING
  validationUnitName: LintValidationUnits/RestrictedAttributesCheck