

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

# Definition und Filterung von Guard-Abfragen
<a name="query-and-filtering"></a>

In diesem Thema werden das Schreiben von Abfragen und die Verwendung von Filtern beim Schreiben von Guard-Regelklauseln behandelt.

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

Das Filtern ist ein fortgeschrittenes AWS CloudFormation Guard Konzept. Wir empfehlen Ihnen, sich mit den folgenden grundlegenden Themen vertraut zu machen, bevor Sie sich mit Filtern vertraut machen:
+ [Was ist AWS CloudFormation Guard?](what-is-guard.md)
+ [Schreibregeln, Klauseln](writing-rules.md)

## Abfragen definieren
<a name="defining-queries"></a>

Abfrageausdrücke sind einfache, durch Punkte (`.`) getrennte Ausdrücke, die geschrieben wurden, um hierarchische Daten zu durchqueren. Abfrageausdrücke können Filterausdrücke enthalten, die auf eine Teilmenge von Werten abzielen. Wenn Abfragen ausgewertet werden, führen sie zu einer Sammlung von Werten, ähnlich einer Ergebnismenge, die von einer SQL-Abfrage zurückgegeben wird.

Die folgende Beispielabfrage durchsucht eine CloudFormation Vorlage nach `AWS::IAM::Role` Ressourcen.

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

Abfragen folgen diesen Grundprinzipien:
+ Jeder Punkt (`.`) der Abfrage durchläuft die Hierarchie nach unten, wenn ein expliziter Schlüsselbegriff verwendet wird, wie z. B. `Resources` oder `Properties.Encrypted.` Wenn ein Teil der Abfrage nicht mit dem eingehenden Datum übereinstimmt, gibt Guard einen Abruffehler aus.
+ Ein Punkt (`.`) in der Abfrage, der einen Platzhalter verwendet, `*` durchläuft alle Werte für die Struktur auf dieser Ebene.
+ Ein Punkt (`.`) -Teil der Abfrage, der einen Array-Platzhalter verwendet, `[*]` durchquert alle Indizes für dieses Array.
+ Alle Sammlungen können gefiltert werden, indem Filter in eckigen Klammern angegeben werden. `[]` Sammlungen können auf folgende Weise gefunden werden:
  + Natürlich vorkommende Anordnungen in Daten sind Sammlungen. Hier einige Beispiele aus der :

    Anschlüsse: `[20, 21, 110, 190]`

    Schlagworte: `[{"Key": "Stage", "Value": "PROD"}, {"Key": "App", "Value": "MyService"}]`
  + Beim Durchlaufen aller Werte für eine Struktur wie `Resources.*`
  + Jedes Abfrageergebnis ist selbst eine Sammlung, aus der Werte weiter gefiltert werden können. Sehen Sie sich das folgende Beispiel an.

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

Im Folgenden finden Sie ein Beispiel für einen CloudFormation Vorlagenausschnitt.

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

Basierend auf dieser Vorlage ist der durchlaufene Pfad `SampleRole` und der gewählte Endwert ist. `Type: AWS::IAM::Role`

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

Der resultierende Wert der Abfrage `Resources.*[ Type == 'AWS::IAM::Role' ]` im YAML-Format wird im folgenden Beispiel gezeigt.

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

Sie können Abfragen unter anderem wie folgt verwenden:
+ Weisen Sie Variablen eine Abfrage zu, sodass auf Abfrageergebnisse zugegriffen werden kann, indem auf diese Variablen verwiesen wird.
+ Folgen Sie der Abfrage mit einem Block, der mit jedem der ausgewählten Werte testet.
+ Vergleichen Sie eine Abfrage direkt mit einer Basisklausel.

## Abfragen Variablen zuordnen
<a name="queries-and-filtering-variables"></a>

Guard unterstützt einmalige Variablenzuweisungen innerhalb eines bestimmten Bereichs. Weitere Informationen zu Variablen in Guard-Regeln finden Sie unter[Zuweisen und Referenzieren von Variablen in Guard-Regeln](variables.md).

Sie können Variablen Abfragen zuweisen, sodass Sie Abfragen einmal schreiben und dann an anderer Stelle in Ihren Guard-Regeln darauf verweisen können. Sehen Sie sich das folgende Beispiel für Variablenzuweisungen an, das die Abfrageprinzipien demonstriert, die später in diesem Abschnitt erörtert werden.

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

## Direktes Durchlaufen von Werten aus einer Variablen, die einer Abfrage zugewiesen wurde
<a name="variable-assigned-from-query"></a>

Guard unterstützt die direkte Ausführung der Ergebnisse einer Abfrage. Im folgenden Beispiel testet der `when` Block anhand der `AvailabilityZone` Eigenschaften `Encrypted``VolumeType`, und für jede `AWS::EC2::Volume` Ressource, die in einer CloudFormation Vorlage gefunden wurde.

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

## Direkte Vergleiche auf Klauselebene
<a name="direct-clause-level-comparisons"></a>

Guard unterstützt auch Abfragen als Teil direkter Vergleiche. Sehen Sie sich zum Beispiel Folgendes an.

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

Im vorherigen Beispiel werden die beiden Klauseln (beginnend mit dem `some` Schlüsselwort), die in der abgebildeten Form ausgedrückt werden, als unabhängige Klauseln betrachtet und separat bewertet.

### Form einer Einzelklausel und einer Blockklausel
<a name="single-versus-block-clause-form"></a>

Zusammengenommen entsprechen die beiden im vorherigen Abschnitt aufgeführten Beispielklauseln nicht dem folgenden Block.

```
let resources = Resources.*

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

Dieser Block fragt nach jedem `Tag` Wert in der Sammlung ab und vergleicht seine Eigenschaftswerte mit den erwarteten Eigenschaftswerten. Durch die kombinierte Form der Klauseln im vorherigen Abschnitt werden die beiden Klauseln unabhängig voneinander bewertet. Betrachten Sie die folgende Eingabe.

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

Klauseln in der ersten Form haben die Wirkung von`PASS`. Bei der Validierung der ersten Klausel in der ersten Form `Key` entspricht der folgende Pfad über `Resources` `Properties``Tags`,, und dem Wert `NotPRODEnd` und nicht dem erwarteten Wert. `PROD`

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

Das Gleiche passiert mit der zweiten Klausel der ersten Form. Der Pfad über`Resources`, `Properties``Tags`, und `Value` entspricht dem Wert`AppStart`. Daher die zweite Klausel unabhängig.

Das Gesamtergebnis ist ein`PASS`.

Die Blockform wird jedoch wie folgt ausgewertet. Für jeden `Tags` Wert wird verglichen, ob `Key` sowohl der als auch der `Value` gleiche Wert `NotAppStart` zutrifft. Im folgenden Beispiel werden die `NotPRODEnd` Werte nicht gefunden.

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

Da bei Auswertungen sowohl auf beide als auch `Key == /PROD$/` geprüft wird`Value == /^App/`, ist die Übereinstimmung nicht vollständig. Daher lautet das Ergebnis`FAIL`.

**Anmerkung**  
Wenn Sie mit Sammlungen arbeiten, empfehlen wir, das Blockklauselformular zu verwenden, wenn Sie mehrere Werte für jedes Element in der Sammlung vergleichen möchten. Verwenden Sie das Einzelklauselformular, wenn es sich bei der Sammlung um eine Gruppe von Skalarwerten handelt oder wenn Sie nur ein einzelnes Attribut vergleichen möchten.

## Abfrageergebnisse und zugehörige Klauseln
<a name="query-outcomes"></a>

Alle Abfragen geben eine Werteliste zurück. Jeder Teil einer Traversierung, z. B. ein fehlender Schlüssel, leere Werte für ein Array (`Tags: []`) beim Zugriff auf alle Indizes oder fehlende Werte für eine Map, wenn auf eine leere Map (`Resources: {}`) gestoßen wird, kann zu Abruffehlern führen.

Bei der Auswertung von Klauseln anhand solcher Abfragen werden alle Abruffehler als Fehlschläge gewertet. Die einzige Ausnahme ist, wenn in der Abfrage explizite Filter verwendet werden. Wenn Filter verwendet werden, werden die zugehörigen Klauseln übersprungen.

Die folgenden Blockfehler stehen im Zusammenhang mit laufenden Abfragen.
+ Wenn eine Vorlage keine Ressourcen enthält, wird die Abfrage als ausgewertet`FAIL`, und die zugehörigen Klauseln auf Blockebene werden ebenfalls als ausgewertet. `FAIL`
+ Wenn eine Vorlage einen leeren Ressourcenblock wie enthält`{ "Resources": {} }`, wird die Abfrage als ausgewertet`FAIL`, und die zugehörigen Klauseln auf Blockebene werden ebenfalls als ausgewertet. `FAIL`
+ Wenn eine Vorlage Ressourcen enthält, aber keine der Abfrage entsprechen, gibt die Abfrage leere Ergebnisse zurück, und die Klauseln auf Blockebene werden übersprungen.

## Verwenden von Filtern in Abfragen
<a name="filtering"></a>

Filter in Abfragen sind im Grunde Guard-Klauseln, die als Auswahlkriterien verwendet werden. Es folgt die Struktur einer Klausel.

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

Beachten Sie bei der Arbeit mit Filtern die folgenden wichtigen Punkte: [AWS CloudFormation Guard Regeln schreiben](writing-rules.md)
+ Kombinieren Sie Klauseln mithilfe der [konjunktiven Normalform (CNF)](https://en.wikipedia.org/wiki/Conjunctive_normal_form).
+ Geben Sie jede Konjunktion (`and`) -Klausel in einer neuen Zeile an.
+ Geben Sie Disjunktionen (`or`) an, indem Sie das `or` Schlüsselwort zwischen zwei Klauseln verwenden.

Das folgende Beispiel zeigt konjunktive und disjunktive Klauseln.

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

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

### Verwendung von Klauseln als Auswahlkriterien
<a name="selection-criteria"></a>

Sie können die Filterung auf jede Sammlung anwenden. Die Filterung kann direkt auf Attribute in der Eingabe angewendet werden, die bereits einer Sammlung ähneln`securityGroups: [....]`. Sie können die Filterung auch auf eine Abfrage anwenden, bei der es sich immer um eine Sammlung von Werten handelt. Sie können alle Funktionen von Klauseln, einschließlich der konjunktiven Normalform, zum Filtern verwenden.

Die folgende allgemeine Abfrage wird häufig verwendet, wenn Ressourcen nach Typ aus einer CloudFormation Vorlage ausgewählt werden.

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

Die Abfrage `Resources.*` gibt alle Werte zurück, die im `Resources` Abschnitt der Eingabe vorhanden sind. Für die Beispielvorlage Input in [Abfragen definieren](#defining-queries) gibt die Abfrage Folgendes zurück.

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

Wenden Sie nun den Filter auf diese Sammlung an. Das Kriterium, das erfüllt werden muss, ist`Type == AWS::IAM::Role`. Im Folgenden finden Sie die Ausgabe der Abfrage, nachdem der Filter angewendet wurde.

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

Überprüfen Sie als Nächstes verschiedene Klauseln für `AWS::IAM::Role` Ressourcen.

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

Im Folgenden finden Sie ein Beispiel für eine Filterabfrage, die alle `AWS::IAM::ManagedPolicy` Ressourcen `AWS::IAM::Policy` auswählt.

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

Im folgenden Beispiel wird geprüft, ob für diese Richtlinienressourcen ein `PolicyDocument` bestimmter Wert angegeben wurde.

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

### Aufbau komplexerer Filteranforderungen
<a name="complex-filtering"></a>

Betrachten Sie das folgende Beispiel für ein AWS Config Konfigurationselement für Informationen zu Sicherheitsgruppen für eingehenden und ausgehenden Datenverkehr.

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

Beachten Sie Folgendes:
+ `ipPermissions`(Eingangsregeln) ist eine Sammlung von Regeln innerhalb eines Konfigurationsblocks.
+ Jede Regelstruktur enthält Attribute wie `ipv4Ranges` und `ipv6Ranges` zur Spezifizierung einer Sammlung von CIDR-Blöcken.

Schreiben wir eine Regel, die alle Eingangsregeln auswählt, die Verbindungen von einer beliebigen IP-Adresse aus zulassen, und überprüft, ob die Regeln nicht zulassen, dass blockierte TCP-Ports offengelegt werden.

Beginnen Sie mit dem entsprechenden Abfrageteil IPv4, wie im folgenden Beispiel gezeigt.

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

Das `some` Schlüsselwort ist in diesem Zusammenhang nützlich. Alle Abfragen geben eine Sammlung von Werten zurück, die der Abfrage entsprechen. Standardmäßig wertet Guard aus, dass alle als Ergebnis der Abfrage zurückgegebenen Werte mit Prüfungen abgeglichen werden. Dieses Verhalten ist jedoch möglicherweise nicht immer das, was Sie für Prüfungen benötigen. Betrachten Sie den folgenden Teil der Eingabe aus dem Konfigurationselement.

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

Es sind zwei Werte für vorhanden`ipv4Ranges`. Nicht alle `ipv4Ranges` Werte entsprechen einer IP-Adresse, die mit bezeichnet wird. `0.0.0.0/0` Sie möchten sehen, ob mindestens ein Wert übereinstimmt. `0.0.0.0/0` Sie teilen Guard mit, dass nicht alle von einer Abfrage zurückgegebenen Ergebnisse übereinstimmen müssen, aber mindestens ein Ergebnis muss übereinstimmen. Das `some` Schlüsselwort weist Guard an, sicherzustellen, dass ein oder mehrere Werte aus der resultierenden Abfrage der Prüfung entsprechen. Wenn keine Abfrageergebniswerte übereinstimmen, gibt Guard einen Fehler aus.

Fügen Sie als Nächstes hinzu IPv6, wie im folgenden Beispiel gezeigt.

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

Stellen Sie im folgenden Beispiel abschließend sicher, dass das Protokoll dies nicht ist`udp`.

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

Im Folgenden finden Sie die vollständige Regel.

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

        }       
     }
}
```

### Trennen von Sammlungen nach ihren enthaltenen Typen
<a name="splitting-collection"></a>

Wenn Sie IaC-Konfigurationsvorlagen (Infrastructure as Code) verwenden, stoßen Sie möglicherweise auf eine Sammlung, die Verweise auf andere Entitäten innerhalb der Konfigurationsvorlage enthält. Im Folgenden finden Sie eine CloudFormation Beispielvorlage, die Aufgaben von Amazon Elastic Container Service (Amazon ECS) mit einem lokalen Verweis auf`TaskRoleArn`, einem Verweis auf `TaskArn` und einem direkten Zeichenkettenverweis beschreibt.

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

Betrachten Sie folgende Abfrage.

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

Diese Abfrage gibt eine Sammlung von Werten zurück, die alle drei in der Beispielvorlage gezeigten `AWS::ECS::TaskDefinition` Ressourcen enthält. Trennen Sie `ecs_tasks` diese, die `TaskRoleArn` lokale Verweise enthalten, von anderen, wie im folgenden Beispiel gezeigt.

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