

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# AWS CloudFormation Guard Aturan penulisan
<a name="writing-rules"></a>

Dalam AWS CloudFormation Guard, *aturan* adalah policy-as-code aturan. Anda menulis aturan dalam bahasa khusus domain Guard (DSL) yang dapat memvalidasi data berformat JSON- atau YAML. Aturan terdiri dari *klausa*.

Anda dapat menyimpan aturan yang ditulis menggunakan Guard DSL ke dalam file teks biasa yang menggunakan ekstensi file apa pun.

Anda dapat membuat beberapa file aturan dan mengkategorikannya sebagai kumpulan *aturan*. Set aturan memungkinkan Anda memvalidasi data berformat JSON atau YAML terhadap beberapa file aturan secara bersamaan.

**Topics**
+ [Klausul](#clauses)
+ [Menggunakan kueri dalam klausa](#clauses-queries)
+ [Menggunakan operator dalam klausa](#clauses-operators)
+ [Menggunakan pesan kustom dalam klausa](#clauses-custom-messages)
+ [Menggabungkan klausa](#combining-clauses)
+ [Menggunakan blok dengan aturan Guard](#blocks)
+ [Menggunakan fungsi bawaan](#built-in-functions)
+ [Mendefinisikan kueri Guard dan pemfilteran](query-and-filtering.md)
+ [Menetapkan dan mereferensikan variabel dalam aturan Guard](variables.md)
+ [Menyusun blok aturan bernama di AWS CloudFormation Guard](named-rule-block-composition.md)
+ [Menulis klausa untuk melakukan evaluasi sadar konteks](context-aware-evaluations.md)

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

Klausa adalah ekspresi Boolean yang mengevaluasi ke true (`PASS`) atau false (). `FAIL` Klausul menggunakan operator biner untuk membandingkan dua nilai atau operator unary yang beroperasi pada satu nilai.

**Contoh klausa unary**

Klausul unary berikut mengevaluasi apakah koleksi `TcpBlockedPorts` kosong.

```
InputParameters.TcpBlockedPorts not empty
```

Klausa unary berikut mengevaluasi apakah `ExecutionRoleArn` properti adalah string.

```
Properties.ExecutionRoleArn is_string
```

**Contoh klausa biner**

Klausa biner berikut mengevaluasi apakah `BucketName` properti berisi string`encrypted`, terlepas dari casing.

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

Klausul biner berikut mengevaluasi apakah `ReadCapacityUnits` properti kurang dari atau sama dengan 5.000.

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

### Sintaks untuk menulis klausa aturan Guard
<a name="clauses-syntax"></a>

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

### Properti klausa aturan Penjaga
<a name="clauses-properties"></a>

`query`  <a name="clauses-properties-query"></a>
Ekspresi terpisah dot (`.`) ditulis untuk melintasi data hierarkis. Ekspresi kueri dapat mencakup ekspresi filter untuk menargetkan subset nilai. Kueri dapat ditetapkan ke variabel sehingga Anda dapat menulisnya sekali dan mereferensikannya di tempat lain dalam kumpulan aturan, yang akan memungkinkan Anda mengakses hasil kueri.  
Untuk informasi selengkapnya tentang menulis kueri dan pemfilteran, lihat. [Mendefinisikan kueri dan pemfilteran](query-and-filtering.md)  
 *Wajib*: Ya

`operator`  <a name="clauses-properties-operator"></a>
Operator unary atau biner yang membantu memeriksa status kueri. Sisi kiri (LHS) dari operator biner harus berupa kueri, dan sisi kanan (RHS) harus berupa kueri atau nilai literal.  
 *Operator biner yang didukung*: `==` `!=` (Sama) \$1 (Tidak sama) \$1 `>` (Lebih besar dari) \$1 `>=` (Lebih besar dari atau sama dengan) \$1 `<` (Kurang dari) \$1 `<=` (Kurang dari atau sama dengan) \$1 `IN` (Dalam daftar formulir [x, y, z]  
 *Operator unary yang didukung*: `exists` \$1 `empty` \$1 `is_string` \$1 `is_list` \$1 `is_struct` `not(!)`  
 *Wajib*: Ya

`query|value literal`  <a name="clauses-properties-value-literal"></a>
Kueri atau nilai literal yang didukung seperti `string` atau`integer(64)`.   
*Literal nilai yang didukung*:  
+ Semua tipe primitif:`string`,,`integer(64)`,`float(64)`,`bool`, `char` `regex`
+ Semua jenis rentang khusus untuk mengekspresikan`integer(64)`,`float(64)`, atau `char` rentang dinyatakan sebagai:
  + `r[<lower_limit>, <upper_limit>]`, yang diterjemahkan ke nilai apa pun `k` yang memenuhi ekspresi berikut: `lower_limit <= k <= upper_limit`
  + `r[<lower_limit>, <upper_limit>`), yang diterjemahkan ke nilai apa pun `k` yang memenuhi ekspresi berikut: `lower_limit <= k < upper_limit`
  + `r(<lower_limit>, <upper_limit>]`, yang diterjemahkan ke nilai apa pun `k` yang memenuhi ekspresi berikut: `lower_limit < k <= upper_limit`
  + `r(<lower_limit>, <upper_limit>),`yang diterjemahkan ke nilai apa pun `k` yang memenuhi ekspresi berikut: `lower_limit < k < upper_limit`
+ Array asosiatif (peta) untuk data struktur nilai kunci bersarang. Contoh:

  `{ "my-map": { "nested-maps": [ { "key": 10, "value": 20 } ] } }`
+ Array tipe primitif atau tipe array asosiatif
 *Wajib*: Bersyarat; diperlukan ketika operator biner digunakan.

`custom message`  <a name="clauses-properties-custom-message"></a>
String yang memberikan informasi tentang klausa. Pesan ditampilkan dalam output verbose dari `test` perintah `validate` dan dapat berguna untuk memahami atau men-debug evaluasi aturan pada data hierarkis.  
 *Wajib*: Tidak

## Menggunakan kueri dalam klausa
<a name="clauses-queries"></a>

Untuk informasi tentang menulis kueri, lihat [Mendefinisikan kueri dan pemfilteran](query-and-filtering.md) dan[Menetapkan dan mereferensikan variabel dalam aturan Guard](variables.md).

## Menggunakan operator dalam klausa
<a name="clauses-operators"></a>

Berikut ini adalah contoh CloudFormation template, `Template-1` dan`Template-2`. Untuk mendemonstrasikan penggunaan operator yang didukung, contoh kueri dan klausa di bagian ini mengacu pada contoh templat ini.

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

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

### Contoh klausa yang menggunakan operator unary
<a name="clauses-unary-operators"></a>
+ `empty`— Memeriksa apakah koleksi kosong. Anda juga dapat menggunakannya untuk memeriksa apakah kueri memiliki nilai dalam data hierarkis karena kueri menghasilkan koleksi. Anda tidak dapat menggunakannya untuk memeriksa apakah kueri nilai string memiliki string kosong (`""`) yang ditentukan. Untuk informasi selengkapnya, lihat [Mendefinisikan kueri dan pemfilteran](query-and-filtering.md).

  Klausa berikut memeriksa apakah template memiliki satu atau lebih sumber daya yang ditentukan. Ini mengevaluasi `PASS` karena sumber daya dengan ID logis `S3Bucket` didefinisikan dalam`Template-1`.

  ```
  Resources !empty
  ```

  Klausa berikut memeriksa apakah satu atau beberapa tag didefinisikan untuk `S3Bucket` sumber daya. Ini mengevaluasi `PASS` karena `S3Bucket` memiliki dua tag yang didefinisikan untuk `Tags` properti di`Template-1`.

  ```
  Resources.S3Bucket.Properties.Tags !empty
  ```
+ `exists`— Memeriksa apakah setiap kemunculan query memiliki nilai dan dapat digunakan sebagai pengganti`!= null`.

  Klausul berikut memeriksa apakah `BucketEncryption` properti didefinisikan untuk. `S3Bucket` Ini mengevaluasi `PASS` karena `BucketEncryption` didefinisikan untuk `S3Bucket` dalam`Template-1`.

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

**catatan**  
The `empty` and `not exists` checks mengevaluasi `true` untuk kunci properti yang hilang saat melintasi data input. Misalnya, jika `Properties` bagian tidak ditentukan dalam templat untuk`S3Bucket`, klausa akan `Resources.S3Bucket.Properties.Tag empty` dievaluasi. `true` `empty`Pemeriksaan `exists` dan tidak menampilkan jalur penunjuk JSON di dalam dokumen dalam pesan kesalahan. Kedua klausa ini sering memiliki kesalahan pengambilan yang tidak mempertahankan informasi traversal ini.
+ `is_string`— Memeriksa apakah setiap kemunculan kueri adalah `string` tipe.

  Klausa berikut memeriksa apakah nilai string ditentukan untuk `BucketName` properti `S3Bucket` sumber daya. Ini mengevaluasi `PASS` karena nilai string `"MyServiceS3Bucket"` ditentukan untuk `BucketName` in`Template-1`.

  ```
  Resources.S3Bucket.Properties.BucketName is_string
  ```
+ `is_list`— Memeriksa apakah setiap kemunculan kueri adalah `list` tipe.

  Klausa berikut memeriksa apakah daftar ditentukan untuk `Tags` properti `S3Bucket` sumber daya. Ini mengevaluasi `PASS` karena dua pasangan kunci-nilai ditentukan untuk in. `Tags` `Template-1`

  ```
  Resources.S3Bucket.Properties.Tags is_list
  ```
+ `is_struct`— Memeriksa apakah setiap kemunculan kueri adalah data terstruktur.

  Klausa berikut memeriksa apakah data terstruktur ditentukan untuk `BucketEncryption` properti `S3Bucket` sumber daya. Ini mengevaluasi `PASS` karena `BucketEncryption` ditentukan menggunakan tipe `ServerSideEncryptionConfiguration` properti *(object)* di`Template-1`.

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

**catatan**  
Untuk memeriksa keadaan terbalik, Anda dapat menggunakan operator (` not !`) dengan`is_string`,`is_list`, dan `is_struct` operator.

### Contoh klausa yang menggunakan operator biner
<a name="clauses-binary-operators"></a>

Klausa berikut memeriksa apakah nilai yang ditentukan untuk `BucketName` properti `S3Bucket` sumber daya di `Template-1` berisi string`encrypt`, terlepas dari casing. Ini dievaluasi `PASS` karena nama bucket yang ditentukan `"MyServiceS3Bucket"` tidak berisi string`encrypt`.

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

Klausa berikut memeriksa apakah nilai yang ditentukan untuk `Size` properti `NewVolume` sumber daya `Template-2` berada dalam rentang tertentu: 50 <= `Size` <= 200. Ini mengevaluasi `PASS` karena `100` ditentukan untuk`Size`.

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

Klausa berikut memeriksa apakah nilai yang ditentukan untuk `VolumeType` properti `NewVolume` sumber daya di `Template-2` adalah`io1`,`io2`, atau`gp3`. Ini mengevaluasi `PASS` karena `io1` ditentukan untuk`NewVolume`.

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

**catatan**  
Contoh kueri di bagian ini menunjukkan penggunaan operator menggunakan sumber daya dengan logis IDs `S3Bucket` dan`NewVolume`. Nama sumber daya sering kali ditentukan pengguna dan dapat secara sewenang-wenang dinamai dalam templat infrastruktur sebagai kode (IAc). Untuk menulis aturan yang generik dan berlaku untuk semua `AWS::S3::Bucket` sumber daya yang didefinisikan dalam template, bentuk kueri yang paling umum digunakan adalah`Resources.*[ Type == ‘AWS::S3::Bucket’ ]`. Untuk informasi selengkapnya, lihat [Mendefinisikan kueri dan pemfilteran](query-and-filtering.md) detail tentang penggunaan dan jelajahi direktori [examples](https://github.com/aws-cloudformation/cloudformation-guard/tree/main/guard-examples) di `cloudformation-guard` GitHub repositori.

## Menggunakan pesan kustom dalam klausa
<a name="clauses-custom-messages"></a>

Dalam contoh berikut, klausa untuk `Template-2` menyertakan pesan kustom.

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

## Menggabungkan klausa
<a name="combining-clauses"></a>

Di Guard, setiap klausa yang ditulis pada baris baru digabungkan secara implisit dengan klausa berikutnya dengan menggunakan konjungsi (logika Boolean). `and` Lihat contoh berikut ini.

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

Anda juga dapat menggunakan disjungsi untuk menggabungkan klausa dengan klausa berikutnya dengan menentukan `or|OR` di akhir klausa pertama.

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

Dalam klausa Penjaga, disjungsi dievaluasi terlebih dahulu, diikuti oleh konjungsi. Aturan penjaga dapat didefinisikan sebagai gabungan dari disjungsi klausa (an `and|AND` of `or|OR` s) yang mengevaluasi ke () atau `true` (`PASS`). `false` `FAIL` Ini mirip dengan [bentuk normal konjungtif](https://en.wikipedia.org/wiki/Conjunctive_normal_form). 

Contoh-contoh berikut menunjukkan urutan evaluasi klausa.

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

Semua klausa yang didasarkan pada contoh `Template-1` dapat digabungkan dengan menggunakan konjungsi. Lihat contoh berikut ini.

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

## Menggunakan blok dengan aturan Guard
<a name="blocks"></a>

Blok adalah komposisi yang menghilangkan verbositas dan pengulangan dari serangkaian klausa, kondisi, atau aturan terkait. Ada tiga jenis blok:
+ Blok kueri
+ `when`blok
+ Blok aturan bernama

### Blok kueri
<a name="query-blocks"></a>

Berikut ini adalah klausa yang didasarkan pada contoh. `Template-1` Konjungsi digunakan untuk menggabungkan klausa.

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

Bagian dari ekspresi kueri di setiap klausa diulang. Anda dapat meningkatkan kemampuan komposisi dan menghapus verbositas dan pengulangan dari sekumpulan klausa terkait dengan jalur kueri awal yang sama dengan menggunakan blok kueri. Kumpulan klausa yang sama dapat ditulis seperti yang ditunjukkan pada contoh berikut.

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

Dalam blok kueri, kueri sebelum blok menetapkan konteks untuk klausa di dalam blok.

Untuk informasi selengkapnya tentang menggunakan blok, lihat[Menyusun blok aturan bernama](named-rule-block-composition.md).

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

Anda dapat mengevaluasi blok secara kondisional dengan menggunakan `when` blok, yang mengambil formulir berikut.

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

Kata `when` kunci menunjuk awal `when` blok. `condition`adalah aturan penjaga. Blok hanya dievaluasi jika evaluasi kondisi menghasilkan `true` (`PASS`).

Berikut ini adalah contoh `when` blok yang didasarkan pada`Template-1`.

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

Klausa dalam `when` blok hanya dievaluasi jika nilai yang ditentukan untuk `BucketName` adalah string. Jika nilai yang `BucketName` ditentukan untuk direferensikan di `Parameters` bagian template seperti yang ditunjukkan pada contoh berikut, klausa dalam `when` blok tidak dievaluasi.

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

### Blok aturan bernama
<a name="named-rule-blocks"></a>

*Anda dapat menetapkan nama ke seperangkat aturan (kumpulan aturan), dan kemudian mereferensikan blok validasi modular ini, yang disebut blok aturan *bernama, dalam aturan lain*.* Blok aturan bernama mengambil bentuk berikut.

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

`rule`Kata kunci menunjuk awal dari blok aturan bernama.

`rule name`adalah string yang dapat dibaca manusia yang secara unik mengidentifikasi blok aturan bernama. Ini adalah label untuk aturan Guard set yang dienkapsulasi. Dalam penggunaan ini, istilah *aturan Penjaga* mencakup klausa, blok kueri, blok, dan `when` blok aturan bernama. Nama aturan dapat digunakan untuk merujuk pada hasil evaluasi dari kumpulan aturan yang dirangkum, yang membuat blok aturan bernama dapat digunakan kembali. Nama aturan juga menyediakan konteks tentang kegagalan aturan dalam output `validate` dan `test` perintah. Nama aturan ditampilkan bersama dengan status evaluasi blok (`PASS`,`FAIL`, atau`SKIP`) dalam output evaluasi file aturan. Lihat contoh berikut ini.

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

Anda juga dapat mengevaluasi blok aturan bernama secara kondisional dengan menentukan `when` kata kunci diikuti dengan kondisi setelah nama aturan.

Berikut ini adalah contoh `when` blok yang telah dibahas sebelumnya dalam topik ini.

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

Menggunakan blok aturan bernama, yang sebelumnya juga dapat ditulis sebagai berikut.

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

Anda dapat menggunakan kembali dan mengelompokkan blok aturan bernama dengan aturan Penjaga lainnya. Berikut ini adalah beberapa contoh.

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

## Menggunakan fungsi bawaan
<a name="built-in-functions"></a>

AWS CloudFormation Guard menyediakan fungsi bawaan yang dapat Anda gunakan dalam aturan Anda untuk melakukan operasi seperti manipulasi string, penguraian JSON, dan konversi tipe data. Fungsi didukung hanya melalui penugasan ke variabel.

### Fungsi kunci
<a name="key-functions"></a>

`json_parse(json_string)`  
Mem-parsing string JSON sebaris dari template. Setelah parsing, Anda dapat mengevaluasi properti dari objek yang dihasilkan.

`count(collection)`  
Mengembalikan jumlah item yang query menyelesaikan ke.

`regex_replace(base_string, regex_to_extract, regex_replacement)`  
Mengganti bagian dari string menggunakan ekspresi reguler.

Untuk daftar lengkap fungsi yang tersedia termasuk manipulasi string, operasi pengumpulan, dan fungsi konversi tipe data, lihat [dokumentasi Fungsi](https://github.com/aws-cloudformation/cloudformation-guard/blob/main/docs/FUNCTIONS.md) di GitHub repositori Guard.

# Mendefinisikan kueri Guard dan pemfilteran
<a name="query-and-filtering"></a>

Topik ini mencakup penulisan kueri dan menggunakan pemfilteran saat menulis klausa aturan Guard.

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

Penyaringan adalah AWS CloudFormation Guard konsep lanjutan. Kami menyarankan Anda meninjau topik dasar berikut sebelum Anda belajar tentang pemfilteran:
+ [Apa itu AWS CloudFormation Guard?](what-is-guard.md)
+ [Menulis aturan, klausa](writing-rules.md)

## Mendefinisikan kueri
<a name="defining-queries"></a>

Ekspresi kueri adalah ekspresi terpisah dot (`.`) sederhana yang ditulis untuk melintasi data hierarkis. Ekspresi kueri dapat mencakup ekspresi filter untuk menargetkan subset nilai. Ketika kueri dievaluasi, mereka menghasilkan kumpulan nilai, mirip dengan set hasil yang dikembalikan dari kueri SQL.

Contoh query berikut mencari CloudFormation template untuk `AWS::IAM::Role` sumber daya.

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

Pertanyaan mengikuti prinsip-prinsip dasar ini:
+ Setiap titik (`.`) bagian dari kueri melintasi hierarki ketika istilah kunci eksplisit digunakan, seperti `Resources` atau `Properties.Encrypted.` Jika ada bagian dari kueri yang tidak cocok dengan datum yang masuk, Guard akan melempar kesalahan pengambilan.
+ Bagian dot (`.`) dari kueri yang menggunakan wildcard `*` melintasi semua nilai untuk struktur pada tingkat itu.
+ Bagian dot (`.`) dari kueri yang menggunakan wildcard array `[*]` melintasi semua indeks untuk array tersebut.
+ Semua koleksi dapat disaring dengan menentukan filter di dalam tanda kurung siku`[]`. Koleksi dapat ditemukan dengan cara-cara berikut:
  + Array yang terjadi secara alami dalam datum adalah koleksi. Berikut ini adalah contoh:

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

    Tag: `[{"Key": "Stage", "Value": "PROD"}, {"Key": "App", "Value": "MyService"}]`
  + Saat melintasi semua nilai untuk struktur seperti `Resources.*`
  + Setiap hasil kueri itu sendiri merupakan kumpulan dari mana nilai dapat difilter lebih lanjut. Lihat contoh berikut ini.

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

Berikut ini adalah contoh cuplikan CloudFormation template.

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

Berdasarkan template ini, jalur yang dilalui adalah `SampleRole` dan nilai akhir yang dipilih adalah. `Type: AWS::IAM::Role`

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

Nilai yang dihasilkan dari query `Resources.*[ Type == 'AWS::IAM::Role' ]` dalam format YAMAL ditunjukkan dalam contoh berikut.

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

Beberapa cara yang dapat Anda gunakan kueri adalah sebagai berikut:
+ Tetapkan kueri ke variabel sehingga hasil kueri dapat diakses dengan mereferensikan variabel-variabel tersebut.
+ Ikuti kueri dengan blok yang menguji setiap nilai yang dipilih.
+ Bandingkan kueri secara langsung dengan klausa dasar.

## Menetapkan kueri ke variabel
<a name="queries-and-filtering-variables"></a>

Guard mendukung penugasan variabel satu-shot dalam lingkup tertentu. Untuk informasi selengkapnya tentang variabel dalam aturan Guard, lihat[Menetapkan dan mereferensikan variabel dalam aturan Guard](variables.md).

Anda dapat menetapkan kueri ke variabel sehingga Anda dapat menulis kueri sekali dan kemudian mereferensikannya di tempat lain dalam aturan Guard Anda. Lihat contoh penugasan variabel berikut yang menunjukkan prinsip kueri yang dibahas nanti di bagian ini.

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

## Langsung perulangan melalui nilai-nilai dari variabel yang ditugaskan ke kueri
<a name="variable-assigned-from-query"></a>

Guard mendukung langsung berjalan terhadap hasil dari kueri. Dalam contoh berikut, `when` blok menguji terhadap`Encrypted`,`VolumeType`, dan `AvailabilityZone` properti untuk setiap `AWS::EC2::Volume` sumber daya yang ditemukan dalam CloudFormation template.

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

## Perbandingan tingkat klausa langsung
<a name="direct-clause-level-comparisons"></a>

Guard juga mendukung kueri sebagai bagian dari perbandingan langsung. Misalnya, lihat yang berikut ini.

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

Dalam contoh sebelumnya, dua klausa (dimulai dengan `some` kata kunci) yang dinyatakan dalam bentuk yang ditampilkan dianggap klausa independen dan dievaluasi secara terpisah.

### Klausa tunggal dan formulir klausa blok
<a name="single-versus-block-clause-form"></a>

Secara keseluruhan, dua contoh klausa yang ditunjukkan di bagian sebelumnya tidak setara dengan blok berikut.

```
let resources = Resources.*

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

Ini memblokir kueri untuk setiap `Tag` nilai dalam koleksi dan membandingkan nilai propertinya dengan nilai properti yang diharapkan. Bentuk gabungan dari klausa di bagian sebelumnya mengevaluasi dua klausa secara independen. Pertimbangkan masukan berikut.

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

Klausul dalam bentuk pertama mengevaluasi. `PASS` Saat memvalidasi klausa pertama dalam bentuk pertama, jalur berikut melintasi`Resources`,, `Properties``Tags`, dan `Key` cocok dengan nilai `NotPRODEnd` dan tidak cocok dengan nilai yang diharapkan. `PROD`

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

Hal yang sama terjadi dengan klausa kedua dari bentuk pertama. Jalur melintasi`Resources`,, `Properties``Tags`, dan `Value` cocok dengan nilainya`AppStart`. Akibatnya, klausa kedua secara independen.

Hasil keseluruhannya adalah a`PASS`.

Namun, formulir blok mengevaluasi sebagai berikut. Untuk setiap `Tags` nilai, itu membandingkan jika keduanya `Key` dan `Value` tidak cocok; `NotAppStart` dan `NotPRODEnd` nilai tidak cocok dalam contoh berikut.

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

Karena evaluasi memeriksa keduanya`Key == /PROD$/`, dan`Value == /^App/`, pertandingan tidak lengkap. Karena itu, hasilnya adalah`FAIL`.

**catatan**  
Saat bekerja dengan koleksi, kami sarankan Anda menggunakan formulir klausa blok saat Anda ingin membandingkan beberapa nilai untuk setiap elemen dalam koleksi. Gunakan formulir klausa tunggal ketika koleksi adalah sekumpulan nilai skalar, atau ketika Anda hanya bermaksud untuk membandingkan satu atribut.

## Hasil kueri dan klausa terkait
<a name="query-outcomes"></a>

Semua query mengembalikan daftar nilai. Setiap bagian dari traversal, seperti kunci yang hilang, nilai kosong untuk array (`Tags: []`) saat mengakses semua indeks, atau nilai yang hilang untuk peta saat menghadapi map (`Resources: {}`) kosong, dapat menyebabkan kesalahan pengambilan.

Semua kesalahan pengambilan dianggap gagal saat mengevaluasi klausa terhadap kueri tersebut. Satu-satunya pengecualian adalah ketika filter eksplisit digunakan dalam kueri. Saat filter digunakan, klausa terkait dilewati.

Kegagalan blok berikut dikaitkan dengan menjalankan kueri.
+ Jika template tidak berisi sumber daya, maka kueri akan dievaluasi`FAIL`, dan klausa tingkat blok terkait juga mengevaluasi. `FAIL`
+ Ketika template berisi blok sumber daya kosong seperti`{ "Resources": {} }`, kueri akan dievaluasi`FAIL`, dan klausa tingkat blok terkait juga mengevaluasi. `FAIL`
+ Jika template berisi sumber daya tetapi tidak ada yang cocok dengan kueri, maka kueri mengembalikan hasil kosong, dan klausa tingkat blok dilewati.

## Menggunakan filter dalam kueri
<a name="filtering"></a>

Filter dalam kueri secara efektif adalah klausa Penjaga yang digunakan sebagai kriteria pemilihan. Berikut ini adalah struktur klausa.

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

Ingatlah poin-poin penting berikut dari [AWS CloudFormation Guard Aturan penulisan](writing-rules.md) saat Anda bekerja dengan filter:
+ Gabungkan klausa dengan menggunakan [Conjunctive Normal Form (](https://en.wikipedia.org/wiki/Conjunctive_normal_form)CNF).
+ Tentukan setiap klausa konjungsi (`and`) pada baris baru.
+ Tentukan disjunctions (`or`) dengan menggunakan `or` kata kunci antara dua klausa.

Contoh berikut menunjukkan klausa konjungtif dan disjungtif.

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

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

### Menggunakan klausa untuk kriteria seleksi
<a name="selection-criteria"></a>

Anda dapat menerapkan pemfilteran ke koleksi apa pun. Pemfilteran dapat diterapkan langsung pada atribut di input yang sudah menjadi koleksi seperti`securityGroups: [....]`. Anda juga dapat menerapkan pemfilteran terhadap kueri, yang selalu merupakan kumpulan nilai. Anda dapat menggunakan semua fitur klausa, termasuk bentuk normal konjungtif, untuk penyaringan.

Kueri umum berikut sering digunakan saat memilih sumber daya berdasarkan jenis dari CloudFormation template.

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

Query `Resources.*` mengembalikan semua nilai yang ada di `Resources` bagian input. Untuk contoh masukan template di[Mendefinisikan kueri](#defining-queries), query mengembalikan berikut ini.

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

Sekarang, terapkan filter terhadap koleksi ini. Kriteria untuk mencocokkan adalah. `Type == AWS::IAM::Role` Berikut ini adalah output dari query setelah filter diterapkan.

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

Selanjutnya, periksa berbagai klausa untuk `AWS::IAM::Role` sumber daya.

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

Berikut ini adalah contoh query pemfilteran yang memilih semua `AWS::IAM::Policy` dan `AWS::IAM::ManagedPolicy` sumber daya.

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

Contoh berikut memeriksa apakah sumber daya kebijakan ini memiliki yang `PolicyDocument` ditentukan.

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

### Membangun kebutuhan penyaringan yang lebih kompleks
<a name="complex-filtering"></a>

Perhatikan contoh item AWS Config konfigurasi berikut untuk informasi grup keamanan ingress dan egress.

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

Perhatikan hal-hal berikut:
+ `ipPermissions`(aturan ingress) adalah kumpulan aturan di dalam blok konfigurasi.
+ Setiap struktur aturan berisi atribut seperti `ipv4Ranges` dan `ipv6Ranges` untuk menentukan kumpulan blok CIDR.

Mari kita menulis aturan yang memilih aturan masuk apa pun yang memungkinkan koneksi dari alamat IP apa pun, dan memverifikasi bahwa aturan tidak mengizinkan port yang diblokir TCP diekspos.

Mulailah dengan bagian query yang mencakup IPv4, seperti yang ditunjukkan pada contoh berikut.

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

`some`Kata kunci berguna dalam konteks ini. Semua kueri mengembalikan kumpulan nilai yang cocok dengan kueri. Secara default, Guard mengevaluasi bahwa semua nilai yang dikembalikan sebagai hasil dari kueri dicocokkan dengan pemeriksaan. Namun, perilaku ini mungkin tidak selalu menjadi apa yang Anda butuhkan untuk pemeriksaan. Pertimbangkan bagian input berikut dari item konfigurasi.

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

Ada dua nilai yang hadir untuk`ipv4Ranges`. Tidak semua `ipv4Ranges` nilai sama dengan alamat IP yang dilambangkan dengan. `0.0.0.0/0` Anda ingin melihat apakah setidaknya satu nilai cocok`0.0.0.0/0`. Anda memberi tahu Guard bahwa tidak semua hasil yang dikembalikan dari kueri harus cocok, tetapi setidaknya satu hasil harus cocok. `some`Kata kunci memberitahu Guard untuk memastikan bahwa satu atau lebih nilai dari query yang dihasilkan cocok dengan cek. Jika tidak ada nilai hasil kueri yang cocok, Guard akan melempar kesalahan.

Selanjutnya, tambahkan IPv6, seperti yang ditunjukkan pada contoh berikut.

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

Akhirnya, dalam contoh berikut, validasi bahwa protokol tidak`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' ] 
]
```

Berikut ini adalah aturan lengkapnya.

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

        }       
     }
}
```

### Memisahkan koleksi berdasarkan jenis yang terkandung
<a name="splitting-collection"></a>

Saat menggunakan templat konfigurasi infrastruktur sebagai kode (IAc), Anda mungkin menemukan koleksi yang berisi referensi ke entitas lain dalam templat konfigurasi. Berikut ini adalah contoh CloudFormation template yang menjelaskan tugas Amazon Elastic Container Service (Amazon ECS) Container ECS) dengan referensi lokal `TaskRoleArn` ke, referensi `TaskArn` ke, dan referensi string langsung.

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

Pertimbangkan kueri berikut.

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

Query ini mengembalikan koleksi nilai-nilai yang berisi semua tiga `AWS::ECS::TaskDefinition` sumber daya yang ditampilkan dalam contoh template. Pisahkan `ecs_tasks` yang berisi referensi `TaskRoleArn` lokal dari yang lain, seperti yang ditunjukkan pada contoh berikut.

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

# Menetapkan dan mereferensikan variabel dalam aturan Guard
<a name="variables"></a>

Anda dapat menetapkan variabel dalam file AWS CloudFormation Guard aturan untuk menyimpan informasi yang ingin Anda referensikan dalam aturan Guard Anda. Guard mendukung penugasan variabel satu tembakan. Variabel dievaluasi dengan malas, artinya Guard hanya mengevaluasi variabel ketika aturan dijalankan.

**Topics**
+ [Menetapkan variabel](#assigning-variables)
+ [Variabel referensi](#referencing-variables)
+ [Lingkup variabel](#variable-scope)
+ [Contoh variabel dalam file aturan Guard](#variables-examples)

## Menetapkan variabel
<a name="assigning-variables"></a>

Gunakan `let` kata kunci untuk menginisialisasi dan menetapkan variabel. Sebagai praktik terbaik, gunakan kasus ular untuk nama variabel. Variabel dapat menyimpan literal statis atau properti dinamis yang dihasilkan dari kueri. Dalam contoh berikut, variabel `ecs_task_definition_task_role_arn` menyimpan nilai string statis`arn:aws:iam:123456789012:role/my-role-name`.

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

Dalam contoh berikut, variabel `ecs_tasks` menyimpan hasil kueri yang mencari semua `AWS::ECS::TaskDefinition` sumber daya dalam CloudFormation template. Anda dapat merujuk `ecs_tasks` untuk mengakses informasi tentang sumber daya tersebut ketika Anda menulis aturan.

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

## Variabel referensi
<a name="referencing-variables"></a>

Gunakan `%` awalan untuk mereferensikan variabel.

Berdasarkan contoh `ecs_task_definition_task_role_arn` variabel di[Menetapkan variabel](#assigning-variables), Anda dapat referensi `ecs_task_definition_task_role_arn` di `query|value literal` bagian klausa aturan Guard. Menggunakan referensi itu memastikan bahwa nilai yang ditentukan untuk `TaskDefinitionArn` properti sumber `AWS::ECS::TaskDefinition` daya apa pun dalam CloudFormation template adalah nilai string statis`arn:aws:iam:123456789012:role/my-role-name`.

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

Berdasarkan contoh `ecs_tasks` variabel di[Menetapkan variabel](#assigning-variables), Anda dapat mereferensikan `ecs_tasks` dalam kueri (misalnya, %ecs\$1tasks.properties). Pertama, Guard mengevaluasi variabel `ecs_tasks` dan kemudian menggunakan nilai yang dikembalikan untuk melintasi hierarki. Jika variabel `ecs_tasks` menyelesaikan nilai non-string, maka Guard melempar kesalahan.

**catatan**  
Saat ini, Guard tidak mendukung variabel referensi di dalam pesan kesalahan khusus.

## Lingkup variabel
<a name="variable-scope"></a>

Lingkup mengacu pada visibilitas variabel yang didefinisikan dalam file aturan. Sebuah nama variabel hanya dapat digunakan sekali dalam lingkup. Ada tiga tingkat di mana variabel dapat dideklarasikan, atau tiga kemungkinan cakupan variabel:
+ **File-level** — Biasanya dideklarasikan di bagian atas file aturan, Anda dapat menggunakan variabel tingkat file di semua aturan dalam file aturan. Mereka terlihat ke seluruh file.

  Dalam contoh berikut aturan file, variabel `ecs_task_definition_task_role_arn` dan `ecs_task_definition_execution_role_arn` diinisialisasi pada file-tingkat.

  ```
  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
  }
  ```
+ **Rule-level** — Dideklarasikan dalam aturan, variabel tingkat aturan hanya terlihat oleh aturan tertentu. Referensi apa pun di luar aturan menghasilkan kesalahan.

  Dalam contoh berikut aturan file, variabel `ecs_task_definition_task_role_arn` dan `ecs_task_definition_execution_role_arn` diinisialisasi pada aturan-tingkat. Hanya `ecs_task_definition_task_role_arn` dapat direferensikan dalam aturan `check_ecs_task_definition_task_role_arn` bernama. Anda hanya dapat mereferensikan `ecs_task_definition_execution_role_arn` variabel dalam aturan `check_ecs_task_definition_execution_role_arn` bernama.

  ```
  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
  }
  ```
+ **Tingkat blok** — Dideklarasikan dalam blok, seperti `when` klausa, variabel tingkat blok hanya terlihat oleh blok tertentu. Referensi apa pun di luar blok menghasilkan kesalahan.

  Dalam contoh berikut aturan file, variabel `ecs_task_definition_task_role_arn` dan `ecs_task_definition_execution_role_arn` diinisialisasi pada blok-tingkat dalam blok tipe. `AWS::ECS::TaskDefinition` Anda hanya dapat mereferensikan `ecs_task_definition_execution_role_arn` variabel `ecs_task_definition_task_role_arn` dan dalam blok `AWS::ECS::TaskDefinition` tipe untuk aturan masing-masing.

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

## Contoh variabel dalam file aturan Guard
<a name="variables-examples"></a>

Bagian berikut memberikan contoh penugasan variabel statis dan dinamis.

### Penugasan statis
<a name="assigning-static-variables"></a>

Berikut ini adalah contoh CloudFormation template.

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

Berdasarkan template ini, Anda dapat menulis aturan yang disebut `check_ecs_task_definition_task_role_arn` yang memastikan bahwa `TaskRoleArn` properti dari semua sumber daya `AWS::ECS::TaskDefinition` template adalah`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
}
```

Dalam lingkup aturan, Anda dapat menginisialisasi variabel yang dipanggil `ecs_task_definition_task_role_arn` dan menetapkan untuk itu nilai string statis. `'arn:aws:iam::123456789012:role/my-role-name'` Klausa aturan memeriksa apakah nilai yang ditentukan untuk `TaskRoleArn` properti `EcsTask` sumber daya adalah `arn:aws:iam::123456789012:role/my-role-name` dengan mereferensikan `ecs_task_definition_task_role_arn` variabel di bagian tersebut`query|value literal`.

### Penugasan dinamis
<a name="example-dynamic-assignment"></a>

Berikut ini adalah contoh CloudFormation template.

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

Berdasarkan template ini, Anda dapat menginisialisasi variabel yang disebut `ecs_tasks` dalam lingkup file dan menetapkan untuk itu query. `Resources.*[ Type == 'AWS::ECS::TaskDefinition'` Guard menanyakan semua sumber daya dalam template input dan menyimpan informasi tentang mereka di`ecs_tasks`. Anda juga dapat menulis aturan yang disebut `check_ecs_task_definition_task_role_arn` yang memastikan bahwa `TaskRoleArn` properti dari semua sumber daya `AWS::ECS::TaskDefinition` template `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'
}
```

Klausa aturan memeriksa apakah nilai yang ditentukan untuk `TaskRoleArn` properti `EcsTask` sumber daya adalah `arn:aws:iam::123456789012:role/my-role-name` dengan mereferensikan `ecs_task_definition_task_role_arn` variabel di bagian tersebut`query`.

### Menegakkan konfigurasi CloudFormation template
<a name="example-3"></a>

Mari kita telusuri contoh kasus penggunaan produksi yang lebih kompleks. Dalam contoh ini, kami menulis aturan Penjaga untuk memastikan kontrol yang lebih ketat tentang bagaimana tugas Amazon ECS didefinisikan.

Berikut ini adalah contoh CloudFormation template.

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

Berdasarkan template ini, kami menulis aturan berikut untuk memastikan bahwa persyaratan ini terpenuhi:
+ Setiap `AWS::ECS::TaskDefinition` sumber daya dalam template memiliki peran tugas dan peran eksekusi yang dilampirkan.
+ Peran tugas dan peran eksekusi adalah peran AWS Identity and Access Management (IAM).
+ Peran didefinisikan dalam template.
+ `PermissionsBoundary`Properti ditentukan untuk setiap peran.

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

# Menyusun blok aturan bernama di AWS CloudFormation Guard
<a name="named-rule-block-composition"></a>

Saat menulis blok aturan bernama menggunakan AWS CloudFormation Guard, Anda dapat menggunakan dua gaya komposisi berikut:
+ Ketergantungan bersyarat
+ Ketergantungan korelasional

Menggunakan salah satu dari gaya komposisi ketergantungan ini membantu meningkatkan kegunaan kembali dan mengurangi verbositas dan pengulangan dalam blok aturan bernama.

**Topics**
+ [Prasyarat](#named-rules-prerequisites)
+ [Komposisi ketergantungan bersyarat](#named-rules-conditional-dependency)
+ [Komposisi ketergantungan korelasional](#named-rules-correlational-dependency)

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

Pelajari tentang blok aturan bernama dalam aturan [Menulis](writing-rules.md#named-rule-blocks).

## Komposisi ketergantungan bersyarat
<a name="named-rules-conditional-dependency"></a>

Dalam gaya komposisi ini, evaluasi `when` blok atau blok aturan bernama memiliki ketergantungan bersyarat pada hasil evaluasi dari satu atau lebih blok atau klausa aturan bernama lainnya. Contoh berikut file Guard rules berisi blok named-rule yang menunjukkan dependensi kondisional.

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

Dalam contoh file aturan sebelumnya, `Example-1` memiliki hasil yang mungkin sebagai berikut:
+ Jika `rule_name_A` dievaluasi`PASS`, aturan Penjaga yang dienkapsulasi oleh dievaluasi. `rule_name_B`
+ Jika `rule_name_A` dievaluasi`FAIL`, aturan Penjaga yang dienkapsulasi oleh `rule_name_B` tidak dievaluasi. `rule_name_B`mengevaluasi untuk`SKIP`.
+ Jika `rule_name_A` dievaluasi`SKIP`, aturan Penjaga yang dienkapsulasi oleh `rule_name_B` tidak dievaluasi. `rule_name_B`mengevaluasi untuk`SKIP`.
**catatan**  
Kasus ini terjadi jika `rule_name_A` secara kondisional tergantung pada aturan yang mengevaluasi `FAIL` dan menghasilkan `rule_name_A` evaluasi. `SKIP`

Berikut ini adalah contoh item konfigurasi database manajemen konfigurasi (CMDB) dari AWS Config item untuk informasi grup keamanan masuk dan keluar. Contoh ini menunjukkan komposisi ketergantungan bersyarat.

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

Dalam contoh sebelumnya, tergantung secara `check_parameter_validity` kondisional `check_resource_type_and_parameter` dan bergantung pada `check_ip_procotol_and_port_range_validity` kondisional. `check_parameter_validity` Berikut ini adalah item konfigurasi database manajemen konfigurasi (CMDB) yang sesuai dengan aturan sebelumnya.

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

## Komposisi ketergantungan korelasional
<a name="named-rules-correlational-dependency"></a>

Dalam gaya komposisi ini, evaluasi `when` blok atau blok aturan bernama memiliki ketergantungan korelasional pada hasil evaluasi dari satu atau lebih aturan Penjaga lainnya. Ketergantungan korelasional dapat dicapai sebagai berikut.

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

Untuk membantu Anda memahami komposisi ketergantungan korelasional, tinjau contoh berikut dari file aturan 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'
}
```

Dalam file aturan sebelumnya, `ensure_elbs_are_internal_and_secure` memiliki ketergantungan korelasional pada. `ensure_all_elbs_are_secure` Berikut ini adalah contoh CloudFormation template yang sesuai dengan aturan sebelumnya.

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

# Menulis klausa untuk melakukan evaluasi sadar konteks
<a name="context-aware-evaluations"></a>

AWS CloudFormation Guard klausa dievaluasi terhadap data hierarkis. Mesin evaluasi Guard menyelesaikan kueri terhadap data yang masuk dengan mengikuti data hierarkis seperti yang ditentukan, menggunakan notasi putus-putus sederhana. Seringkali, beberapa klausa diperlukan untuk mengevaluasi terhadap peta data atau koleksi. Guard menyediakan sintaks yang nyaman untuk menulis klausa tersebut. Mesin sadar kontekstual dan menggunakan data terkait yang terkait untuk evaluasi.

Berikut ini adalah contoh konfigurasi Kubernetes Pod dengan kontainer, di mana Anda dapat menerapkan evaluasi konteks-sadar.

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

Anda dapat membuat klausa Guard untuk mengevaluasi data ini. Saat mengevaluasi file aturan, konteksnya adalah seluruh dokumen input. Berikut ini adalah contoh klausul yang memvalidasi limit enforcement untuk container yang ditentukan dalam sebuah 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
            >>
        }
    }
}
```

## Pemahaman `context` dalam evaluasi
<a name="context"></a>

Pada tingkat blok aturan, konteks yang masuk adalah dokumen lengkap. Evaluasi untuk `when` kondisi terjadi terhadap konteks root yang masuk ini di mana `kind` atribut `apiVersion` and berada. Dalam contoh sebelumnya, kondisi ini mengevaluasi`true`.

Sekarang, lintasi hierarki yang `spec.containers[*]` ditunjukkan pada contoh sebelumnya. Untuk setiap lintasan hierarki, nilai konteks berubah sesuai dengan itu. Setelah traversal `spec` blok selesai, konteksnya berubah, seperti yang ditunjukkan pada contoh berikut.

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

Setelah melintasi `containers` atribut, konteksnya ditampilkan dalam contoh berikut.

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

## Memahami loop
<a name="loops"></a>

Anda dapat menggunakan ekspresi `[*]` untuk mendefinisikan loop untuk semua nilai yang terkandung dalam array untuk `containers` atribut. Blok dievaluasi untuk setiap elemen di dalamnya`containers`. Dalam cuplikan aturan contoh sebelumnya, klausa yang terkandung di dalam blok menentukan pemeriksaan yang akan divalidasi terhadap definisi kontainer. Blok klausa yang terkandung di dalamnya dievaluasi dua kali, satu kali untuk setiap definisi kontainer.

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

Untuk setiap iterasi, nilai konteks adalah nilai pada indeks yang sesuai.

**catatan**  
Satu-satunya format akses indeks yang didukung adalah `[<integer>]` atau`[*]`. Saat ini, Guard tidak mendukung rentang seperti`[2..4]`.

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

Seringkali di tempat-tempat di mana array diterima, nilai tunggal juga diterima. Misalnya, jika hanya ada satu kontainer, array dapat dijatuhkan dan input berikut diterima.

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

Jika atribut dapat menerima array, pastikan bahwa aturan Anda menggunakan formulir array. Dalam contoh sebelumnya, Anda menggunakan `containers[*]` dan tidak. `containers` Guard mengevaluasi dengan benar saat melintasi data ketika hanya menemukan bentuk nilai tunggal.

**catatan**  
Selalu gunakan formulir array saat mengekspresikan akses untuk klausa aturan ketika atribut menerima array. Guard mengevaluasi dengan benar bahkan dalam kasus bahwa satu nilai digunakan.

## Menggunakan formulir `spec.containers[*]` alih-alih `spec.containers`
<a name="containers"></a>

Kueri penjaga mengembalikan kumpulan nilai yang diselesaikan. Saat Anda menggunakan formulir`spec.containers`, nilai yang diselesaikan untuk kueri berisi array yang dirujuk oleh`containers`, bukan elemen di dalamnya. Ketika Anda menggunakan formulir`spec.containers[*]`, Anda merujuk ke setiap elemen individu yang terkandung. Ingatlah untuk menggunakan `[*]` formulir setiap kali Anda berniat untuk mengevaluasi setiap elemen yang terkandung dalam array.

## Menggunakan `this` untuk mereferensikan nilai konteks saat ini
<a name="this"></a>

Saat Anda membuat aturan Guard, Anda dapat mereferensikan nilai konteks dengan menggunakan`this`. Seringkali`this`, implisit karena terikat pada nilai konteks. Misalnya,`this.apiVersion`,`this.kind`, dan `this.spec` terikat pada root atau dokumen. Sebaliknya, `this.resources` terikat pada setiap nilai untuk`containers`, seperti `/spec/containers/0/` dan`/spec/containers/1`. Demikian pula, `this.cpu` dan `this.memory` memetakan ke batas, secara khusus `/spec/containers/0/resources/limits` dan`/spec/containers/1/resources/limits`. 

Dalam contoh berikutnya, aturan sebelumnya untuk konfigurasi Kubernetes Pod ditulis ulang untuk digunakan secara eksplisit. `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
            >>
        }
    }
}
```

Anda tidak perlu menggunakan secara `this` eksplisit. Namun, `this` referensi dapat berguna saat bekerja dengan skalar, seperti yang ditunjukkan pada contoh berikut.

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

Pada contoh sebelumnya, `this` digunakan untuk merujuk ke setiap nomor port.

## Potensi kesalahan dengan penggunaan implisit `this`
<a name="common-errors"></a>

Saat membuat aturan dan klausa, ada beberapa kesalahan umum saat mereferensikan elemen dari nilai konteks implisit. `this` Misalnya, pertimbangkan datum masukan berikut untuk dievaluasi (ini harus lulus).

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

Ketika diuji terhadap template sebelumnya, aturan berikut menghasilkan kesalahan karena membuat asumsi yang salah untuk memanfaatkan implisit. `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
                >>
            }                
        }
    }
}
```

Untuk menelusuri contoh ini, simpan file aturan sebelumnya dengan nama `any_ip_ingress_check.guard` dan data dengan nama file. `ip_ingress.yaml` Kemudian, jalankan `validate` perintah berikut dengan file-file ini.

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

Dalam output berikut, mesin menunjukkan bahwa usahanya untuk mengambil properti `InputParameters.TcpBlockedPorts[*]` pada nilai`/configuration/ipPermissions/0`, `/configuration/ipPermissions/1` gagal.

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

Untuk membantu memahami hasil ini, tulis ulang aturan menggunakan referensi `this` eksplisit.

```
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`referensi setiap nilai yang terkandung di dalam variabel`any_ip_permissions`. Kueri yang ditetapkan ke variabel memilih `configuration.ipPermissions` nilai yang cocok. Kesalahan menunjukkan upaya untuk mengambil `InputParamaters` dalam konteks ini, tetapi `InputParameters` berada dalam konteks root.

Blok dalam juga mereferensikan variabel yang berada di luar cakupan, seperti yang ditunjukkan pada contoh berikut.

```
{
    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`mengacu pada setiap nilai port di`[21, 22, 110]`, tetapi juga mengacu pada `fromPort` dan`toPort`. Keduanya termasuk dalam lingkup blok luar.

### Menyelesaikan kesalahan dengan penggunaan implisit `this`
<a name="common-errors-resolution"></a>

Gunakan variabel untuk secara eksplisit menetapkan dan mereferensikan nilai. Pertama, `InputParameter.TcpBlockedPorts` adalah bagian dari konteks input (root). Pindah `InputParameter.TcpBlockedPorts` keluar dari blok dalam dan tetapkan secara eksplisit, seperti yang ditunjukkan pada contoh berikut.

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

Kemudian, lihat variabel ini secara eksplisit.

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

Lakukan hal yang sama untuk `this` referensi batin di dalam`%ports`.

Namun, semua kesalahan belum diperbaiki karena loop di dalamnya `ports` masih memiliki referensi yang salah. Contoh berikut menunjukkan penghapusan referensi yang salah.

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

Selanjutnya, jalankan `validate` perintah lagi. Kali ini, berlalu.

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

Berikut ini adalah output dari `validate` perintah.

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

Untuk menguji pendekatan ini untuk kegagalan, contoh berikut menggunakan perubahan 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 berada dalam kisaran 89—109 yang memiliki IPv6 alamat apa pun yang diizinkan. Berikut ini adalah output dari `validate` perintah setelah menjalankannya lagi.

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