

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

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