

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

# AWS CloudFormation Guard Regole di scrittura
<a name="writing-rules"></a>

*In, le regole sono regole. AWS CloudFormation Guard* policy-as-code Scrivi regole nel linguaggio DSL (Domain-Specific Language) Guard in base alle quali puoi convalidare i tuoi dati in formato JSON o YAML. *Le regole sono costituite da clausole.*

È possibile salvare le regole scritte utilizzando Guard DSL in file di testo semplice che utilizzano qualsiasi estensione di file.

*È possibile creare più file di regole e classificarli come set di regole.* I set di regole consentono di convalidare i dati in formato JSON o YAML rispetto a più file di regole contemporaneamente.

**Topics**
+ [

## Clausole
](#clauses)
+ [

## Utilizzo di interrogazioni nelle clausole
](#clauses-queries)
+ [

## Utilizzo degli operatori nelle clausole
](#clauses-operators)
+ [

## Utilizzo di messaggi personalizzati nelle clausole
](#clauses-custom-messages)
+ [

## Combinazione di clausole
](#combining-clauses)
+ [

## Utilizzo di blocchi con regole Guard
](#blocks)
+ [

## Utilizzo delle funzioni integrate
](#built-in-functions)
+ [

# Definizione delle interrogazioni e del filtraggio di Guard
](query-and-filtering.md)
+ [

# Assegnazione e riferimento a variabili nelle regole di Guard
](variables.md)
+ [

# Composizione di blocchi con regole denominate in AWS CloudFormation Guard
](named-rule-block-composition.md)
+ [

# Scrittura di clausole per eseguire valutazioni basate sul contesto
](context-aware-evaluations.md)

## Clausole
<a name="clauses"></a>

Le clausole sono espressioni booleane che restituiscono true () o false ()`PASS`. `FAIL` Le clausole utilizzano operatori binari per confrontare due valori o operatori unari che operano su un singolo valore.

**Esempi di clausole unarie**

La seguente clausola unaria valuta se la raccolta è vuota. `TcpBlockedPorts`

```
InputParameters.TcpBlockedPorts not empty
```

La seguente clausola unaria valuta se la proprietà è una stringa. `ExecutionRoleArn`

```
Properties.ExecutionRoleArn is_string
```

**Esempi di clausole binarie**

La clausola binaria seguente valuta se la `BucketName` proprietà contiene la stringa`encrypted`, indipendentemente dal maiuscolo.

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

La clausola binaria seguente valuta se la `ReadCapacityUnits` proprietà è inferiore o uguale a 5.000.

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

### Sintassi per scrivere le clausole delle regole di Guard
<a name="clauses-syntax"></a>

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

### Proprietà delle clausole delle regole Guard
<a name="clauses-properties"></a>

`query`  <a name="clauses-properties-query"></a>
Un'espressione separata da punti (`.`) scritta per attraversare dati gerarchici. Le espressioni di query possono includere espressioni di filtro destinate a un sottoinsieme di valori. Le query possono essere assegnate alle variabili in modo da poterle scrivere una sola volta e fare riferimento ad esse altrove in un set di regole, il che consentirà di accedere ai risultati delle query.  
Per ulteriori informazioni sulla scrittura di interrogazioni e sui filtri, vedere. [Definizione di interrogazioni e filtri](query-and-filtering.md)  
 *Obbligatorio:* sì

`operator`  <a name="clauses-properties-operator"></a>
Un operatore unario o binario che consente di controllare lo stato della query. Il lato sinistro (LHS) di un operatore binario deve essere una query, mentre il lato destro (RHS) deve essere una query o un valore letterale.  
 *Operatori binari supportati*: `==` (Uguale) \$1 `!=` (Non uguale) \$1 `>` (Maggiore di) \$1 `>=` (Maggiore o uguale a) \$1 `<` (Minore di) \$1 `<=` (Minore o uguale a) \$1 `IN` (In un elenco in forma [x, y, z]  
 *Operatori unari supportati*: `exists` \$1 `empty` \$1 \$1 `is_string` \$1 `is_list` \$1 `is_struct` `not(!)`  
 *Obbligatorio:* sì

`query|value literal`  <a name="clauses-properties-value-literal"></a>
Una query o un valore letterale supportato come `string` o. `integer(64)`   
*Valori letterali supportati*:  
+ Tutti i tipi primitivi:`string`,,`integer(64)`,,`float(64)`, `bool` `char` `regex`
+ Tutti i tipi di intervalli specializzati per esprimere `integer(64)` o `char` intervalli espressi come: `float(64)`
  + `r[<lower_limit>, <upper_limit>]`, che si traduce in qualsiasi valore `k` che soddisfi la seguente espressione: `lower_limit <= k <= upper_limit`
  + `r[<lower_limit>, <upper_limit>`), che si traduce in qualsiasi valore `k` che soddisfi la seguente espressione: `lower_limit <= k < upper_limit`
  + `r(<lower_limit>, <upper_limit>]`, che si traduce in qualsiasi valore `k` che soddisfi la seguente espressione: `lower_limit < k <= upper_limit`
  + `r(<lower_limit>, <upper_limit>),`che si traduce in qualsiasi valore `k` che soddisfi la seguente espressione: `lower_limit < k < upper_limit`
+ Matrici associative (mappe) per dati di struttura chiave-valore annidati. Esempio:

  `{ "my-map": { "nested-maps": [ { "key": 10, "value": 20 } ] } }`
+ Matrici di tipi primitivi o tipi di array associativi
 *Obbligatorio*: condizionale; richiesto quando si utilizza un operatore binario.

`custom message`  <a name="clauses-properties-custom-message"></a>
Una stringa che fornisce informazioni sulla clausola. Il messaggio viene visualizzato negli output dettagliati dei `test` comandi `validate` and e può essere utile per comprendere o eseguire il debug della valutazione delle regole sui dati gerarchici.  
 *Obbligatorio:* no

## Utilizzo di interrogazioni nelle clausole
<a name="clauses-queries"></a>

Per informazioni sulla scrittura di interrogazioni, vedere e. [Definizione di interrogazioni e filtri](query-and-filtering.md) [Assegnazione e riferimento a variabili nelle regole di Guard](variables.md)

## Utilizzo degli operatori nelle clausole
<a name="clauses-operators"></a>

Di seguito sono riportati CloudFormation modelli di esempio e`Template-1`. `Template-2` Per dimostrare l'uso degli operatori supportati, le query e le clausole di esempio in questa sezione fanno riferimento a questi modelli di esempio.

**Modello-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
```

**Modello-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
```

### Esempi di clausole che utilizzano operatori unari
<a name="clauses-unary-operators"></a>
+ `empty`— Controlla se una raccolta è vuota. È inoltre possibile utilizzarlo per verificare se una query contiene valori in un dato gerarchico, poiché le query generano una raccolta. Non è possibile utilizzarlo per verificare se le query con valori di stringa hanno una stringa vuota () definita. `""` Per ulteriori informazioni, consulta [Definizione di interrogazioni e filtri](query-and-filtering.md).

  La clausola seguente verifica se il modello ha una o più risorse definite. Viene restituito `PASS` perché una risorsa con l'ID logico `S3Bucket` è definita in. `Template-1`

  ```
  Resources !empty
  ```

  La clausola seguente verifica se uno o più tag sono definiti per la `S3Bucket` risorsa. Il risultato è `PASS` perché `S3Bucket` ha due tag definiti per la `Tags` proprietà in. `Template-1`

  ```
  Resources.S3Bucket.Properties.Tags !empty
  ```
+ `exists`— Verifica se ogni occorrenza dell'interrogazione ha un valore e può essere utilizzata al posto di`!= null`.

  La clausola seguente verifica se la `BucketEncryption` proprietà è definita per. `S3Bucket` Restituisce `PASS` perché `BucketEncryption` è definito per `S3Bucket` in. `Template-1`

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

**Nota**  
I `not exists` controlli `empty` e restituiscono le chiavi `true` di proprietà mancanti durante l'attraversamento dei dati di input. Ad esempio, se la `Properties` sezione non è definita nel modello di`S3Bucket`, la clausola restituisce lo stesso risultato`Resources.S3Bucket.Properties.Tag empty`. `true` I `empty` controlli `exists` and non visualizzano il percorso del puntatore JSON all'interno del documento nei messaggi di errore. Entrambe queste clausole presentano spesso errori di recupero che non mantengono queste informazioni trasversali.
+ `is_string`— Verifica se ogni occorrenza dell'interrogazione è di tipo. `string`

  La clausola seguente verifica se è specificato un valore di stringa per la `BucketName` proprietà della `S3Bucket` risorsa. Viene restituito `PASS` perché il valore della stringa `"MyServiceS3Bucket"` è specificato per `BucketName` in. `Template-1`

  ```
  Resources.S3Bucket.Properties.BucketName is_string
  ```
+ `is_list`— Verifica se ogni occorrenza dell'interrogazione è di `list` tipo.

  La clausola seguente verifica se è specificato un elenco per la `Tags` proprietà della `S3Bucket` risorsa. Viene restituito `PASS` perché per in sono state specificate due coppie chiave-valore. `Tags` `Template-1`

  ```
  Resources.S3Bucket.Properties.Tags is_list
  ```
+ `is_struct`— Verifica se ogni occorrenza della query è costituita da dati strutturati.

  La clausola seguente verifica se i dati strutturati sono specificati per la `BucketEncryption` proprietà della `S3Bucket` risorsa. Viene restituito `PASS` perché `BucketEncryption` è specificato utilizzando il tipo *(object)* di `ServerSideEncryptionConfiguration` proprietà in. `Template-1`

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

**Nota**  
Per verificare lo stato inverso, è possibile utilizzare l'operatore (` not !`) con gli operatori `is_string``is_list`, e`is_struct`.

### Esempi di clausole che utilizzano operatori binari
<a name="clauses-binary-operators"></a>

La clausola seguente verifica se il valore specificato per la `BucketName` proprietà della `S3Bucket` risorsa in `Template-1` contiene la stringa`encrypt`, indipendentemente dal maiuscolo e minuscolo. Il risultato è che il `PASS` nome del bucket specificato `"MyServiceS3Bucket"` non contiene la stringa. `encrypt`

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

La clausola seguente verifica se il valore specificato per la `Size` proprietà della `NewVolume` risorsa in rientra in `Template-2` un intervallo specifico: 50 <= `Size` <= 200. Restituisce `PASS` perché `100` è specificato per. `Size`

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

La clausola seguente verifica se il valore specificato per la `VolumeType` proprietà della `NewVolume` risorsa in `Template-2` è `io1``io2`, o. `gp3` Restituisce `PASS` perché `io1` è specificato per. `NewVolume`

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

**Nota**  
Le query di esempio in questa sezione dimostrano l'uso di operatori che utilizzano le risorse con logico IDs `S3Bucket` and. `NewVolume` I nomi delle risorse sono spesso definiti dall'utente e possono essere denominati arbitrariamente in un modello Infrastructure as Code (IaC). Per scrivere una regola generica e applicabile a tutte le `AWS::S3::Bucket` risorse definite nel modello, la forma di interrogazione più comune utilizzata è. `Resources.*[ Type == ‘AWS::S3::Bucket’ ]` Per ulteriori informazioni, consulta [Definizione di interrogazioni e filtri](query-and-filtering.md) i dettagli sull'utilizzo ed esplora la directory [degli esempi](https://github.com/aws-cloudformation/cloudformation-guard/tree/main/guard-examples) nel `cloudformation-guard` GitHub repository.

## Utilizzo di messaggi personalizzati nelle clausole
<a name="clauses-custom-messages"></a>

Nell'esempio seguente, le clausole per `Template-2` includere un messaggio personalizzato.

```
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>>
```

## Combinazione di clausole
<a name="combining-clauses"></a>

In Guard, ogni clausola scritta su una nuova riga viene combinata implicitamente con la clausola successiva utilizzando la congiunzione (logica booleana). `and` Guarda l'esempio seguente.

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

È inoltre possibile utilizzare la disgiunzione per combinare una clausola con la clausola successiva specificando alla fine della prima clausola. `or|OR`

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

In una clausola Guard, le disgiunzioni vengono valutate per prime, seguite dalle congiunzioni. Le regole Guard possono essere definite come una combinazione di clausole (e di `or|OR` s) che danno come risultato () o (). `and|AND` `true` `PASS` `false` `FAIL` [È simile alla forma normale congiuntiva.](https://en.wikipedia.org/wiki/Conjunctive_normal_form) 

Gli esempi seguenti mostrano l'ordine di valutazione delle clausole.

```
# (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
```

Tutte le clausole basate sull'esempio `Template-1` possono essere combinate utilizzando la congiunzione. Guarda l'esempio seguente.

```
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
```

## Utilizzo di blocchi con regole Guard
<a name="blocks"></a>

I blocchi sono composizioni che rimuovono la verbosità e la ripetizione da un insieme di clausole, condizioni o regole correlate. Esistono tre tipi di blocchi:
+ Blocchi di query
+ `when`blocchi
+ blocchi con regole denominate

### Blocchi di query
<a name="query-blocks"></a>

Di seguito sono riportate le clausole basate sull'esempio. `Template-1` La congiunzione è stata utilizzata per combinare le clausole.

```
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
```

Parti dell'espressione di interrogazione in ogni clausola vengono ripetute. È possibile migliorare la componibilità e rimuovere la verbosità e la ripetizione da un set di clausole correlate con lo stesso percorso di interrogazione iniziale utilizzando un blocco di query. È possibile scrivere lo stesso set di clausole come illustrato nell'esempio seguente.

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

In un blocco di query, la query che precede il blocco imposta il contesto per le clausole all'interno del blocco.

Per ulteriori informazioni sull'uso dei blocchi, vedere. [Composizione di blocchi con regole denominate](named-rule-block-composition.md)

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

È possibile valutare i blocchi in modo condizionale utilizzando `when` i blocchi, che assumono la forma seguente.

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

La `when` parola chiave indica l'inizio del `when` blocco. `condition`è una regola della Guardia. Il blocco viene valutato solo se la valutazione della condizione risulta in `true` (`PASS`).

Di seguito è riportato un esempio di `when` blocco basato su`Template-1`.

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

La clausola all'interno del `when` blocco viene valutata solo se il valore specificato per `BucketName` è una stringa. Se il valore specificato per `BucketName` è referenziato nella `Parameters` sezione del modello, come illustrato nell'esempio seguente, la clausola all'interno del `when` blocco non viene valutata.

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

### Blocchi con regole denominate
<a name="named-rule-blocks"></a>

*È possibile assegnare un nome a un set di regole (set di regole) e quindi fare riferimento a questi blocchi di convalida modulari, denominati blocchi con regole *denominate, in altre regole*.* I blocchi con regole denominate assumono la forma seguente.

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

La `rule` parola chiave indica l'inizio del blocco di regole con nome.

`rule name`è una stringa leggibile dall'uomo che identifica in modo univoco un blocco di regole con nome. È un'etichetta per il set di regole Guard che incapsula. In questo uso, il termine *regola Guard* include clausole, blocchi di query, blocchi e blocchi di regole denominate. `when` Il nome della regola può essere usato per fare riferimento al risultato della valutazione del set di regole che incapsula, il che rende riutilizzabili i blocchi con regole denominate. Il nome della regola fornisce inoltre un contesto sugli errori delle regole negli output e dei comandi. `validate` `test` Il nome della regola viene visualizzato insieme allo stato di valutazione del blocco (`PASS``FAIL`, o`SKIP`) nell'output di valutazione del file delle regole. Guarda l'esempio seguente.

```
# 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**
```

È inoltre possibile valutare i blocchi con regole denominate in modo condizionale specificando la `when` parola chiave seguita da una condizione dopo il nome della regola.

Di seguito è riportato il `when` blocco di esempio discusso in precedenza in questo argomento.

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

Utilizzando blocchi con regole denominate, il precedente può anche essere scritto come segue.

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

Puoi riutilizzare e raggruppare blocchi con regole denominate con altre regole di Guard. Di seguito sono riportati alcuni esempi.

```
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
    ...
}
```

## Utilizzo delle funzioni integrate
<a name="built-in-functions"></a>

AWS CloudFormation Guard fornisce funzioni integrate che puoi utilizzare nelle tue regole per eseguire operazioni come la manipolazione di stringhe, l'analisi JSON e la conversione dei tipi di dati. Le funzioni sono supportate solo tramite l'assegnazione a una variabile.

### Funzioni chiave
<a name="key-functions"></a>

`json_parse(json_string)`  
Analizza le stringhe JSON in linea da un modello. Dopo l'analisi, è possibile valutare le proprietà dell'oggetto risultante.

`count(collection)`  
Restituisce il numero di elementi in cui viene risolta una query.

`regex_replace(base_string, regex_to_extract, regex_replacement)`  
Sostituisce parti di una stringa utilizzando espressioni regolari.

Per un elenco completo delle funzioni disponibili, tra cui la manipolazione delle stringhe, le operazioni di raccolta e le funzioni di conversione dei tipi di dati, consulta la [documentazione sulle funzioni nel repository](https://github.com/aws-cloudformation/cloudformation-guard/blob/main/docs/FUNCTIONS.md) Guard GitHub .

# Definizione delle interrogazioni e del filtraggio di Guard
<a name="query-and-filtering"></a>

Questo argomento tratta la scrittura di query e l'uso dei filtri durante la scrittura delle clausole delle regole Guard.

## Prerequisiti
<a name="query-filtering-prerequisites"></a>

Il filtraggio è un concetto avanzato. AWS CloudFormation Guard Ti consigliamo di leggere i seguenti argomenti fondamentali prima di imparare a usare i filtri:
+ [Che cos'è AWS CloudFormation Guard?](what-is-guard.md)
+ [Regole e clausole di scrittura](writing-rules.md)

## Definizione delle interrogazioni
<a name="defining-queries"></a>

Le espressioni di query sono semplici espressioni separate da punti (`.`) scritte per attraversare dati gerarchici. Le espressioni di query possono includere espressioni di filtro destinate a un sottoinsieme di valori. Quando le query vengono valutate, danno come risultato una raccolta di valori, simile a un set di risultati restituito da una query SQL.

La seguente query di esempio cerca risorse in un CloudFormation modello. `AWS::IAM::Role`

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

Le query seguono questi principi di base:
+ Ogni parte dot (`.`) della query attraversa la gerarchia quando viene utilizzato un termine chiave esplicito, ad esempio `Resources` o `Properties.Encrypted.` Se una parte della query non corrisponde al dato in entrata, Guard genera un errore di recupero.
+ Una parte dot (`.`) della query che utilizza un carattere jolly `*` attraversa tutti i valori della struttura a quel livello.
+ Una parte dot (`.`) della query che utilizza un carattere jolly di matrice `[*]` attraversa tutti gli indici di tale array.
+ Tutte le raccolte possono essere filtrate specificando i filtri all'interno di parentesi quadre. `[]` È possibile accedere alle raccolte nei seguenti modi:
  + Gli array presenti naturalmente in Datum sono raccolte. Di seguito vengono riportati alcuni esempi relativi ad :

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

    Tag: `[{"Key": "Stage", "Value": "PROD"}, {"Key": "App", "Value": "MyService"}]`
  + Quando si attraversano tutti i valori di una struttura come `Resources.*`
  + Qualsiasi risultato della query è di per sé una raccolta da cui i valori possono essere ulteriormente filtrati. Guarda l'esempio seguente.

    ```
    # 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
    }
    ```

Di seguito è riportato un frammento di CloudFormation modello di esempio.

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

In base a questo modello, il percorso percorso è `SampleRole` e il valore finale selezionato è. `Type: AWS::IAM::Role`

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

Il valore risultante della query `Resources.*[ Type == 'AWS::IAM::Role' ]` in formato YAML è illustrato nell'esempio seguente.

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

Alcuni dei modi in cui è possibile utilizzare le interrogazioni sono i seguenti:
+ Assegnate un'interrogazione alle variabili in modo che sia possibile accedere ai risultati della query facendo riferimento a tali variabili.
+ Segui l'interrogazione con un blocco che esegue il test rispetto a ciascuno dei valori selezionati.
+ Confronta direttamente una query con una clausola di base.

## Assegnazione di interrogazioni alle variabili
<a name="queries-and-filtering-variables"></a>

Guard supporta l'assegnazione di variabili in un'unica operazione all'interno di un determinato ambito. Per ulteriori informazioni sulle variabili nelle regole di Guard, vedere. [Assegnazione e riferimento a variabili nelle regole di Guard](variables.md)

Puoi assegnare le query alle variabili in modo da poter scrivere le query una sola volta e poi farvi riferimento altrove nelle regole di Guard. Vedi il seguente esempio di assegnazione di variabili che illustra i principi di interrogazione discussi più avanti in questa sezione.

```
#
# 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'
    }
]
```

## Esame diretto dei valori di una variabile assegnata a una query
<a name="variable-assigned-from-query"></a>

Guard supporta l'esecuzione diretta sui risultati di una query. Nell'esempio seguente, il `when` blocco verifica la `AvailabilityZone` proprietà `Encrypted``VolumeType`, e per ogni `AWS::EC2::Volume` risorsa trovata in un CloudFormation modello.

```
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']
        }
    }
}
```

## Confronti diretti a livello di clausola
<a name="direct-clause-level-comparisons"></a>

Guard supporta anche le interrogazioni come parte dei confronti diretti. Ad esempio, osserva quanto seguente.

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

Nell'esempio precedente, le due clausole (che iniziano con la `some` parola chiave) espresse nel modulo mostrato sono considerate clausole indipendenti e vengono valutate separatamente.

### Modulo a clausola singola e clausola a blocchi
<a name="single-versus-block-clause-form"></a>

Nel loro insieme, le due clausole di esempio mostrate nella sezione precedente non sono equivalenti al blocco seguente.

```
let resources = Resources.*

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

Questo blocco esegue una query per ogni `Tag` valore della raccolta e confronta i valori delle proprietà con i valori delle proprietà previsti. La forma combinata delle clausole nella sezione precedente valuta le due clausole in modo indipendente. Considerate il seguente input.

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

Le clausole nel primo modulo restituiscono a. `PASS` Quando si convalida la prima clausola nella prima forma, il percorso seguente attraversa `Resources` `Properties``Tags`, e `Key` corrisponde al valore `NotPRODEnd` e non corrisponde al valore previsto. `PROD`

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

Lo stesso accade con la seconda clausola del primo modulo. Il percorso attraversa`Resources`, `Properties``Tags`, e `Value` corrisponde al valore`AppStart`. Di conseguenza, la seconda clausola è indipendente.

Il risultato complessivo è un`PASS`.

Tuttavia, il modulo a blocchi viene valutato come segue. Per ogni `Tags` valore, viene confrontato se entrambi gli `Key` e `Value` corrispondono; `NotAppStart` e `NotPRODEnd` i valori non corrispondono nell'esempio seguente.

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

Perché le valutazioni controllano entrambi e `Key == /PROD$/``Value == /^App/`, la corrispondenza non è completa. Pertanto, il risultato è`FAIL`.

**Nota**  
Quando si lavora con le raccolte, si consiglia di utilizzare il modulo della clausola di blocco quando si desidera confrontare più valori per ogni elemento della raccolta. Utilizzate il modulo a clausola singola quando la raccolta è un insieme di valori scalari o quando intendete confrontare solo un attributo.

## Risultati delle query e clausole associate
<a name="query-outcomes"></a>

Tutte le query restituiscono un elenco di valori. Qualsiasi parte di un attraversamento, ad esempio una chiave mancante, valori vuoti per un array (`Tags: []`) quando si accede a tutti gli indici o valori mancanti per una mappa quando si incontra una map vuota (`Resources: {}`), può causare errori di recupero.

Tutti gli errori di recupero sono considerati errori nella valutazione delle clausole rispetto a tali interrogazioni. L'unica eccezione è quando nella query vengono utilizzati filtri espliciti. Quando vengono utilizzati i filtri, le clausole associate vengono ignorate.

I seguenti errori di blocco sono associati all'esecuzione delle query.
+ Se un modello non contiene risorse, la query restituisce lo stesso risultato e anche le clausole a `FAIL` livello di blocco associate lo restituiscono. `FAIL`
+ Quando un modello contiene un blocco di risorse vuoto, ad `FAIL` esempio`{ "Resources": {} }`, la query restituisce come risultato anche le clausole a livello di blocco associate. `FAIL`
+ Se un modello contiene risorse ma nessuna corrisponde alla query, la query restituisce risultati vuoti e le clausole a livello di blocco vengono ignorate.

## Utilizzo dei filtri nelle interrogazioni
<a name="filtering"></a>

I filtri nelle query sono effettivamente clausole Guard utilizzate come criteri di selezione. Di seguito è riportata la struttura di una clausola.

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

Tieni presente i seguenti punti chiave relativi [AWS CloudFormation Guard Regole di scrittura](writing-rules.md) all'utilizzo dei filtri:
+ Combina le clausole utilizzando [Conjunctive Normal Form](https://en.wikipedia.org/wiki/Conjunctive_normal_form) (CNF).
+ Specificate ogni clausola di congiunzione (`and`) su una nuova riga.
+ Specificate le disgiunzioni (`or`) utilizzando la `or` parola chiave tra due clausole.

L'esempio seguente illustra le clausole congiuntive e disgiuntive.

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

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

### Utilizzo delle clausole per i criteri di selezione
<a name="selection-criteria"></a>

È possibile applicare filtri a qualsiasi raccolta. Il filtro può essere applicato direttamente agli attributi dell'input che sono già simili a una raccolta. `securityGroups: [....]` È inoltre possibile applicare il filtro in base a una query, che è sempre una raccolta di valori. È possibile utilizzare tutte le funzionalità delle clausole, inclusa la forma normale congiuntiva, per il filtraggio.

La seguente query comune viene spesso utilizzata quando si selezionano le risorse per tipo da un modello. CloudFormation 

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

La query `Resources.*` restituisce tutti i valori presenti nella `Resources` sezione dell'input. Per il modello di esempio inserito in[Definizione delle interrogazioni](#defining-queries), la query restituisce quanto segue.

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

Ora, applica il filtro a questa raccolta. Il criterio da abbinare è. `Type == AWS::IAM::Role` Di seguito è riportato l'output della query dopo l'applicazione del filtro.

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

Quindi, controlla le varie clausole relative alle risorse. `AWS::IAM::Role`

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

Di seguito è riportato un esempio di query di filtraggio che seleziona tutte le risorse. `AWS::IAM::Policy` `AWS::IAM::ManagedPolicy`

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

L'esempio seguente verifica se queste risorse politiche hanno un `PolicyDocument` valore specificato.

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

### Elaborazione di esigenze di filtraggio più complesse
<a name="complex-filtering"></a>

Considerate il seguente esempio di elemento di AWS Config configurazione per le informazioni sui gruppi di sicurezza in ingresso e in uscita.

```
---
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
```

Tenere presente quanto segue:
+ `ipPermissions`(regole di ingresso) è una raccolta di regole all'interno di un blocco di configurazione.
+ Ogni struttura di regole contiene attributi come `ipv4Ranges` e `ipv6Ranges` per specificare una raccolta di blocchi CIDR.

Scriviamo una regola che selezioni tutte le regole di ingresso che consentano le connessioni da qualsiasi indirizzo IP e verifichi che le regole non consentano l'esposizione delle porte bloccate dal protocollo TCP.

Iniziamo con la parte di query che copre IPv4, come illustrato nell'esempio seguente.

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

La `some` parola chiave è utile in questo contesto. Tutte le query restituiscono una raccolta di valori che corrispondono alla query. Per impostazione predefinita, Guard valuta che tutti i valori restituiti come risultato della query vengano confrontati con i controlli. Tuttavia, questo comportamento potrebbe non essere sempre quello necessario per i controlli. Considerate la parte seguente dell'input dell'elemento di configurazione.

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

Sono presenti due valori per`ipv4Ranges`. Non tutti i `ipv4Ranges` valori equivalgono a un indirizzo IP indicato da`0.0.0.0/0`. Vuoi vedere se almeno un valore corrisponde`0.0.0.0/0`. Dici a Guard che non tutti i risultati restituiti da una query devono corrispondere, ma almeno un risultato deve corrispondere. La `some` parola chiave indica a Guard di assicurarsi che uno o più valori della query risultante corrispondano al controllo. Se nessun valore del risultato della query corrisponde, Guard genera un errore.

Quindi, aggiungi IPv6, come mostrato nell'esempio seguente.

```
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'
]
```

Infine, nell'esempio seguente, verifica che il protocollo non `udp` lo sia.

```
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' ] 
]
```

Di seguito è riportata la regola 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
                    >>
                }
            }

        }       
     }
}
```

### Separazione delle raccolte in base ai tipi in cui sono contenute
<a name="splitting-collection"></a>

Quando si utilizzano modelli di configurazione infrastructure as code (IaC), è possibile che si verifichi una raccolta che contiene riferimenti ad altre entità all'interno del modello di configurazione. Di seguito è riportato un CloudFormation modello di esempio che descrive le attività di Amazon Elastic Container Service (Amazon ECS) con un riferimento locale, un riferimento `TaskRoleArn` a e un riferimento `TaskArn` diretto a una stringa.

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

Considera la query seguente.

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

Questa query restituisce una raccolta di valori che contiene tutte e tre le `AWS::ECS::TaskDefinition` risorse mostrate nel modello di esempio. Separazioni `ecs_tasks` che contengono riferimenti `TaskRoleArn` locali dalle altre, come illustrato nell'esempio seguente.

```
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
    >>
}
```

# Assegnazione e riferimento a variabili nelle regole di Guard
<a name="variables"></a>

Puoi assegnare variabili nei tuoi file di AWS CloudFormation Guard regole per archiviare le informazioni a cui desideri fare riferimento nelle regole di Guard. Guard supporta l'assegnazione di variabili in un colpo solo. Le variabili vengono valutate pigramente, il che significa che Guard valuta le variabili solo quando vengono eseguite le regole.

**Topics**
+ [

## Assegnazione di variabili
](#assigning-variables)
+ [

## Variabili di riferimento
](#referencing-variables)
+ [

## Ambito variabile
](#variable-scope)
+ [

## Esempi di variabili nei file delle regole di Guard
](#variables-examples)

## Assegnazione di variabili
<a name="assigning-variables"></a>

Utilizzate la `let` parola chiave per inizializzare e assegnare una variabile. Come best practice, utilizzate snake case per i nomi delle variabili. Le variabili possono memorizzare valori letterali statici o proprietà dinamiche risultanti dalle query. Nell'esempio seguente, la variabile `ecs_task_definition_task_role_arn` memorizza il valore della stringa statica. `arn:aws:iam:123456789012:role/my-role-name`

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

Nell'esempio seguente, la variabile `ecs_tasks` memorizza i risultati di una query che cerca tutte le `AWS::ECS::TaskDefinition` risorse in un CloudFormation modello. È possibile fare riferimento `ecs_tasks` all'accesso alle informazioni su tali risorse quando si scrivono le regole.

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

## Variabili di riferimento
<a name="referencing-variables"></a>

Utilizzate il `%` prefisso per fare riferimento a una variabile.

In base all'esempio di `ecs_task_definition_task_role_arn` variabile in[Assegnazione di variabili](#assigning-variables), è possibile fare riferimento `ecs_task_definition_task_role_arn` nella `query|value literal` sezione di una clausola della regola Guard. L'utilizzo di tale riferimento garantisce che il valore specificato per la `TaskDefinitionArn` proprietà di qualsiasi `AWS::ECS::TaskDefinition` risorsa in un CloudFormation modello sia il valore `arn:aws:iam:123456789012:role/my-role-name` della stringa statica.

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

In base all'esempio della `ecs_tasks` variabile in[Assegnazione di variabili](#assigning-variables), è possibile fare riferimento `ecs_tasks` in una query (ad esempio, %ECS\$1Tasks.properties). Innanzitutto, Guard valuta la variabile `ecs_tasks` e quindi utilizza i valori restituiti per attraversare la gerarchia. Se la variabile si `ecs_tasks` risolve in valori non di stringa, Guard genera un errore.

**Nota**  
Attualmente, Guard non supporta il riferimento a variabili all'interno di messaggi di errore personalizzati.

## Ambito variabile
<a name="variable-scope"></a>

L'ambito si riferisce alla visibilità delle variabili definite in un file di regole. Un nome di variabile può essere utilizzato solo una volta all'interno di un ambito. Esistono tre livelli in cui è possibile dichiarare una variabile o tre possibili ambiti variabili:
+ A **livello di file**: in genere dichiarate nella parte superiore del file delle regole, è possibile utilizzare variabili a livello di file in tutte le regole all'interno del file delle regole. Sono visibili all'intero file.

  Nel seguente file di regole di esempio, le variabili `ecs_task_definition_task_role_arn` e `ecs_task_definition_execution_role_arn` sono inizializzate a livello di file.

  ```
  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
  }
  ```
+ A **livello di regola**: dichiarate all'interno di una regola, le variabili a livello di regola sono visibili solo per quella regola specifica. Qualsiasi riferimento esterno alla regola genera un errore.

  Nel seguente file di regole di esempio, le variabili `ecs_task_definition_task_role_arn` e `ecs_task_definition_execution_role_arn` vengono inizializzate a livello di regola. `ecs_task_definition_task_role_arn`È possibile fare riferimento solo all'interno della regola denominata. `check_ecs_task_definition_task_role_arn` È possibile fare riferimento solo alla `ecs_task_definition_execution_role_arn` variabile all'interno della regola `check_ecs_task_definition_execution_role_arn` denominata.

  ```
  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
  }
  ```
+ A **livello di blocco**: dichiarate all'interno di un blocco, ad esempio una `when` clausola, le variabili a livello di blocco sono visibili solo per quel blocco specifico. Qualsiasi riferimento esterno al blocco genera un errore.

  Nel seguente file di regole di esempio, le variabili `ecs_task_definition_task_role_arn` e `ecs_task_definition_execution_role_arn` sono inizializzate a livello di blocco all'interno del `AWS::ECS::TaskDefinition` blocco di tipo. È possibile fare riferimento solo alle `ecs_task_definition_execution_role_arn` variabili `ecs_task_definition_task_role_arn` and all'interno dei blocchi `AWS::ECS::TaskDefinition` di tipo per le rispettive regole.

  ```
  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
      }
  }
  ```

## Esempi di variabili nei file delle regole di Guard
<a name="variables-examples"></a>

Le sezioni seguenti forniscono esempi di assegnazione statica e dinamica delle variabili.

### Assegnazione statica
<a name="assigning-static-variables"></a>

Di seguito è riportato un CloudFormation modello di esempio.

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

Sulla base di questo modello, è possibile scrivere una regola denominata `check_ecs_task_definition_task_role_arn` che garantisce che la `TaskRoleArn` proprietà di tutte le risorse del `AWS::ECS::TaskDefinition` modello sia`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
}
```

Nell'ambito della regola, è possibile inizializzare una variabile chiamata `ecs_task_definition_task_role_arn` e assegnarle il valore di stringa statico. `'arn:aws:iam::123456789012:role/my-role-name'` La clausola della regola verifica se il valore specificato per la `TaskRoleArn` proprietà della `EcsTask` risorsa proviene `arn:aws:iam::123456789012:role/my-role-name` dal riferimento alla `ecs_task_definition_task_role_arn` variabile nella sezione. `query|value literal`

### Assegnazione dinamica
<a name="example-dynamic-assignment"></a>

Di seguito è riportato un CloudFormation modello di esempio.

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

Sulla base di questo modello, è possibile inizializzare una variabile chiamata nell'`ecs_tasks`ambito del file e assegnarle la query. `Resources.*[ Type == 'AWS::ECS::TaskDefinition'` Guard interroga tutte le risorse nel modello di input e memorizza le informazioni su di esse. `ecs_tasks` Puoi anche scrivere una regola chiamata `check_ecs_task_definition_task_role_arn` che assicura che la `TaskRoleArn` proprietà di tutte le risorse del `AWS::ECS::TaskDefinition` modello sia `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'
}
```

La clausola della regola verifica se il valore specificato per la `TaskRoleArn` proprietà della `EcsTask` risorsa proviene `arn:aws:iam::123456789012:role/my-role-name` dal riferimento alla `ecs_task_definition_task_role_arn` variabile nella `query` sezione.

### Applicazione CloudFormation della configurazione del modello
<a name="example-3"></a>

Esaminiamo un esempio più complesso di caso d'uso in produzione. In questo esempio, scriviamo regole Guard per garantire controlli più rigorosi su come vengono definite le attività di Amazon ECS.

Di seguito è riportato un modello di esempio CloudFormation .

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

Sulla base di questo modello, scriviamo le seguenti regole per garantire che questi requisiti siano soddisfatti:
+ A ogni `AWS::ECS::TaskDefinition` risorsa del modello sono associati sia un ruolo di attività che un ruolo di esecuzione.
+ I ruoli di attività e i ruoli di esecuzione sono ruoli AWS Identity and Access Management (IAM).
+ I ruoli sono definiti nel modello.
+ La `PermissionsBoundary` proprietà è specificata per ogni ruolo.

```
# 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
    }
}
```

# Composizione di blocchi con regole denominate in AWS CloudFormation Guard
<a name="named-rule-block-composition"></a>

Quando si scrivono blocchi con regole denominate utilizzando AWS CloudFormation Guard, è possibile utilizzare i due stili di composizione seguenti:
+ Dipendenza condizionale
+ Dipendenza correlazionale

L'uso di uno di questi stili di composizione delle dipendenze aiuta a promuovere la riusabilità e riduce la verbosità e la ripetizione nei blocchi con regole denominate.

**Topics**
+ [

## Prerequisiti
](#named-rules-prerequisites)
+ [

## Composizione delle dipendenze condizionali
](#named-rules-conditional-dependency)
+ [

## Composizione delle dipendenze correlazionali
](#named-rules-correlational-dependency)

## Prerequisiti
<a name="named-rules-prerequisites"></a>

[Scopri i blocchi con regole denominate in Writing rules.](writing-rules.md#named-rule-blocks)

## Composizione delle dipendenze condizionali
<a name="named-rules-conditional-dependency"></a>

In questo stile di composizione, la valutazione di un `when` blocco o di un blocco con regole denominate dipende condizionatamente dal risultato della valutazione di uno o più altri blocchi o clausole con regole denominate. Il seguente file di regole Guard contiene blocchi con regole denominate che dimostrano dipendenze condizionali.

```
# 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
    ...
}
```

Nel file di regole di esempio precedente, `Example-1` ha i seguenti risultati possibili:
+ Se `rule_name_A` restituisce a`PASS`, vengono valutate le regole Guard incapsulate da. `rule_name_B`
+ Se `rule_name_A` restituisce a`FAIL`, le regole Guard incapsulate da non vengono valutate. `rule_name_B` `rule_name_B`valuta `SKIP` in.
+ Se `rule_name_A` restituisce a`SKIP`, le regole Guard incapsulate da `rule_name_B` non vengono valutate. `rule_name_B`valuta `SKIP` in.
**Nota**  
Questo caso si verifica se dipende `rule_name_A` condizionatamente da una regola che restituisce `FAIL` e determina la valutazione a. `rule_name_A` `SKIP`

Di seguito è riportato un esempio di elemento di configurazione del database di gestione della configurazione (CMDB) tratto da un AWS Config elemento per le informazioni sui gruppi di sicurezza in ingresso e in uscita. Questo esempio dimostra la composizione delle dipendenze condizionali.

```
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
                }
            }
        }
    }
}
```

Nell'esempio precedente, `check_parameter_validity` dipende condizionatamente da `check_resource_type_and_parameter` e `check_ip_procotol_and_port_range_validity` dipende condizionatamente da. `check_parameter_validity` Quanto segue è un elemento di configurazione del database di gestione della configurazione (CMDB) conforme alle regole precedenti.

```
---
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
```

## Composizione delle dipendenze correlazionali
<a name="named-rules-correlational-dependency"></a>

In questo stile di composizione, la valutazione di un `when` blocco o di un blocco con regole denominate dipende in modo correlazionale dal risultato della valutazione di una o più altre regole di Guard. La dipendenza correlazionale può essere ottenuta come segue.

```
# 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
    ...
}
```

Per aiutarti a comprendere la composizione delle dipendenze correlazionali, consulta il seguente esempio di un file di regole di 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'
}
```

Nel file di regole precedente, `ensure_elbs_are_internal_and_secure` ha una dipendenza correlazionale da. `ensure_all_elbs_are_secure` Di seguito è riportato un CloudFormation modello di esempio conforme alle regole precedenti.

```
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...'
```

# Scrittura di clausole per eseguire valutazioni basate sul contesto
<a name="context-aware-evaluations"></a>

AWS CloudFormation Guard le clausole vengono valutate sulla base di dati gerarchici. Il motore di valutazione Guard risolve le interrogazioni sui dati in entrata seguendo i dati gerarchici come specificato, utilizzando una semplice notazione punteggiata. Spesso sono necessarie più clausole per la valutazione rispetto a una mappa di dati o a una raccolta. Guard fornisce una sintassi comoda per scrivere tali clausole. Il motore è contestualmente consapevole e utilizza i dati corrispondenti associati per le valutazioni.

Di seguito è riportato un esempio di configurazione di Kubernetes Pod con contenitori, a cui è possibile applicare valutazioni sensibili al contesto.

```
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
```

Puoi creare clausole Guard per valutare questi dati. Quando si valuta un file di regole, il contesto è l'intero documento di input. Di seguito sono riportate alcune clausole di esempio che convalidano l'applicazione dei limiti per i contenitori specificati in un 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
            >>
        }
    }
}
```

## Comprensione nelle valutazioni `context`
<a name="context"></a>

A livello di blocco di regole, il contesto in entrata è il documento completo. Le valutazioni della `when` condizione vengono eseguite in base a questo contesto radice in entrata in cui si trovano gli attributi `apiVersion` and`kind`. Nell'esempio precedente, queste condizioni restituiscono a`true`.

Ora, attraversate la gerarchia `spec.containers[*]` mostrata nell'esempio precedente. Per ogni attraversamento della gerarchia, il valore del contesto cambia di conseguenza. Al termine dell'attraversamento del `spec` blocco, il contesto cambia, come illustrato nell'esempio seguente.

```
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
```

Dopo aver attraversato l'`containers`attributo, il contesto viene mostrato nell'esempio seguente.

```
- 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
```

## Comprensione dei loop
<a name="loops"></a>

È possibile utilizzare l'espressione `[*]` per definire un ciclo per tutti i valori contenuti nell'array per l'`containers`attributo. Il blocco viene valutato per ogni elemento al suo interno`containers`. Nel frammento di regola dell'esempio precedente, le clausole contenute all'interno del blocco definiscono i controlli da convalidare rispetto a una definizione di contenitore. Il blocco di clausole contenuto all'interno viene valutato due volte, una volta per ogni definizione di contenitore.

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

Per ogni iterazione, il valore di contesto è il valore in corrispondenza dell'indice corrispondente.

**Nota**  
L'unico formato di accesso all'indice supportato è `[<integer>]` o`[*]`. Attualmente, Guard non supporta intervalli come`[2..4]`.

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

Spesso nei luoghi in cui viene accettato un array, vengono accettati anche valori singoli. Ad esempio, se è presente un solo contenitore, l'array può essere eliminato e viene accettato il seguente input.

```
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 un attributo può accettare un array, assicurati che la regola utilizzi il modulo di matrice. Nell'esempio precedente, si usa `containers[*]` e non`containers`. Guard valuta correttamente quando attraversa i dati quando incontra solo la forma a valore singolo.

**Nota**  
Usa sempre il modulo di matrice quando esprimi l'accesso a una clausola di regola quando un attributo accetta un array. Guard valuta correttamente anche nel caso in cui venga utilizzato un solo valore.

## Utilizzando il modulo `spec.containers[*]` invece di `spec.containers`
<a name="containers"></a>

Le query Guard restituiscono una raccolta di valori risolti. Quando si utilizza il modulo`spec.containers`, i valori risolti per la query contengono l'array a cui si fa riferimento`containers`, non gli elementi al suo interno. Quando si utilizza il modulo`spec.containers[*]`, si fa riferimento a ogni singolo elemento contenuto. Ricordatevi di usare il `[*]` modulo ogni volta che intendete valutare ogni elemento contenuto nell'array.

## Usato `this` per fare riferimento al valore di contesto corrente
<a name="this"></a>

Quando si crea una regola Guard, è possibile fare riferimento al valore di contesto utilizzando`this`. Spesso `this` è implicito perché è legato al valore del contesto. Ad esempio, `this.apiVersion``this.kind`, e `this.spec` sono associati alla radice o al documento. Al contrario, `this.resources` è associato a ciascun valore per`containers`, ad esempio `/spec/containers/0/` e`/spec/containers/1`. Allo stesso modo, `this.cpu` e `this.memory` mappa fino ai limiti, in particolare `/spec/containers/0/resources/limits` e`/spec/containers/1/resources/limits`. 

Nel prossimo esempio, la regola precedente per la configurazione di Kubernetes Pod viene riscritta per essere utilizzata in modo esplicito. `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
            >>
        }
    }
}
```

Non è necessario utilizzarlo in modo esplicito. `this` Tuttavia, il `this` riferimento può essere utile quando si lavora con gli scalari, come mostrato nell'esempio seguente.

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

Nell'esempio precedente, `this` viene utilizzato per fare riferimento a ciascun numero di porta.

## Potenziali errori con l'uso di dati impliciti `this`
<a name="common-errors"></a>

Quando si creano regole e clausole, si verificano alcuni errori comuni quando si fa riferimento a elementi del valore di contesto implicito. `this` Ad esempio, considerate il seguente dato di input rispetto al quale effettuare la valutazione (questo deve passare).

```
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 viene testata rispetto al modello precedente, la regola seguente genera un errore perché presuppone erroneamente di sfruttare l'implicito. `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
                >>
            }                
        }
    }
}
```

Per illustrare questo esempio, salvate il file delle regole precedenti con il nome `any_ip_ingress_check.guard` e i dati con il nome del file. `ip_ingress.yaml` Quindi, esegui il `validate` comando seguente con questi file.

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

Nell'output seguente, il motore indica che il suo tentativo di recuperare una proprietà `InputParameters.TcpBlockedPorts[*]` sul valore `/configuration/ipPermissions/1` è `/configuration/ipPermissions/0` fallito.

```
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[*]
```

Per facilitare la comprensione di questo risultato, riscrivi la regola utilizzando riferimenti `this` espliciti.

```
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`fa riferimento a ogni valore contenuto nella variabile. `any_ip_permissions` L'interrogazione assegnata alla variabile seleziona `configuration.ipPermissions` i valori che corrispondono. L'errore indica un tentativo di recupero `InputParamaters` in questo contesto, ma si `InputParameters` è verificato nel contesto principale.

Il blocco interno fa riferimento anche a variabili che non rientrano nell'ambito, come illustrato nell'esempio seguente.

```
{
    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`si riferisce a ogni valore di porta in`[21, 22, 110]`, ma si riferisce anche a `fromPort` and`toPort`. Entrambi appartengono all'ambito del blocco esterno.

### Risoluzione degli errori con l'uso implicito di `this`
<a name="common-errors-resolution"></a>

Utilizzate le variabili per assegnare e fare riferimento in modo esplicito ai valori. Innanzitutto, `InputParameter.TcpBlockedPorts` fa parte del contesto di input (root). `InputParameter.TcpBlockedPorts`Esci dal blocco interno e assegnalo in modo esplicito, come mostrato nell'esempio seguente.

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

Quindi, fate riferimento a questa variabile in modo esplicito.

```
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
                >>
            }
        }
    }        
}
```

Fate lo stesso per i `this` riferimenti interni`%ports`.

Tuttavia, non tutti gli errori sono ancora stati corretti perché il loop interno contiene `ports` ancora un riferimento errato. L'esempio seguente mostra la rimozione del riferimento errato.

```
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
                    >>
                }
            }
        }       
    }   
}
```

Quindi, esegui nuovamente il `validate` comando. Questa volta, passa.

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

Quanto segue è l'output del `validate` comando.

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

Per testare questo approccio in caso di errori, l'esempio seguente utilizza una modifica del payload.

```
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 rientra nell'intervallo compreso tra 89 e 109 a cui è consentito qualsiasi indirizzo. IPv6 Di seguito è riportato l'output del `validate` comando dopo averlo eseguito nuovamente.

```
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
```