

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# AWS CloudFormation Guard Regras de redação
<a name="writing-rules"></a>

Dentro AWS CloudFormation Guard, *regras* são policy-as-code regras. Você escreve regras na linguagem específica de domínio (DSL) do Guard com as quais você pode validar seus dados formatados em JSON ou YAML. As regras são compostas por *cláusulas*.

Você pode salvar regras escritas usando o Guard DSL em arquivos de texto simples que usam qualquer extensão de arquivo.

Você pode criar vários arquivos de regras e categorizá-los como um *conjunto de regras*. Os conjuntos de regras permitem que você valide seus dados formatados em JSON ou YAML em relação a vários arquivos de regras ao mesmo tempo.

**Topics**
+ [Cláusulas](#clauses)
+ [Usando consultas em cláusulas](#clauses-queries)
+ [Usando operadores em cláusulas](#clauses-operators)
+ [Usando mensagens personalizadas em cláusulas](#clauses-custom-messages)
+ [Combinando cláusulas](#combining-clauses)
+ [Usando blocos com regras do Guard](#blocks)
+ [Usando funções integradas](#built-in-functions)
+ [Definindo consultas e filtragem do Guard](query-and-filtering.md)
+ [Atribuição e referência de variáveis nas regras do Guard](variables.md)
+ [Composição de blocos de regras nomeadas em AWS CloudFormation Guard](named-rule-block-composition.md)
+ [Escrevendo cláusulas para realizar avaliações contextuais](context-aware-evaluations.md)

## Cláusulas
<a name="clauses"></a>

As cláusulas são expressões booleanas que são avaliadas como verdadeiras (`PASS`) ou falsas (`FAIL`). As cláusulas usam operadores binários para comparar dois valores ou operadores unários que operam em um único valor.

**Exemplos de cláusulas unárias**

A cláusula unária a seguir avalia se a coleção `TcpBlockedPorts` está vazia.

```
InputParameters.TcpBlockedPorts not empty
```

A cláusula unária a seguir avalia se a `ExecutionRoleArn` propriedade é uma string.

```
Properties.ExecutionRoleArn is_string
```

**Exemplos de cláusulas binárias**

A cláusula binária a seguir avalia se a `BucketName` propriedade contém a string`encrypted`, independentemente da maiúscula e minúscula.

```
Properties.BucketName != /(?i)encrypted/
```

A cláusula binária a seguir avalia se a `ReadCapacityUnits` propriedade é menor ou igual a 5.000.

```
Properties.ProvisionedThroughput.ReadCapacityUnits <= 5000
```

### Sintaxe para escrever cláusulas de regras do Guard
<a name="clauses-syntax"></a>

```
<query> <operator> [query|value literal] [custom message]
```

### Propriedades das cláusulas da regra de guarda
<a name="clauses-properties"></a>

`query`  <a name="clauses-properties-query"></a>
Uma expressão separada por ponto (`.`) escrita para atravessar dados hierárquicos. As expressões de consulta podem incluir expressões de filtro para direcionar um subconjunto de valores. As consultas podem ser atribuídas a variáveis para que você possa escrevê-las uma vez e referenciá-las em outro lugar em um conjunto de regras, o que permitirá acessar os resultados da consulta.  
Para obter mais informações sobre como escrever consultas e filtrar, consulte. [Definição de consultas e filtragem](query-and-filtering.md)  
 *Obrigatório*: sim

`operator`  <a name="clauses-properties-operator"></a>
Um operador unário ou binário que ajuda a verificar o estado da consulta. O lado esquerdo (LHS) de um operador binário deve ser uma consulta e o lado direito (RHS) deve ser uma consulta ou um valor literal.  
 *Operadores binários suportados*: `==` (Igual) \$1 `!=` (Diferente) \$1 `>` (Maior que) \$1 `>=` (Maior que ou igual a) \$1 `<` (Menor que) \$1 `<=` (Menor que ou igual a) \$1 `IN` (Em uma lista no formato [x, y, z]  
 *Operadores unários suportados*: `exists` \$1 `empty` \$1 \$1 `is_string` \$1 `is_list` \$1 `is_struct` `not(!)`  
 *Obrigatório*: sim

`query|value literal`  <a name="clauses-properties-value-literal"></a>
Uma consulta ou um valor literal compatível, como `string` ou`integer(64)`.   
*Literais de valor suportados*:  
+ Todos os tipos primitivos:`string`,`integer(64)`,,`float(64)`,`bool`, `char` `regex`
+ Todos os tipos de intervalos especializados para expressão `integer(64)``float(64)`, ou `char` intervalos expressos como:
  + `r[<lower_limit>, <upper_limit>]`, que se traduz em qualquer valor `k` que satisfaça a seguinte expressão: `lower_limit <= k <= upper_limit`
  + `r[<lower_limit>, <upper_limit>`), que se traduz em qualquer valor `k` que satisfaça a seguinte expressão: `lower_limit <= k < upper_limit`
  + `r(<lower_limit>, <upper_limit>]`, que se traduz em qualquer valor `k` que satisfaça a seguinte expressão: `lower_limit < k <= upper_limit`
  + `r(<lower_limit>, <upper_limit>),`que se traduz em qualquer valor `k` que satisfaça a seguinte expressão: `lower_limit < k < upper_limit`
+ Matrizes associativas (mapas) para dados de estrutura de valores-chave aninhados. Por exemplo:

  `{ "my-map": { "nested-maps": [ { "key": 10, "value": 20 } ] } }`
+ Matrizes de tipos primitivos ou tipos de matrizes associativas
 *Obrigatório*: Condicional; obrigatório quando um operador binário é usado.

`custom message`  <a name="clauses-properties-custom-message"></a>
Uma string que fornece informações sobre a cláusula. A mensagem é exibida nas saídas detalhadas dos `test` comandos `validate` and e pode ser útil para entender ou depurar a avaliação de regras em dados hierárquicos.  
 *Obrigatório*: não

## Usando consultas em cláusulas
<a name="clauses-queries"></a>

Para obter informações sobre como escrever consultas, consulte [Definição de consultas e filtragem](query-and-filtering.md) e. [Atribuição e referência de variáveis nas regras do Guard](variables.md)

## Usando operadores em cláusulas
<a name="clauses-operators"></a>

A seguir estão exemplos CloudFormation de modelos `Template-1` `Template-2` e. Para demonstrar o uso de operadores compatíveis, os exemplos de consultas e cláusulas nesta seção se referem a esses modelos de exemplo.

**Modelo-1**

```
Resources:
 S3Bucket:
   Type: AWS::S3::Bucket
   Properties:
     BucketName: MyServiceS3Bucket
     BucketEncryption:
       ServerSideEncryptionConfiguration:
         - ServerSideEncryptionByDefault:
             SSEAlgorithm: 'aws:kms'
             KMSMasterKeyID: 'arn:aws:kms:us-east-1:123456789:key/056ea50b-1013-3907-8617-c93e474e400'
     Tags:
       - Key: stage
         Value: prod
       - Key: service
         Value: myService
```

**Modelo-2**

```
Resources:
 NewVolume:
   Type: AWS::EC2::Volume
   Properties: 
     Size: 100
     VolumeType: io1
     Iops: 100
     AvailabilityZone:
       Fn::Select:
         - 0
         - Fn::GetAZs: us-east-1
     Tags:
       - Key: environment
         Value: test
   DeletionPolicy: Snapshot
```

### Exemplos de cláusulas que usam operadores unários
<a name="clauses-unary-operators"></a>
+ `empty`— Verifica se uma coleção está vazia. Você também pode usá-lo para verificar se uma consulta tem valores em dados hierárquicos porque as consultas resultam em uma coleção. Você não pode usá-lo para verificar se as consultas de valor de string têm uma string (`""`) vazia definida. Para obter mais informações, consulte [Definição de consultas e filtragem](query-and-filtering.md).

  A cláusula a seguir verifica se o modelo tem um ou mais recursos definidos. É avaliado `PASS` porque um recurso com o ID lógico `S3Bucket` está definido em`Template-1`.

  ```
  Resources !empty
  ```

  A cláusula a seguir verifica se uma ou mais tags estão definidas para o `S3Bucket` recurso. É avaliado `PASS` porque `S3Bucket` tem duas tags definidas para a `Tags` propriedade em`Template-1`.

  ```
  Resources.S3Bucket.Properties.Tags !empty
  ```
+ `exists`— Verifica se cada ocorrência da consulta tem um valor e pode ser usada no lugar de`!= null`.

  A cláusula a seguir verifica se a `BucketEncryption` propriedade está definida para o. `S3Bucket` É avaliado como `PASS` porque `BucketEncryption` está definido para `S3Bucket` em`Template-1`.

  ```
  Resources.S3Bucket.Properties.BucketEncryption exists
  ```

**nota**  
As `not exists` verificações `empty` e avaliam a ausência `true` de chaves de propriedade ao percorrer os dados de entrada. Por exemplo, se a `Properties` seção não estiver definida no modelo para o`S3Bucket`, a cláusula será `Resources.S3Bucket.Properties.Tag empty` avaliada como. `true` As `empty` verificações `exists` e não exibem o caminho do ponteiro JSON dentro do documento nas mensagens de erro. Ambas as cláusulas geralmente têm erros de recuperação que não mantêm essas informações de travessia.
+ `is_string`— Verifica se cada ocorrência da consulta é do `string` tipo.

  A cláusula a seguir verifica se um valor de string foi especificado para a `BucketName` propriedade do `S3Bucket` recurso. É avaliado como `PASS` porque o valor da string `"MyServiceS3Bucket"` é especificado para `BucketName` in`Template-1`.

  ```
  Resources.S3Bucket.Properties.BucketName is_string
  ```
+ `is_list`— Verifica se cada ocorrência da consulta é do `list` tipo.

  A cláusula a seguir verifica se uma lista foi especificada para a `Tags` propriedade do `S3Bucket` recurso. É avaliado como `PASS` porque dois pares de valores-chave são especificados em. `Tags` `Template-1`

  ```
  Resources.S3Bucket.Properties.Tags is_list
  ```
+ `is_struct`— Verifica se cada ocorrência da consulta é um dado estruturado.

  A cláusula a seguir verifica se os dados estruturados estão especificados para a `BucketEncryption` propriedade do `S3Bucket` recurso. É avaliado como `PASS` porque `BucketEncryption` é especificado usando o tipo de `ServerSideEncryptionConfiguration` propriedade *(object)* em`Template-1`.

  ```
  Resources.S3Bucket.Properties.BucketEncryption is_struct
  ```

**nota**  
Para verificar o estado inverso, você pode usar o operador (` not !`) com os `is_struct` operadores `is_string``is_list`, e.

### Exemplos de cláusulas que usam operadores binários
<a name="clauses-binary-operators"></a>

A cláusula a seguir verifica se o valor especificado para a `BucketName` propriedade do `S3Bucket` recurso em `Template-1` contém a string`encrypt`, independentemente da maiúscula e minúscula. Isso acontece `PASS` porque o nome do bucket especificado `"MyServiceS3Bucket"` não contém a string`encrypt`.

```
Resources.S3Bucket.Properties.BucketName != /(?i)encrypt/
```

A cláusula a seguir verifica se o valor especificado para a `Size` propriedade do `NewVolume` recurso em `Template-2` está dentro de um intervalo específico: 50 <= `Size` <= 200. É avaliado como `PASS` porque `100` está especificado para`Size`.

```
Resources.NewVolume.Properties.Size IN r[50,200]
```

A cláusula a seguir verifica se o valor especificado para a `VolumeType` propriedade do `NewVolume` recurso em `Template-2` é `io1``io2`, ou`gp3`. É avaliado como `PASS` porque `io1` está especificado para`NewVolume`.

```
Resources.NewVolume.Properties.NewVolume.VolumeType IN [ 'io1','io2','gp3' ]
```

**nota**  
Os exemplos de consultas nesta seção demonstram o uso de operadores usando os recursos com lógica IDs `S3Bucket` e. `NewVolume` Os nomes dos recursos geralmente são definidos pelo usuário e podem ser nomeados arbitrariamente em um modelo de infraestrutura como código (IaC). Para escrever uma regra que seja genérica e se aplique a todos os `AWS::S3::Bucket` recursos definidos no modelo, a forma mais comum de consulta usada é`Resources.*[ Type == ‘AWS::S3::Bucket’ ]`. Para obter mais informações, consulte [Definição de consultas e filtragem](query-and-filtering.md) para obter detalhes sobre o uso e explore o diretório de [exemplos](https://github.com/aws-cloudformation/cloudformation-guard/tree/main/guard-examples) no `cloudformation-guard` GitHub repositório.

## Usando mensagens personalizadas em cláusulas
<a name="clauses-custom-messages"></a>

No exemplo a seguir, cláusulas para `Template-2` incluir uma mensagem personalizada.

```
Resources.NewVolume.Properties.Size IN r(50,200) 
<<
    EC2Volume size must be between 50 and 200, 
    not including 50 and 200
>>
Resources.NewVolume.Properties.VolumeType IN [ 'io1','io2','gp3' ] <<Allowed Volume Types are io1, io2, and gp3>>
```

## Combinando cláusulas
<a name="combining-clauses"></a>

No Guard, cada cláusula escrita em uma nova linha é combinada implicitamente com a próxima cláusula usando conjunção (lógica booleana). `and` Veja o exemplo a seguir.

```
# clause_A ^ clause_B ^ clause_C
clause_A
clause_B
clause_C
```

Você também pode usar a disjunção para combinar uma cláusula com a próxima cláusula especificando `or|OR` no final da primeira cláusula.

```
<query> <operator> [query|value literal] [custom message] [or|OR]
```

Em uma cláusula de Guarda, as disjunções são avaliadas primeiro, seguidas pelas conjunções. As regras de proteção podem ser definidas como uma conjunção de disjunção de cláusulas (e `and|AND` de `or|OR` s) que são avaliadas como () ou `true` (`PASS`). `false` `FAIL` Isso é semelhante à forma [normal conjuntiva](https://en.wikipedia.org/wiki/Conjunctive_normal_form). 

Os exemplos a seguir demonstram a ordem das avaliações das cláusulas.

```
# (clause_E v clause_F) ^ clause_G
clause_E OR clause_F
clause_G

# (clause_H v clause_I) ^ (clause_J v clause_K)
clause_H OR
clause_I
clause_J OR
clause_K

# (clause_L v clause_M v clause_N) ^ clause_O
clause_L OR
clause_M OR
clause_N 
clause_O
```

Todas as cláusulas baseadas no exemplo `Template-1` podem ser combinadas usando a conjunção. Veja o exemplo a seguir.

```
Resources.S3Bucket.Properties.BucketName is_string
Resources.S3Bucket.Properties.BucketName != /(?i)encrypt/
Resources.S3Bucket.Properties.BucketEncryption exists
Resources.S3Bucket.Properties.BucketEncryption is_struct
Resources.S3Bucket.Properties.Tags is_list
Resources.S3Bucket.Properties.Tags !empty
```

## Usando blocos com regras do Guard
<a name="blocks"></a>

Blocos são composições que removem a verbosidade e a repetição de um conjunto de cláusulas, condições ou regras relacionadas. Existem três tipos de blocos:
+ Blocos de consulta
+ `when`blocos
+ Blocos de regras nomeadas

### Blocos de consulta
<a name="query-blocks"></a>

A seguir estão as cláusulas baseadas no exemplo`Template-1`. A conjunção foi usada para combinar as cláusulas.

```
Resources.S3Bucket.Properties.BucketName is_string
Resources.S3Bucket.Properties.BucketName != /(?i)encrypt/
Resources.S3Bucket.Properties.BucketEncryption exists
Resources.S3Bucket.Properties.BucketEncryption is_struct
Resources.S3Bucket.Properties.Tags is_list
Resources.S3Bucket.Properties.Tags !empty
```

Partes da expressão de consulta em cada cláusula são repetidas. Você pode melhorar a composição e remover a verbosidade e a repetição de um conjunto de cláusulas relacionadas com o mesmo caminho de consulta inicial usando um bloco de consulta. O mesmo conjunto de cláusulas pode ser escrito conforme mostrado no exemplo a seguir.

```
Resources.S3Bucket.Properties {
    BucketName is_string
    BucketName != /(?i)encrypt/
    BucketEncryption exists
    BucketEncryption is_struct
    Tags is_list
    Tags !empty
}
```

Em um bloco de consulta, a consulta anterior ao bloco define o contexto das cláusulas dentro do bloco.

Para obter mais informações sobre o uso de blocos, consulte[Composição de blocos de regras nomeadas](named-rule-block-composition.md).

### `when`blocos
<a name="when-blocks"></a>

Você pode avaliar blocos condicionalmente usando `when` blocos, que assumem o seguinte formato.

```
  when <condition> {
       Guard_rule_1
       Guard_rule_2
       ...
   }
```

A `when` palavra-chave designa o início do `when` bloco. `condition`é uma regra da Guarda. O bloco só é avaliado se a avaliação da condição resultar em `true` (`PASS`).

A seguir está um exemplo de `when` bloco baseado em`Template-1`.

```
when Resources.S3Bucket.Properties.BucketName is_string {
     Resources.S3Bucket.Properties.BucketName != /(?i)encrypt/
 }
```

A cláusula dentro do `when` bloco só é avaliada se o valor especificado `BucketName` for uma string. Se o valor especificado para `BucketName` for referenciado na `Parameters` seção do modelo, conforme mostrado no exemplo a seguir, a cláusula dentro do `when` bloco não será avaliada.

```
Parameters:
   S3BucketName:
     Type: String
 Resources:
   S3Bucket:
     Type: AWS::S3::Bucket
     Properties:
       BucketName: 
         Ref: S3BucketName
     ...
```

### Blocos de regras nomeadas
<a name="named-rule-blocks"></a>

*Você pode atribuir um nome a um conjunto de regras (conjunto de regras) e, em seguida, referenciar esses blocos de validação modulares, chamados de blocos *de regras nomeadas*, em outras regras.* Os blocos de regras nomeadas assumem o seguinte formato.

```
  rule <rule name> [when <condition>] {
    Guard_rule_1
    Guard_rule_2
    ...
    }
```

A `rule` palavra-chave designa o início do bloco de regras nomeadas.

`rule name`é uma string legível por humanos que identifica de forma exclusiva um bloco de regras nomeadas. É um rótulo para o conjunto de regras do Guard que ele encapsula. Nesse uso, o termo *regra de proteção* inclui cláusulas, blocos de consulta, blocos e `when` blocos de regras nomeadas. O nome da regra pode ser usado para se referir ao resultado da avaliação do conjunto de regras que ela encapsula, o que torna os blocos de regras nomeadas reutilizáveis. O nome da regra também fornece contexto sobre falhas de regras nas saídas do `test` comando `validate` e. O nome da regra é exibido junto com o status de avaliação do bloco (`PASS``FAIL`, ou`SKIP`) na saída de avaliação do arquivo de regras. Veja o exemplo a seguir.

```
# Sample output of an evaluation where check1, check2, and check3 are rule names.
template.json Status = **FAIL**
**SKIP rules**
check1 **SKIP**
**PASS rules**
check2 **PASS**
**FAILED rules**
check3 **FAIL**
```

Você também pode avaliar blocos de regras nomeadas condicionalmente especificando a `when` palavra-chave seguida por uma condição após o nome da regra.

A seguir está o `when` bloco de exemplo que foi discutido anteriormente neste tópico.

```
rule checkBucketNameStringValue when Resources.S3Bucket.Properties.BucketName is_string {
    Resources.S3Bucket.Properties.BucketName != /(?i)encrypt/
}
```

Usando blocos de regras nomeadas, o precedente também pode ser escrito da seguinte forma.

```
rule checkBucketNameIsString {
    Resources.S3Bucket.Properties.BucketName is_string
}
rule checkBucketNameStringValue when checkBucketNameIsString {
    Resources.S3Bucket.Properties.BucketName != /(?i)encrypt/
}
```

Você pode reutilizar e agrupar blocos de regras nomeadas com outras regras do Guard. A seguir estão alguns exemplos.

```
rule rule_name_A {
    Guard_rule_1 OR
    Guard_rule_2
    ...
}

rule rule_name_B {
    Guard_rule_3
    Guard_rule_4
    ...
}

rule rule_name_C {
    rule_name_A OR rule_name_B
}

rule rule_name_D {
    rule_name_A
    rule_name_B
}

rule rule_name_E when rule_name_D {
    Guard_rule_5
    Guard_rule_6
    ...
}
```

## Usando funções integradas
<a name="built-in-functions"></a>

AWS CloudFormation Guard fornece funções integradas que você pode usar em suas regras para realizar operações como manipulação de strings, análise de JSON e conversão de tipo de dados. As funções são suportadas somente por meio da atribuição a uma variável.

### Funções-chave
<a name="key-functions"></a>

`json_parse(json_string)`  
Analisa cadeias de caracteres JSON embutidas a partir de um modelo. Após a análise, você pode avaliar as propriedades do objeto resultante.

`count(collection)`  
Retorna o número de itens para os quais uma consulta é resolvida.

`regex_replace(base_string, regex_to_extract, regex_replacement)`  
Substitui partes de uma string usando expressões regulares.

Para obter uma lista completa das funções disponíveis, incluindo manipulação de strings, operações de coleta e funções de conversão de tipo de dados, consulte a [documentação de funções](https://github.com/aws-cloudformation/cloudformation-guard/blob/main/docs/FUNCTIONS.md) no GitHub repositório Guard.

# Definindo consultas e filtragem do Guard
<a name="query-and-filtering"></a>

Este tópico aborda como escrever consultas e usar a filtragem ao escrever cláusulas de regras do Guard.

## Pré-requisitos
<a name="query-filtering-prerequisites"></a>

A filtragem é um AWS CloudFormation Guard conceito avançado. Recomendamos que você analise os seguintes tópicos fundamentais antes de aprender sobre filtragem:
+ [O que é AWS CloudFormation Guard?](what-is-guard.md)
+ [Regras de redação, cláusulas](writing-rules.md)

## Definindo consultas
<a name="defining-queries"></a>

As expressões de consulta são expressões simples separadas por ponto (`.`) escritas para atravessar dados hierárquicos. As expressões de consulta podem incluir expressões de filtro para direcionar um subconjunto de valores. Quando as consultas são avaliadas, elas resultam em uma coleção de valores, semelhante a um conjunto de resultados retornado de uma consulta SQL.

O exemplo de consulta a seguir pesquisa `AWS::IAM::Role` recursos em um CloudFormation modelo.

```
Resources.*[ Type == 'AWS::IAM::Role' ]
```

As consultas seguem estes princípios básicos:
+ Cada parte dot (`.`) da consulta percorre a hierarquia quando um termo-chave explícito é usado, como `Resources` ou `Properties.Encrypted.` Se alguma parte da consulta não corresponder ao datum de entrada, o Guard gerará um erro de recuperação.
+ Uma parte dot (`.`) da consulta que usa um curinga `*` percorre todos os valores da estrutura nesse nível.
+ Uma parte dot (`.`) da consulta que usa um curinga de matriz `[*]` percorre todos os índices dessa matriz.
+ Todas as coleções podem ser filtradas especificando filtros dentro de colchetes. `[]` As coleções podem ser encontradas das seguintes maneiras:
  + As matrizes que ocorrem naturalmente no datum são coleções. A seguir estão exemplos da :

    Portas: `[20, 21, 110, 190]`

    Etiquetas: `[{"Key": "Stage", "Value": "PROD"}, {"Key": "App", "Value": "MyService"}]`
  + Ao percorrer todos os valores de uma estrutura como `Resources.*`
  + Qualquer resultado de consulta é, em si, uma coleção da qual os valores podem ser filtrados posteriormente. Veja o exemplo a seguir.

    ```
    # Query all resources
    let all_resources = Resource.*
    
    # Filter IAM resources from query results
    let iam_resources = %resources[ Type == /IAM/ ]
    
    # Further refine to get managed policies
    let managed_policies = %iam_resources[ Type == /ManagedPolicy/ ]
    
    # Traverse each managed policy
    %managed_policies {
        # Do something with each policy
    }
    ```

Veja a seguir um exemplo de trecho CloudFormation de modelo.

```
Resources:
  SampleRole:
    Type: AWS::IAM::Role
    ...
  SampleInstance:
    Type: AWS::EC2::Instance
    ...
  SampleVPC:
     Type: AWS::EC2::VPC
    ...
  SampleSubnet1:
    Type: AWS::EC2::Subnet
    ...
  SampleSubnet2:
    Type: AWS::EC2::Subnet
    ...
```

Com base nesse modelo, o caminho percorrido é `SampleRole` e o valor final selecionado é. `Type: AWS::IAM::Role`

```
Resources:
  SampleRole:
    Type: AWS::IAM::Role
    ...
```

O valor resultante da consulta `Resources.*[ Type == 'AWS::IAM::Role' ]` no formato YAML é mostrado no exemplo a seguir.

```
- Type: AWS::IAM::Role
  ...
```

Algumas das maneiras pelas quais você pode usar consultas são as seguintes:
+ Atribua uma consulta às variáveis para que os resultados da consulta possam ser acessados referenciando essas variáveis.
+ Siga a consulta com um bloco que testa cada um dos valores selecionados.
+ Compare uma consulta diretamente com uma cláusula básica.

## Atribuição de consultas a variáveis
<a name="queries-and-filtering-variables"></a>

O Guard suporta atribuições de variáveis únicas dentro de um determinado escopo. Para obter mais informações sobre variáveis nas regras do Guard, consulte[Atribuição e referência de variáveis nas regras do Guard](variables.md).

Você pode atribuir consultas a variáveis para poder escrever consultas uma vez e depois referenciá-las em outro lugar nas regras do Guard. Veja o exemplo a seguir de atribuições de variáveis que demonstram os princípios de consulta discutidos posteriormente nesta seção.

```
#
# Simple query assignment
#
let resources = Resources.* # All resources

#
# A more complex query here (this will be explained below)
#
let iam_policies_allowing_log_creates = Resources.*[
    Type in [/IAM::Policy/, /IAM::ManagedPolicy/]
    some Properties.PolicyDocument.Statement[*] {
         some Action[*] == 'cloudwatch:CreateLogGroup'
         Effect == 'Allow'
    }
]
```

## Percorrendo diretamente os valores de uma variável atribuída a uma consulta
<a name="variable-assigned-from-query"></a>

O Guard suporta a execução direta dos resultados de uma consulta. No exemplo a seguir, o `when` bloco testa a `AvailabilityZone` propriedade `Encrypted``VolumeType`, e para cada `AWS::EC2::Volume` recurso encontrado em um CloudFormation modelo.

```
let ec2_volumes = Resources.*[ Type == 'AWS::EC2::Volume' ] 

when %ec2_volumes !empty {
    %ec2_volumes {
        Properties {
            Encrypted == true
            VolumeType in ['gp2', 'gp3']
            AvailabilityZone in ['us-west-2b', 'us-west-2c']
        }
    }
}
```

## Comparações diretas em nível de cláusula
<a name="direct-clause-level-comparisons"></a>

O Guard também oferece suporte a consultas como parte das comparações diretas. Por exemplo, veja o seguinte:

```
let resources = Resources.*
    
    some %resources.Properties.Tags[*].Key == /PROD$/
    some %resources.Properties.Tags[*].Value == /^App/
```

No exemplo anterior, as duas cláusulas (começando com a `some` palavra-chave) expressas na forma mostrada são consideradas cláusulas independentes e são avaliadas separadamente.

### Formulário de cláusula única e cláusula de bloco
<a name="single-versus-block-clause-form"></a>

Juntas, as duas cláusulas de exemplo mostradas na seção anterior não são equivalentes ao bloco a seguir.

```
let resources = Resources.*

some %resources.Properties.Tags[*] {
    Key == /PROD$/
    Value == /^App/
}
```

Esse bloco consulta cada `Tag` valor na coleção e compara seus valores de propriedade com os valores de propriedade esperados. A forma combinada das cláusulas na seção anterior avalia as duas cláusulas de forma independente. Considere a seguinte entrada.

```
Resources:
  ...
  MyResource:
    ...
    Properties:
      Tags:
        - Key: EndPROD
          Value: NotAppStart
        - Key: NotPRODEnd
          Value: AppStart
```

As cláusulas na primeira forma são avaliadas como. `PASS` Ao validar a primeira cláusula na primeira forma, o caminho a seguir através de `Resources``Properties`,,`Tags`, e `Key` corresponde ao valor `NotPRODEnd` e não corresponde ao valor esperado. `PROD`

```
Resources:
  ...
  MyResource:
    ...
    Properties:
      Tags:
        - Key: EndPROD
          Value: NotAppStart
        - Key: NotPRODEnd
          Value: AppStart
```

O mesmo acontece com a segunda cláusula do primeiro formulário. O caminho através de `Resources``Properties`,`Tags`,, e `Value` corresponde ao valor`AppStart`. Como resultado, a segunda cláusula de forma independente.

O resultado geral é um`PASS`.

No entanto, o formulário de bloqueio é avaliado da seguinte forma. Para cada `Tags` valor, ele compara se o `Key` e `Value` corresponde; `NotAppStart` e `NotPRODEnd` os valores não são correspondidos no exemplo a seguir.

```
Resources:
  ...
  MyResource:
    ...
    Properties:
      Tags:
        - Key: EndPROD
          Value: NotAppStart
        - Key: NotPRODEnd
          Value: AppStart
```

Porque as avaliações verificam ambos e `Key == /PROD$/``Value == /^App/`, a partida não está completa. Portanto, o resultado é`FAIL`.

**nota**  
Ao trabalhar com coleções, recomendamos que você use o formulário de cláusula de bloco quando quiser comparar vários valores para cada elemento na coleção. Use o formulário de cláusula única quando a coleção for um conjunto de valores escalares ou quando você pretende comparar apenas um único atributo.

## Resultados da consulta e cláusulas associadas
<a name="query-outcomes"></a>

Todas as consultas retornam uma lista de valores. Qualquer parte de uma travessia, como uma chave ausente, valores vazios para um array (`Tags: []`) ao acessar todos os índices ou valores ausentes para um mapa ao encontrar um map (`Resources: {}`) vazio, pode levar a erros de recuperação.

Todos os erros de recuperação são considerados falhas ao avaliar as cláusulas em relação a essas consultas. A única exceção é quando filtros explícitos são usados na consulta. Quando os filtros são usados, as cláusulas associadas são ignoradas.

As seguintes falhas de bloco estão associadas à execução de consultas.
+ Se um modelo não contiver recursos, a consulta será avaliada como`FAIL`, e as cláusulas de nível de bloco associadas também serão avaliadas como. `FAIL`
+ Quando um modelo contém um bloco de recursos vazio`{ "Resources": {} }`, como, a consulta é avaliada como`FAIL`, e as cláusulas de nível de bloco associadas também são avaliadas como. `FAIL`
+ Se um modelo contiver recursos, mas nenhum corresponder à consulta, a consulta retornará resultados vazios e as cláusulas de nível de bloco serão ignoradas.

## Usando filtros em consultas
<a name="filtering"></a>

Os filtros nas consultas são efetivamente cláusulas do Guard que são usadas como critérios de seleção. A seguir está a estrutura de uma cláusula.

```
 <query> <operator> [query|value literal] [message] [or|OR]
```

Lembre-se dos seguintes pontos-chave [AWS CloudFormation Guard Regras de redação](writing-rules.md) ao trabalhar com filtros:
+ Combine cláusulas usando a [Forma Normal Conjuntiva (CNF](https://en.wikipedia.org/wiki/Conjunctive_normal_form)).
+ Especifique cada cláusula de conjunção (`and`) em uma nova linha.
+ Especifique disjunções (`or`) usando a `or` palavra-chave entre duas cláusulas.

O exemplo a seguir demonstra as cláusulas conjuntivas e disjuntivas.

```
resourceType == 'AWS::EC2::SecurityGroup'
InputParameters.TcpBlockedPorts not empty 

InputParameters.TcpBlockedPorts[*] {
    this in r(100, 400] or 
    this in r(4000, 65535]
}
```

### Usando cláusulas para critérios de seleção
<a name="selection-criteria"></a>

Você pode aplicar a filtragem a qualquer coleção. A filtragem pode ser aplicada diretamente em atributos na entrada que já são como `securityGroups: [....]` uma coleção. Você também pode aplicar a filtragem em uma consulta, que é sempre uma coleção de valores. Você pode usar todos os recursos das cláusulas, incluindo a forma normal conjuntiva, para filtragem.

A consulta comum a seguir é frequentemente usada ao selecionar recursos por tipo em um CloudFormation modelo.

```
Resources.*[ Type == 'AWS::IAM::Role' ]
```

A consulta `Resources.*` retorna todos os valores presentes na `Resources` seção da entrada. Para o exemplo de entrada do modelo em[Definindo consultas](#defining-queries), a consulta retorna o seguinte.

```
- Type: AWS::IAM::Role
  ...
- Type: AWS::EC2::Instance
  ...
- Type: AWS::EC2::VPC
  ...
- Type: AWS::EC2::Subnet
  ...
- Type: AWS::EC2::Subnet
  ...
```

Agora, aplique o filtro nessa coleção. O critério de correspondência é`Type == AWS::IAM::Role`. A seguir está a saída da consulta após a aplicação do filtro.

```
- Type: AWS::IAM::Role
  ...
```

Em seguida, verifique várias cláusulas para obter `AWS::IAM::Role` recursos.

```
let all_resources = Resources.*
let all_iam_roles = %all_resources[ Type == 'AWS::IAM::Role' ]
```

Veja a seguir um exemplo de consulta de filtragem que seleciona todos `AWS::IAM::Policy` os `AWS::IAM::ManagedPolicy` recursos.

```
Resources.*[
    Type in [ /IAM::Policy/,
              /IAM::ManagedPolicy/ ]
]
```

O exemplo a seguir verifica se esses recursos de política têm um `PolicyDocument` especificado.

```
Resources.*[ 
    Type in [ /IAM::Policy/,
              /IAM::ManagedPolicy/ ]
    Properties.PolicyDocument exists
]
```

### Criando necessidades de filtragem mais complexas
<a name="complex-filtering"></a>

Considere o exemplo a seguir de um item de AWS Config configuração para informações de grupos de segurança de entrada e saída.

```
---
resourceType: 'AWS::EC2::SecurityGroup'
configuration:
  ipPermissions:
    - fromPort: 172
      ipProtocol: tcp
      toPort: 172
      ipv4Ranges:
        - cidrIp: 10.0.0.0/24
        - cidrIp: 0.0.0.0/0
    - fromPort: 89
      ipProtocol: tcp
      ipv6Ranges:
        - cidrIpv6: '::/0'
      toPort: 189
      userIdGroupPairs: []
      ipv4Ranges:
        - cidrIp: 1.1.1.1/32
    - fromPort: 89
      ipProtocol: '-1'
      toPort: 189
      userIdGroupPairs: []
      ipv4Ranges:
        - cidrIp: 1.1.1.1/32
  ipPermissionsEgress:
    - ipProtocol: '-1'
      ipv6Ranges: []
      prefixListIds: []
      userIdGroupPairs: []
      ipv4Ranges:
        - cidrIp: 0.0.0.0/0
      ipRanges:
        - 0.0.0.0/0
  tags:
    - key: Name
      value: good-sg-delete-me
  vpcId: vpc-0123abcd
InputParameter:
  TcpBlockedPorts:
    - 3389
    - 20
    - 21
    - 110
    - 143
```

Observe o seguinte:
+ `ipPermissions`(regras de entrada) é uma coleção de regras dentro de um bloco de configuração.
+ Cada estrutura de regra contém atributos como `ipv4Ranges` e `ipv6Ranges` para especificar uma coleção de blocos CIDR.

Vamos escrever uma regra que seleciona todas as regras de entrada que permitem conexões de qualquer endereço IP e verifica se as regras não permitem que portas bloqueadas por TCP sejam expostas.

Comece com a parte da consulta que abrange IPv4, conforme mostrado no exemplo a seguir.

```
configuration.ipPermissions[
    #
    # at least one ipv4Ranges equals ANY IPv4
    #
    some ipv4Ranges[*].cidrIp == '0.0.0.0/0'
]
```

A `some` palavra-chave é útil nesse contexto. Todas as consultas retornam uma coleção de valores que correspondem à consulta. Por padrão, o Guard avalia se todos os valores retornados como resultado da consulta são comparados com as verificações. No entanto, esse comportamento nem sempre é o que você precisa para verificações. Considere a seguinte parte da entrada do item de configuração.

```
ipv4Ranges: 
  - cidrIp: 10.0.0.0/24
  - cidrIp: 0.0.0.0/0 # any IP allowed
```

Há dois valores presentes para`ipv4Ranges`. Nem todos os `ipv4Ranges` valores são iguais a um endereço IP indicado por. `0.0.0.0/0` Você quer ver se pelo menos um valor corresponde`0.0.0.0/0`. Você diz ao Guard que nem todos os resultados retornados de uma consulta precisam corresponder, mas pelo menos um resultado deve corresponder. A `some` palavra-chave diz ao Guard que garanta que um ou mais valores da consulta resultante correspondam à verificação. Se nenhum valor do resultado da consulta corresponder, o Guard gerará um erro.

Em seguida, adicione IPv6, conforme mostrado no exemplo a seguir.

```
configuration.ipPermissions[
    #
    # at-least-one ipv4Ranges equals ANY IPv4
    #
    some ipv4Ranges[*].cidrIp == '0.0.0.0/0' or
    #
    # at-least-one ipv6Ranges contains ANY IPv6
    #    
    some ipv6Ranges[*].cidrIpv6 == '::/0'
]
```

Por fim, no exemplo a seguir, confirme se o protocolo não `udp` é.

```
configuration.ipPermissions[
    #
    # at-least-one ipv4Ranges equals ANY IPv4
    #
    some ipv4Ranges[*].cidrIp == '0.0.0.0/0' or
    #
    # at-least-one ipv6Ranges contains ANY IPv6
    #    
    some ipv6Ranges[*].cidrIpv6 == '::/0'
    
    #
    # and ipProtocol is not udp
    #
    ipProtocol != 'udp' ] 
]
```

A seguir está a regra completa.

```
rule any_ip_ingress_checks
{

    let ports = InputParameter.TcpBlockedPorts[*]

    let targets = configuration.ipPermissions[
        #
        # if either ipv4 or ipv6 that allows access from any address
        #
        some ipv4Ranges[*].cidrIp == '0.0.0.0/0' or
        some ipv6Ranges[*].cidrIpv6 == '::/0'

        #
        # the ipProtocol is not UDP
        #
        ipProtocol != 'udp' ]
        
    when %targets !empty
    {
        %targets {
            ipProtocol != '-1'
            <<
              result: NON_COMPLIANT
              check_id: HUB_ID_2334
              message: Any IP Protocol is allowed
            >>

            when fromPort exists 
                 toPort exists 
            {
                let each_target = this
                %ports {
                    this < %each_target.fromPort or
                    this > %each_target.toPort
                    <<
                        result: NON_COMPLIANT
                        check_id: HUB_ID_2340
                        message: Blocked TCP port was allowed in range
                    >>
                }
            }

        }       
     }
}
```

### Separando coleções com base em seus tipos contidos
<a name="splitting-collection"></a>

Ao usar modelos de configuração de infraestrutura como código (IaC), você pode encontrar uma coleção que contém referências a outras entidades dentro do modelo de configuração. Veja a seguir um exemplo de CloudFormation modelo que descreve as tarefas do Amazon Elastic Container Service (Amazon ECS) com uma referência local, uma referência `TaskRoleArn` a e uma referência `TaskArn` direta de string.

```
Parameters:
  TaskArn:
    Type: String
Resources:
  ecsTask:
    Type: 'AWS::ECS::TaskDefinition'
    Metadata:
      SharedExectionRole: allowed
    Properties:
      TaskRoleArn: 'arn:aws:....'
      ExecutionRoleArn: 'arn:aws:...'
  ecsTask2:
    Type: 'AWS::ECS::TaskDefinition'
    Metadata:
      SharedExectionRole: allowed
    Properties:
      TaskRoleArn:
        'Fn::GetAtt':
          - iamRole
          - Arn
      ExecutionRoleArn: 'arn:aws:...2'
  ecsTask3:
    Type: 'AWS::ECS::TaskDefinition'
    Metadata:
      SharedExectionRole: allowed
    Properties:
      TaskRoleArn:
        Ref: TaskArn
      ExecutionRoleArn: 'arn:aws:...2'
  iamRole:
    Type: 'AWS::IAM::Role'
    Properties:
      PermissionsBoundary: 'arn:aws:...3'
```

Considere a seguinte consulta.

```
let ecs_tasks = Resources.*[ Type == 'AWS::ECS::TaskDefinition' ]
```

Essa consulta retorna uma coleção de valores que contém todos os três `AWS::ECS::TaskDefinition` recursos mostrados no modelo de exemplo. Separe `ecs_tasks` os que contêm referências `TaskRoleArn` locais dos outros, conforme mostrado no exemplo a seguir.

```
let ecs_tasks = Resources.*[ Type == 'AWS::ECS::TaskDefinition' ]

let ecs_tasks_role_direct_strings = %ecs_tasks[ 
    Properties.TaskRoleArn is_string ]

let ecs_tasks_param_reference = %ecs_tasks[
    Properties.TaskRoleArn.'Ref' exists ]

rule task_role_from_parameter_or_string {
    %ecs_tasks_role_direct_strings !empty or
    %ecs_tasks_param_reference !empty
}

rule disallow_non_local_references {
    # Known issue for rule access: Custom message must start on the same line
    not task_role_from_parameter_or_string 
    <<
        result: NON_COMPLIANT
        message: Task roles are not local to stack definition
    >>
}
```

# Atribuição e referência de variáveis nas regras do Guard
<a name="variables"></a>

Você pode atribuir variáveis em seus arquivos de AWS CloudFormation Guard regras para armazenar informações que você deseja referenciar nas regras do Guard. O Guard suporta a atribuição de variáveis com um único disparo. As variáveis são avaliadas lentamente, o que significa que o Guard só avalia as variáveis quando as regras são executadas.

**Topics**
+ [Atribuição de variáveis](#assigning-variables)
+ [Variáveis de referência](#referencing-variables)
+ [Escopo da variável](#variable-scope)
+ [Exemplos de variáveis nos arquivos de regras do Guard](#variables-examples)

## Atribuição de variáveis
<a name="assigning-variables"></a>

Use a `let` palavra-chave para inicializar e atribuir uma variável. Como prática recomendada, use snake case para nomes de variáveis. As variáveis podem armazenar literais estáticos ou propriedades dinâmicas resultantes de consultas. No exemplo a seguir, a variável `ecs_task_definition_task_role_arn` armazena o valor da string estática`arn:aws:iam:123456789012:role/my-role-name`.

```
let ecs_task_definition_task_role_arn = 'arn:aws:iam::123456789012:role/my-role-name'
```

No exemplo a seguir, a variável `ecs_tasks` armazena os resultados de uma consulta que pesquisa todos os `AWS::ECS::TaskDefinition` recursos em um CloudFormation modelo. Você pode consultar `ecs_tasks` para acessar informações sobre esses recursos ao escrever regras.

```
let ecs_tasks = Resources.*[
    Type == 'AWS::ECS::TaskDefinition'
]
```

## Variáveis de referência
<a name="referencing-variables"></a>

Use o `%` prefixo para referenciar uma variável.

Com base no exemplo da `ecs_task_definition_task_role_arn` variável em[Atribuição de variáveis](#assigning-variables), você pode fazer referência `ecs_task_definition_task_role_arn` na `query|value literal` seção de uma cláusula de regra do Guard. O uso dessa referência garante que o valor especificado para a `TaskDefinitionArn` propriedade de qualquer `AWS::ECS::TaskDefinition` recurso em um CloudFormation modelo seja o valor da string estática`arn:aws:iam:123456789012:role/my-role-name`.

```
Resources.*.Properties.TaskDefinitionArn == %ecs_task_definition_role_arn
```

Com base no exemplo da `ecs_tasks` variável em[Atribuição de variáveis](#assigning-variables), você pode fazer referência `ecs_tasks` em uma consulta (por exemplo, %ECS\$1tasks.properties). Primeiro, o Guard avalia a variável `ecs_tasks` e depois usa os valores retornados para percorrer a hierarquia. Se a variável for `ecs_tasks` resolvida para valores que não sejam de string, o Guard gerará um erro.

**nota**  
Atualmente, o Guard não oferece suporte a variáveis de referência em mensagens de erro personalizadas.

## Escopo da variável
<a name="variable-scope"></a>

O escopo se refere à visibilidade das variáveis definidas em um arquivo de regras. Um nome de variável só pode ser usado uma vez dentro de um escopo. Há três níveis em que uma variável pode ser declarada ou três escopos de variáveis possíveis:
+ **Nível de arquivo** — Normalmente declaradas na parte superior do arquivo de regras, você pode usar variáveis em nível de arquivo em todas as regras do arquivo de regras. Eles são visíveis em todo o arquivo.

  No arquivo de regras de exemplo a seguir, as variáveis `ecs_task_definition_task_role_arn` e `ecs_task_definition_execution_role_arn` são inicializadas no nível do arquivo.

  ```
  let ecs_task_definition_task_role_arn = 'arn:aws:iam::123456789012:role/my-task-role-name'
  let ecs_task_definition_execution_role_arn = 'arn:aws:iam::123456789012:role/my-execution-role-name'
  
  rule check_ecs_task_definition_task_role_arn
  {
      Resources.*.Properties.TaskRoleArn == %ecs_task_definition_task_role_arn
  }
  
  rule check_ecs_task_definition_execution_role_arn
  {
      Resources.*.Properties.ExecutionRoleArn == %ecs_task_definition_execution_role_arn
  }
  ```
+ **Nível de regra** — Declaradas em uma regra, as variáveis de nível de regra só são visíveis para essa regra específica. Qualquer referência fora da regra resultará em um erro.

  No arquivo de regras de exemplo a seguir, as variáveis `ecs_task_definition_task_role_arn` e `ecs_task_definition_execution_role_arn` são inicializadas no nível da regra. O só `ecs_task_definition_task_role_arn` pode ser referenciado dentro da regra `check_ecs_task_definition_task_role_arn` nomeada. Você só pode referenciar a `ecs_task_definition_execution_role_arn` variável dentro da regra `check_ecs_task_definition_execution_role_arn` nomeada.

  ```
  rule check_ecs_task_definition_task_role_arn
  {
      let ecs_task_definition_task_role_arn = 'arn:aws:iam::123456789012:role/my-task-role-name'
      Resources.*.Properties.TaskRoleArn == %ecs_task_definition_task_role_arn
  }
  
  rule check_ecs_task_definition_execution_role_arn
  {
      let ecs_task_definition_execution_role_arn = 'arn:aws:iam::123456789012:role/my-execution-role-name'
      Resources.*.Properties.ExecutionRoleArn == %ecs_task_definition_execution_role_arn
  }
  ```
+ **Nível do bloco** — Declaradas dentro de um bloco, como uma `when` cláusula, as variáveis do nível do bloco só são visíveis para aquele bloco específico. Qualquer referência fora do bloco resultará em um erro.

  No arquivo de regras de exemplo a seguir, as variáveis `ecs_task_definition_task_role_arn` e `ecs_task_definition_execution_role_arn` são inicializadas no nível do bloco dentro do `AWS::ECS::TaskDefinition` bloco de tipos. Você só pode referenciar as `ecs_task_definition_execution_role_arn` variáveis `ecs_task_definition_task_role_arn` e dentro dos blocos `AWS::ECS::TaskDefinition` de tipos para suas respectivas regras.

  ```
  rule check_ecs_task_definition_task_role_arn
  {
      AWS::ECS::TaskDefinition
      {
          let ecs_task_definition_task_role_arn = 'arn:aws:iam::123456789012:role/my-task-role-name'
          Properties.TaskRoleArn == %ecs_task_definition_task_role_arn
      }
  }
  
  rule check_ecs_task_definition_execution_role_arn
  {
      AWS::ECS::TaskDefinition
      {
          let ecs_task_definition_execution_role_arn = 'arn:aws:iam::123456789012:role/my-execution-role-name'
          Properties.ExecutionRoleArn == %ecs_task_definition_execution_role_arn
      }
  }
  ```

## Exemplos de variáveis nos arquivos de regras do Guard
<a name="variables-examples"></a>

As seções a seguir fornecem exemplos de atribuição estática e dinâmica de variáveis.

### Atribuição estática
<a name="assigning-static-variables"></a>

Veja a seguir um exemplo CloudFormation de modelo.

```
Resources:
  EcsTask:
    Type: 'AWS::ECS::TaskDefinition'
    Properties:
      TaskRoleArn: 'arn:aws:iam::123456789012:role/my-role-name'
```

Com base nesse modelo, você pode escrever uma regra chamada `check_ecs_task_definition_task_role_arn` que garante que a `TaskRoleArn` propriedade de todos os recursos do `AWS::ECS::TaskDefinition` modelo seja`arn:aws:iam::123456789012:role/my-role-name`.

```
rule check_ecs_task_definition_task_role_arn
{
    let ecs_task_definition_task_role_arn = 'arn:aws:iam::123456789012:role/my-role-name'
    Resources.*.Properties.TaskRoleArn == %ecs_task_definition_task_role_arn
}
```

Dentro do escopo da regra, você pode inicializar uma variável chamada `ecs_task_definition_task_role_arn` e atribuir a ela o valor `'arn:aws:iam::123456789012:role/my-role-name'` da string estática. A cláusula de regra verifica se o valor especificado para a `TaskRoleArn` propriedade do `EcsTask` recurso é `arn:aws:iam::123456789012:role/my-role-name` referenciando a `ecs_task_definition_task_role_arn` variável na `query|value literal` seção.

### Atribuição dinâmica
<a name="example-dynamic-assignment"></a>

Veja a seguir um exemplo CloudFormation de modelo.

```
Resources:
  EcsTask:
    Type: 'AWS::ECS::TaskDefinition'
    Properties:
      TaskRoleArn: 'arn:aws:iam::123456789012:role/my-role-name'
```

Com base nesse modelo, você pode inicializar uma variável chamada `ecs_tasks` dentro do escopo do arquivo e atribuir a ela a consulta`Resources.*[ Type == 'AWS::ECS::TaskDefinition'`. O Guard consulta todos os recursos no modelo de entrada e armazena informações sobre eles em`ecs_tasks`. Você também pode escrever uma regra chamada `check_ecs_task_definition_task_role_arn` que garanta que a `TaskRoleArn` propriedade de todos os recursos do `AWS::ECS::TaskDefinition` modelo seja `arn:aws:iam::123456789012:role/my-role-name`

```
let ecs_tasks = Resources.*[
    Type == 'AWS::ECS::TaskDefinition'
]

rule check_ecs_task_definition_task_role_arn
{
    %ecs_tasks.Properties.TaskRoleArn == 'arn:aws:iam::123456789012:role/my-role-name'
}
```

A cláusula de regra verifica se o valor especificado para a `TaskRoleArn` propriedade do `EcsTask` recurso é `arn:aws:iam::123456789012:role/my-role-name` referenciando a `ecs_task_definition_task_role_arn` variável na `query` seção.

### Impondo a configuração CloudFormation do modelo
<a name="example-3"></a>

Vamos dar uma olhada em um exemplo mais complexo de um caso de uso de produção. Neste exemplo, escrevemos regras do Guard para garantir controles mais rígidos sobre como as tarefas do Amazon ECS são definidas.

Veja a seguir um exemplo CloudFormation de modelo.

```
Resources:
  EcsTask:
    Type: 'AWS::ECS::TaskDefinition'
    Properties:
      TaskRoleArn: 
        'Fn::GetAtt': [TaskIamRole, Arn]
      ExecutionRoleArn:
        'Fn::GetAtt': [ExecutionIamRole, Arn]

  TaskIamRole:
    Type: 'AWS::IAM::Role'
    Properties:
      PermissionsBoundary: 'arn:aws:iam::123456789012:policy/MyExamplePolicy'

  ExecutionIamRole:
    Type: 'AWS::IAM::Role'
    Properties:
      PermissionsBoundary: 'arn:aws:iam::123456789012:policy/MyExamplePolicy'
```

Com base nesse modelo, escrevemos as seguintes regras para garantir que esses requisitos sejam atendidos:
+ Cada `AWS::ECS::TaskDefinition` recurso no modelo tem uma função de tarefa e uma função de execução anexadas.
+ As funções de tarefa e as funções de execução são funções AWS Identity and Access Management (IAM).
+ As funções são definidas no modelo.
+ A `PermissionsBoundary` propriedade é especificada para cada função.

```
# Select all Amazon ECS task definition resources from the template
let ecs_tasks = Resources.*[
    Type == 'AWS::ECS::TaskDefinition'
]

# Select a subset of task definitions whose specified value for the TaskRoleArn property is an Fn::Gett-retrievable attribute
let task_role_refs = some %ecs_tasks.Properties.TaskRoleArn.'Fn::GetAtt'[0]

# Select a subset of TaskDefinitions whose specified value for the ExecutionRoleArn property is an Fn::Gett-retrievable attribute
let execution_role_refs = some %ecs_tasks.Properties.ExecutionRoleArn.'Fn::GetAtt'[0]

# Verify requirement #1
rule all_ecs_tasks_must_have_task_end_execution_roles 
    when %ecs_tasks !empty 
{
    %ecs_tasks.Properties {
        TaskRoleArn exists
        ExecutionRoleArn exists
    }
}

# Verify requirements #2 and #3
rule all_roles_are_local_and_type_IAM
    when all_ecs_tasks_must_have_task_end_execution_roles
{
    let task_iam_references = Resources.%task_role_refs
    let execution_iam_reference = Resources.%execution_role_refs

    when %task_iam_references !empty {
        %task_iam_references.Type == 'AWS::IAM::Role'
    }

    when %execution_iam_reference !empty {
        %execution_iam_reference.Type == 'AWS::IAM::Role'
    }
}

# Verify requirement #4
rule check_role_have_permissions_boundary
    when all_ecs_tasks_must_have_task_end_execution_roles
{
    let task_iam_references = Resources.%task_role_refs
    let execution_iam_reference = Resources.%execution_role_refs

    when %task_iam_references !empty {
        %task_iam_references.Properties.PermissionsBoundary exists
    }

    when %execution_iam_reference !empty {
        %execution_iam_reference.Properties.PermissionsBoundary exists
    }
}
```

# Composição de blocos de regras nomeadas em AWS CloudFormation Guard
<a name="named-rule-block-composition"></a>

Ao escrever blocos de regras nomeadas usando AWS CloudFormation Guard, você pode usar os dois estilos de composição a seguir:
+ Dependência condicional
+ Dependência correlacional

Usar qualquer um desses estilos de composição de dependências ajuda a promover a reutilização e reduz a verbosidade e a repetição em blocos de regras nomeadas.

**Topics**
+ [Pré-requisitos](#named-rules-prerequisites)
+ [Composição de dependência condicional](#named-rules-conditional-dependency)
+ [Composição de dependência correlacional](#named-rules-correlational-dependency)

## Pré-requisitos
<a name="named-rules-prerequisites"></a>

Saiba mais sobre blocos de regras nomeadas em Como [escrever](writing-rules.md#named-rule-blocks) regras.

## Composição de dependência condicional
<a name="named-rules-conditional-dependency"></a>

Nesse estilo de composição, a avaliação de um `when` bloco ou bloco de regras nomeadas depende condicionalmente do resultado da avaliação de um ou mais outros blocos ou cláusulas de regras nomeadas. O exemplo de arquivo de regras do Guard a seguir contém blocos de regras nomeadas que demonstram dependências condicionais.

```
# Named-rule block, rule_name_A
rule rule_name_A {
    Guard_rule_1
    Guard_rule_2
    ...
}

# Example-1, Named-rule block, rule_name_B, takes a conditional dependency on rule_name_A
rule rule_name_B when rule_name_A {
    Guard_rule_3
    Guard_rule_4
    ...
}

# Example-2, when block takes a conditional dependency on rule_name_A
when rule_name_A {
    Guard_rule_3
    Guard_rule_4
    ...
}

# Example-3, Named-rule block, rule_name_C, takes a conditional dependency on rule_name_A ^ rule_name_B
rule rule_name_C when rule_name_A
                      rule_name_B {
    Guard_rule_3
    Guard_rule_4
    ...
}

# Example-4, Named-rule block, rule_name_D, takes a conditional dependency on (rule_name_A v clause_A) ^ clause_B ^ rule_name_B
rule rule_name_D when rule_name_A OR
                      clause_A
                      clause_B
                      rule_name_B {
    Guard_rule_3
    Guard_rule_4
    ...
}
```

No arquivo de regras de exemplo anterior, `Example-1` tem os seguintes resultados possíveis:
+ Se for `rule_name_A` avaliado como`PASS`, as regras do Guard encapsuladas por `rule_name_B` serão avaliadas.
+ Se for `rule_name_A` avaliado como`FAIL`, as regras do Guard encapsuladas por não `rule_name_B` serão avaliadas. `rule_name_B`avalia a. `SKIP`
+ Se for `rule_name_A` avaliado como`SKIP`, as regras do Guard encapsuladas por não `rule_name_B` serão avaliadas. `rule_name_B`avalia a. `SKIP`
**nota**  
Esse caso acontece se depender `rule_name_A` condicionalmente de uma regra que avalia `FAIL` e resulta na `rule_name_A` avaliação a. `SKIP`

Veja a seguir um exemplo de um item de configuração do banco de dados de gerenciamento de configuração (CMDB) de um AWS Config item para informações de grupos de segurança de entrada e saída. Este exemplo demonstra a composição da dependência condicional.

```
rule check_resource_type_and_parameter {
    resourceType == /AWS::EC2::SecurityGroup/
    InputParameters.TcpBlockedPorts NOT EMPTY 
}

rule check_parameter_validity when check_resource_type_and_parameter {
    InputParameters.TcpBlockedPorts[*] {
        this in r[0,65535] 
    }
}

rule check_ip_procotol_and_port_range_validity when check_parameter_validity {
    let ports = InputParameters.TcpBlockedPorts[*]

    # 
    # select all ipPermission instances that can be reached by ANY IP address
    # IPv4 or IPv6 and not UDP
    #
    let configuration = configuration.ipPermissions[ 
        some ipv4Ranges[*].cidrIp == "0.0.0.0/0" or
        some ipv6Ranges[*].cidrIpv6 == "::/0"
        ipProtocol != 'udp' ] 
    when %configuration !empty {
        %configuration {
            ipProtocol != '-1'

            when fromPort exists 
                toPort exists {
                let ip_perm_block = this
                %ports {
                    this < %ip_perm_block.fromPort or
                    this > %ip_perm_block.toPort
                }
            }
        }
    }
}
```

No exemplo anterior, `check_parameter_validity` depende condicionalmente `check_resource_type_and_parameter` e depende `check_ip_procotol_and_port_range_validity` condicionalmente de. `check_parameter_validity` A seguir está um item de configuração do banco de dados de gerenciamento de configuração (CMDB) que está em conformidade com as regras anteriores.

```
---
version: '1.3'
resourceType: 'AWS::EC2::SecurityGroup'
resourceId: sg-12345678abcdefghi
configuration:
  description: Delete-me-after-testing
  groupName: good-sg-test-delete-me
  ipPermissions:
    - fromPort: 172
      ipProtocol: tcp
      ipv6Ranges: []
      prefixListIds: []
      toPort: 172
      userIdGroupPairs: []
      ipv4Ranges:
        - cidrIp: 0.0.0.0/0
      ipRanges:
        - 0.0.0.0/0
    - fromPort: 89
      ipProtocol: tcp
      ipv6Ranges:
        - cidrIpv6: '::/0'
      prefixListIds: []
      toPort: 89
      userIdGroupPairs: []
      ipv4Ranges:
        - cidrIp: 0.0.0.0/0
      ipRanges:
        - 0.0.0.0/0
  ipPermissionsEgress:
    - ipProtocol: '-1'
      ipv6Ranges: []
      prefixListIds: []
      userIdGroupPairs: []
      ipv4Ranges:
        - cidrIp: 0.0.0.0/0
      ipRanges:
        - 0.0.0.0/0
  tags:
    - key: Name
      value: good-sg-delete-me
  vpcId: vpc-0123abcd
InputParameters:
  TcpBlockedPorts:
    - 3389
    - 20
    - 110
    - 142
    - 1434
    - 5500
supplementaryConfiguration: {}
resourceTransitionStatus: None
```

## Composição de dependência correlacional
<a name="named-rules-correlational-dependency"></a>

Nesse estilo de composição, a avaliação de um `when` bloco ou bloco de regras nomeadas tem uma dependência correlacional do resultado da avaliação de uma ou mais outras regras do Guard. A dependência correlacional pode ser alcançada da seguinte forma.

```
# Named-rule block, rule_name_A, takes a correlational dependency on all of the Guard rules encapsulated by the named-rule block
rule rule_name_A {
    Guard_rule_1
    Guard_rule_2
    ...
}

# when block takes a correlational dependency on all of the Guard rules encapsulated by the when block
when condition {
    Guard_rule_1
    Guard_rule_2
    ...
}
```

Para ajudá-lo a entender a composição de dependências correlacionais, revise o exemplo a seguir de um arquivo de regras do Guard.

```
#
# Allowed valid protocols for AWS::ElasticLoadBalancingV2::Listener resources
#
let allowed_protocols = [ "HTTPS", "TLS" ]

let elbs = Resources.*[ Type == 'AWS::ElasticLoadBalancingV2::Listener' ]

#
# If there are AWS::ElasticLoadBalancingV2::Listener resources present, ensure that they have protocols specified from the 
# list of allowed protocols and that the Certificates property is not empty
#
rule ensure_all_elbs_are_secure when %elbs !empty {
    %elbs.Properties {
        Protocol in %allowed_protocols
        Certificates !empty
    }
}

# 
# In addition to secure settings, ensure that AWS::ElasticLoadBalancingV2::Listener resources are private
#
rule ensure_elbs_are_internal_and_secure when %elbs !empty {
    ensure_all_elbs_are_secure
    %elbs.Properties.Scheme == 'internal'
}
```

No arquivo de regras anterior, `ensure_elbs_are_internal_and_secure` tem uma dependência correlacional de. `ensure_all_elbs_are_secure` Veja a seguir um exemplo de CloudFormation modelo que está em conformidade com as regras anteriores.

```
Resources:
  ServiceLBPublicListener46709EAA:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      Scheme: internal
      Protocol: HTTPS
      Certificates:
        - CertificateArn: 'arn:aws:acm...'
  ServiceLBPublicListener4670GGG:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      Scheme: internal
      Protocol: HTTPS
      Certificates:
        - CertificateArn: 'arn:aws:acm...'
```

# Escrevendo cláusulas para realizar avaliações contextuais
<a name="context-aware-evaluations"></a>

AWS CloudFormation Guard as cláusulas são avaliadas em relação aos dados hierárquicos. O mecanismo de avaliação do Guard resolve consultas em relação aos dados recebidos seguindo os dados hierárquicos conforme especificado, usando uma notação pontilhada simples. Freqüentemente, várias cláusulas são necessárias para avaliar em relação a um mapa de dados ou a uma coleção. O Guard fornece uma sintaxe conveniente para escrever essas cláusulas. O mecanismo está ciente do contexto e usa os dados correspondentes associados às avaliações.

Veja a seguir um exemplo de uma configuração do Kubernetes Pod com contêineres, na qual você pode aplicar avaliações contextuais.

```
apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
    - name: app
      image: 'images.my-company.example/app:v4'
      resources:
        requests:
          memory: 64Mi
          cpu: 0.25
        limits:
          memory: 128Mi
          cpu: 0.5
    - name: log-aggregator
      image: 'images.my-company.example/log-aggregator:v6'
      resources:
        requests:
          memory: 64Mi
          cpu: 0.25
        limits:
          memory: 128Mi
          cpu: 0.75
```

Você pode criar cláusulas do Guard para avaliar esses dados. Ao avaliar um arquivo de regras, o contexto é todo o documento de entrada. Veja a seguir exemplos de cláusulas que validam a aplicação de limites para contêineres especificados em um pod.

```
#
# At this level, the root document is available for evaluation
#

#
# Our rule only evaluates for apiVersion == v1 and K8s kind is Pod
#
rule ensure_container_limits_are_enforced
    when apiVersion == 'v1'
        kind == 'Pod' 
{
    spec.containers[*] {
        resources.limits {
            #
            # Ensure that cpu attribute is set
            #
            cpu exists
            <<
                Id: K8S_REC_18
                Description: CPU limit must be set for the container
            >> 

            #
            # Ensure that memory attribute is set
            #
            memory exists
            <<
                Id: K8S_REC_22
                Description: Memory limit must be set for the container
            >>
        }
    }
}
```

## Compreensão `context` nas avaliações
<a name="context"></a>

No nível do bloco de regras, o contexto de entrada é o documento completo. As avaliações da `when` condição ocorrem nesse contexto raiz de entrada em que os `kind` atributos `apiVersion` e estão localizados. No exemplo anterior, essas condições são avaliadas como`true`.

Agora, percorra a hierarquia `spec.containers[*]` mostrada no exemplo anterior. Para cada travessia da hierarquia, o valor do contexto muda de acordo. Depois que a travessia do `spec` bloco é concluída, o contexto muda, conforme mostrado no exemplo a seguir.

```
containers:
  - name: app
    image: 'images.my-company.example/app:v4'
    resources:
      requests:
        memory: 64Mi
        cpu: 0.25
      limits:
        memory: 128Mi
        cpu: 0.5
  - name: log-aggregator
    image: 'images.my-company.example/log-aggregator:v6'
    resources:
      requests:
        memory: 64Mi
        cpu: 0.25
      limits:
        memory: 128Mi
        cpu: 0.75
```

Depois de percorrer o `containers` atributo, o contexto é mostrado no exemplo a seguir.

```
- name: app
  image: 'images.my-company.example/app:v4'
  resources:
    requests:
      memory: 64Mi
      cpu: 0.25
    limits:
      memory: 128Mi
      cpu: 0.5
- name: log-aggregator
  image: 'images.my-company.example/log-aggregator:v6'
  resources:
    requests:
      memory: 64Mi
      cpu: 0.25
    limits:
      memory: 128Mi
      cpu: 0.75
```

## Entendendo os loops
<a name="loops"></a>

Você pode usar a expressão `[*]` para definir um loop para todos os valores contidos na matriz do `containers` atributo. O bloco é avaliado para cada elemento interno`containers`. No trecho de regra do exemplo anterior, as cláusulas contidas no bloco definem as verificações a serem validadas em relação a uma definição de contêiner. O bloco de cláusulas contido nele é avaliado duas vezes, uma para cada definição de contêiner.

```
{
    spec.containers[*] {
       ...
    }
}
```

Para cada iteração, o valor do contexto é o valor no índice correspondente.

**nota**  
O único formato de acesso ao índice suportado é `[<integer>]` ou`[*]`. Atualmente, o Guard não suporta faixas como`[2..4]`.

## Matrizes
<a name="arrays"></a>

Geralmente, em locais onde uma matriz é aceita, valores únicos também são aceitos. Por exemplo, se houver apenas um contêiner, a matriz poderá ser descartada e a entrada a seguir será aceita.

```
apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
    name: app
    image: images.my-company.example/app:v4
    resources:
      requests:
        memory: "64Mi"
        cpu: 0.25
      limits:
        memory: "128Mi"
        cpu: 0.5
```

Se um atributo puder aceitar uma matriz, certifique-se de que sua regra use o formato de matriz. No exemplo anterior, você usa `containers[*]` e não`containers`. O Guard avalia corretamente ao percorrer os dados quando encontra somente o formulário de valor único.

**nota**  
Sempre use o formulário de matriz ao expressar acesso a uma cláusula de regra quando um atributo aceita uma matriz. O Guard avalia corretamente mesmo no caso de um único valor ser usado.

## Usando o formulário `spec.containers[*]` em vez de `spec.containers`
<a name="containers"></a>

As consultas de proteção retornam uma coleção de valores resolvidos. Quando você usa o formulário`spec.containers`, os valores resolvidos para a consulta contêm a matriz referida por`containers`, não os elementos dentro dela. Ao usar o formulário`spec.containers[*]`, você se refere a cada elemento individual contido. Lembre-se de usar o `[*]` formulário sempre que quiser avaliar cada elemento contido na matriz.

## Usando `this` para referenciar o valor do contexto atual
<a name="this"></a>

Ao criar uma regra do Guard, você pode referenciar o valor do contexto usando`this`. Muitas vezes, `this` está implícito porque está vinculado ao valor do contexto. Por exemplo,`this.apiVersion`,`this.kind`, e `this.spec` estão vinculados à raiz ou ao documento. Por outro lado, `this.resources` está vinculado a cada valor para`containers`, como `/spec/containers/0/` `/spec/containers/1` e. Da mesma forma, `this.cpu` e `this.memory` mapeie os limites, especificamente `/spec/containers/0/resources/limits` `/spec/containers/1/resources/limits` e. 

No próximo exemplo, a regra anterior para a configuração do Kubernetes Pod foi reescrita para ser usada explicitamente. `this`

```
rule ensure_container_limits_are_enforced
    when this.apiVersion == 'v1'
         this.kind == 'Pod' 
{
    this.spec.containers[*] {
        this.resources.limits {
            #
            # Ensure that cpu attribute is set
            #
            this.cpu exists
            <<
                Id: K8S_REC_18
                Description: CPU limit must be set for the container
            >> 

            #
            # Ensure that memory attribute is set
            #
            this.memory exists
            <<
                Id: K8S_REC_22
                Description: Memory limit must be set for the container
            >>
        }
    }
}
```

Você não precisa usar `this` explicitamente. No entanto, a `this` referência pode ser útil ao trabalhar com escalares, conforme mostrado no exemplo a seguir.

```
InputParameters.TcpBlockedPorts[*] {
    this in r[0, 65535) 
    <<
        result: NON_COMPLIANT
        message: TcpBlockedPort not in range (0, 65535)
    >>
}
```

No exemplo anterior, `this` é usado para se referir a cada número de porta.

## Possíveis erros com o uso de implícito `this`
<a name="common-errors"></a>

Ao criar regras e cláusulas, há alguns erros comuns ao referenciar elementos do valor de contexto implícito`this`. Por exemplo, considere o seguinte dado de entrada para avaliar (isso deve ser aprovado).

```
resourceType: 'AWS::EC2::SecurityGroup'
InputParameters:
  TcpBlockedPorts: [21, 22, 110]
configuration:
  ipPermissions:
  - fromPort: 172
    ipProtocol: tcp
    ipv6Ranges: []
    prefixListIds: []
    toPort: 172
    userIdGroupPairs: []
    ipv4Ranges:
      - cidrIp: "0.0.0.0/0"   
  - fromPort: 89
    ipProtocol: tcp
    ipv6Ranges:
      - cidrIpv6: "::/0"
    prefixListIds: []
    toPort: 109
    userIdGroupPairs: []
    ipv4Ranges:
      - cidrIp: 10.2.0.0/24
```

Quando testada em relação ao modelo anterior, a regra a seguir resulta em um erro porque faz uma suposição incorreta de aproveitar o implícito. `this`

```
rule check_ip_procotol_and_port_range_validity
{
    # 
    # select all ipPermission instances that can be reached by ANY IP address
    # IPv4 or IPv6 and not UDP
    #
    let any_ip_permissions = configuration.ipPermissions[ 
        some ipv4Ranges[*].cidrIp == "0.0.0.0/0" or
        some ipv6Ranges[*].cidrIpv6 == "::/0"

        ipProtocol != 'udp' ]
    
    when %any_ip_permissions !empty
    {
        %any_ip_permissions {
            ipProtocol != '-1' # this here refers to each ipPermission instance
            InputParameters.TcpBlockedPorts[*] {
                fromPort > this or 
                toPort   < this 
                <<
                    result: NON_COMPLIANT
                    message: Blocked TCP port was allowed in range
                >>
            }                
        }
    }
}
```

Para ver esse exemplo, salve o arquivo de regras anterior com o nome `any_ip_ingress_check.guard` e os dados com o nome `ip_ingress.yaml` do arquivo. Em seguida, execute o `validate` comando a seguir com esses arquivos.

```
cfn-guard validate -r any_ip_ingress_check.guard -d ip_ingress.yaml --show-clause-failures
```

Na saída a seguir, o mecanismo indica que sua tentativa de recuperar uma propriedade `InputParameters.TcpBlockedPorts[*]` no valor `/configuration/ipPermissions/0` `/configuration/ipPermissions/1` falhou.

```
Clause #2     FAIL(Block[Location[file:any_ip_ingress_check.guard, line:17, column:13]])

              Attempting to retrieve array index or key from map at Path = /configuration/ipPermissions/0, Type was not an array/object map, Remaining Query = InputParameters.TcpBlockedPorts[*]

Clause #3     FAIL(Block[Location[file:any_ip_ingress_check.guard, line:17, column:13]])

              Attempting to retrieve array index or key from map at Path = /configuration/ipPermissions/1, Type was not an array/object map, Remaining Query = InputParameters.TcpBlockedPorts[*]
```

Para ajudar a entender esse resultado, reescreva a regra usando referências `this` explícitas.

```
rule check_ip_procotol_and_port_range_validity
{
    # 
    # select all ipPermission instances that can be reached by ANY IP address
    # IPv4 or IPv6 and not UDP
    #
    let any_ip_permissions = this.configuration.ipPermissions[ 
        some ipv4Ranges[*].cidrIp == "0.0.0.0/0" or
        some ipv6Ranges[*].cidrIpv6 == "::/0"

        ipProtocol != 'udp' ]
    
    when %any_ip_permissions !empty
    {
        %any_ip_permissions {
            this.ipProtocol != '-1' # this here refers to each ipPermission instance
            this.InputParameters.TcpBlockedPorts[*] {
                this.fromPort > this or 
                this.toPort   < this 
                <<
                    result: NON_COMPLIANT
                    message: Blocked TCP port was allowed in range
                >>
            }                
        }
    }
}
```

`this.InputParameters`faz referência a cada valor contido na variável`any_ip_permissions`. A consulta atribuída à variável seleciona `configuration.ipPermissions` valores que correspondem. O erro indica uma tentativa de recuperação `InputParamaters` nesse contexto, mas `InputParameters` estava no contexto raiz.

O bloco interno também faz referência a variáveis que estão fora do escopo, conforme mostrado no exemplo a seguir.

```
{
    this.ipProtocol != '-1' # this here refers to each ipPermission instance
    this.InputParameter.TcpBlockedPorts[*] { # ERROR referencing InputParameter off /configuration/ipPermissions[*]
        this.fromPort > this or # ERROR: implicit this refers to values inside /InputParameter/TcpBlockedPorts[*]
        this.toPort   < this 
        <<
            result: NON_COMPLIANT
            message: Blocked TCP port was allowed in range
        >>
    }
}
```

`this`se refere a cada valor de porta em`[21, 22, 110]`, mas também se refere a `fromPort` `toPort` e. Ambos pertencem ao escopo do bloco externo.

### Resolvendo erros com o uso implícito de `this`
<a name="common-errors-resolution"></a>

Use variáveis para atribuir e referenciar valores explicitamente. Primeiro, `InputParameter.TcpBlockedPorts` faz parte do contexto de entrada (raiz). `InputParameter.TcpBlockedPorts`Saia do bloco interno e atribua-o explicitamente, conforme mostrado no exemplo a seguir.

```
rule check_ip_procotol_and_port_range_validity
{
     let ports = InputParameters.TcpBlockedPorts[*]
    # ... cut off for illustrating change
}
```

Em seguida, consulte essa variável explicitamente.

```
rule check_ip_procotol_and_port_range_validity
{
    #
    # Important: Assigning InputParameters.TcpBlockedPorts results in an ERROR. 
    # We need to extract each port inside the array. The difference is the query
    # InputParameters.TcpBlockedPorts returns [[21, 20, 110]] whereas the query 
    # InputParameters.TcpBlockedPorts[*] returns [21, 20, 110]. 
    #
    let ports = InputParameters.TcpBlockedPorts[*]

    # 
    # select all ipPermission instances that can be reached by ANY IP address
    # IPv4 or IPv6 and not UDP
    #
    let any_ip_permissions = configuration.ipPermissions[ 
        some ipv4Ranges[*].cidrIp == "0.0.0.0/0" or
        some ipv6Ranges[*].cidrIpv6 == "::/0"

        ipProtocol != 'udp' ]
    
    when %any_ip_permissions !empty
    {
        %any_ip_permissions {
            this.ipProtocol != '-1' # this here refers to each ipPermission instance
            %ports {
                this.fromPort > this or 
                this.toPort   < this 
                <<
                    result: NON_COMPLIANT
                    message: Blocked TCP port was allowed in range
                >>
            }
        }
    }        
}
```

Faça o mesmo com `this` as referências internas internas`%ports`.

No entanto, todos os erros ainda não foram corrigidos porque o loop interno `ports` ainda tem uma referência incorreta. O exemplo a seguir mostra a remoção da referência incorreta.

```
rule check_ip_procotol_and_port_range_validity
{
    #
    # Important: Assigning InputParameters.TcpBlockedPorts results in an ERROR. 
    # We need to extract each port inside the array. The difference is the query
    # InputParameters.TcpBlockedPorts returns [[21, 20, 110]] whereas the query 
    # InputParameters.TcpBlockedPorts[*] returns [21, 20, 110].
    #
    let ports = InputParameters.TcpBlockedPorts[*]

    # 
    # select all ipPermission instances that can be reached by ANY IP address
    # IPv4 or IPv6 and not UDP
    #
    let any_ip_permissions = configuration.ipPermissions[
        #
        # if either ipv4 or ipv6 that allows access from any address
        #
        some ipv4Ranges[*].cidrIp == '0.0.0.0/0' or
        some ipv6Ranges[*].cidrIpv6 == '::/0'

        #
        # the ipProtocol is not UDP
        #
        ipProtocol != 'udp' ]
        
    when %any_ip_permissions !empty
    {
        %any_ip_permissions {
            ipProtocol != '-1'
            <<
              result: NON_COMPLIANT
              check_id: HUB_ID_2334
              message: Any IP Protocol is allowed
            >>

            when fromPort exists 
                 toPort exists 
            {
                let each_any_ip_perm = this
                %ports {
                    this < %each_any_ip_perm.fromPort or
                    this > %each_any_ip_perm.toPort
                    <<
                        result: NON_COMPLIANT
                        check_id: HUB_ID_2340
                        message: Blocked TCP port was allowed in range
                    >>
                }
            }
        }       
    }   
}
```

Em seguida, execute o `validate` comando novamente. Desta vez, passa.

```
cfn-guard validate -r any_ip_ingress_check.guard -d ip_ingress.yaml --show-clause-failures
```

A seguir está a saída do `validate` comando.

```
ip_ingress.yaml Status = PASS
PASS rules
check_ip_procotol_and_port_range_validity    PASS
```

Para testar essa abordagem em busca de falhas, o exemplo a seguir usa uma alteração na carga útil.

```
resourceType: 'AWS::EC2::SecurityGroup'
InputParameters:
  TcpBlockedPorts: [21, 22, 90, 110]
configuration:
  ipPermissions:
    - fromPort: 172
      ipProtocol: tcp
      ipv6Ranges: []
      prefixListIds: []
      toPort: 172
      userIdGroupPairs: []
      ipv4Ranges:
        - cidrIp: "0.0.0.0/0"   
    - fromPort: 89
      ipProtocol: tcp
      ipv6Ranges:
        - cidrIpv6: "::/0"
      prefixListIds: []
      toPort: 109
      userIdGroupPairs: []
      ipv4Ranges:
        - cidrIp: 10.2.0.0/24
```

90 está dentro do intervalo de 89 a 109 que tem qualquer IPv6 endereço permitido. A seguir está a saída do `validate` comando depois de executá-lo novamente.

```
Clause #3           FAIL(Clause(Location[file:any_ip_ingress_check.guard, line:43, column:21], Check: _  LESS THAN %each_any_ip_perm.fromPort))
                    Comparing Int((Path("/InputParameters/TcpBlockedPorts/2"), 90)) with Int((Path("/configuration/ipPermissions/1/fromPort"), 89)) failed
                    (DEFAULT: NO_MESSAGE)
Clause #4           FAIL(Clause(Location[file:any_ip_ingress_check.guard, line:44, column:21], Check: _  GREATER THAN %each_any_ip_perm.toPort))
                    Comparing Int((Path("/InputParameters/TcpBlockedPorts/2"), 90)) with Int((Path("/configuration/ipPermissions/1/toPort"), 109)) failed

                                            result: NON_COMPLIANT
                                            check_id: HUB_ID_2340
                                            message: Blocked TCP port was allowed in range
```