

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 撰寫 AWS CloudFormation Guard 規則
<a name="writing-rules"></a>

在 中 AWS CloudFormation Guard，*規則*是policy-as-code規則。您可以使用 Guard 網域特定語言 (DSL) 撰寫規則，以驗證 JSON 或 YAML 格式的資料。規則由 *子句*組成。

您可以將使用 Guard DSL 寫入的規則儲存到使用任何副檔名的純文字檔案中。

您可以建立多個規則檔案，並將其分類為*規則集*。規則集可讓您同時針對多個規則檔案驗證 JSON 或 YAML 格式的資料。

**Topics**
+ [子句](#clauses)
+ [在 子句中使用查詢](#clauses-queries)
+ [在 子句中使用運算子](#clauses-operators)
+ [在 子句中使用自訂訊息](#clauses-custom-messages)
+ [合併子句](#combining-clauses)
+ [搭配 Guard 規則使用區塊](#blocks)
+ [使用內建函數](#built-in-functions)
+ [定義 Guard 查詢和篩選](query-and-filtering.md)
+ [在 Guard 規則中指派和參考變數](variables.md)
+ [在 中編寫具名規則區塊 AWS CloudFormation Guard](named-rule-block-composition.md)
+ [撰寫 子句以執行內容感知評估](context-aware-evaluations.md)

## 子句
<a name="clauses"></a>

子句是評估為 true (`PASS`) 或 false () 的布林表達式`FAIL`。子句使用二進位運算子來比較在單一值上操作的兩個值或單一運算子。

**Unary 子句的範例**

下列 unary 子句會評估集合是否為`TcpBlockedPorts`空。

```
InputParameters.TcpBlockedPorts not empty
```

下列 unary 子句會評估 `ExecutionRoleArn` 屬性是否為字串。

```
Properties.ExecutionRoleArn is_string
```

**二進位子句的範例**

下列二進位子句會評估 `BucketName` 屬性是否包含字串 `encrypted`，無論大小寫為何。

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

下列二進位子句會評估 `ReadCapacityUnits` 屬性是否小於或等於 5，000。

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

### 撰寫 Guard 規則子句的語法
<a name="clauses-syntax"></a>

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

### Guard 規則子句的屬性
<a name="clauses-properties"></a>

`query`  <a name="clauses-properties-query"></a>
以點 (`.`) 分隔的表達式，寫入以周遊階層資料。查詢表達式可以包含篩選條件表達式，以值的子集為目標。您可以將查詢指派給變數，以便您可以寫入它們一次，並在規則集中的其他位置參考它們，這可讓您存取查詢結果。  
如需撰寫查詢和篩選的詳細資訊，請參閱 [定義查詢和篩選](query-and-filtering.md)。  
 *必要*：是

`operator`  <a name="clauses-properties-operator"></a>
單一或二進位運算子，可協助檢查查詢的狀態。二進位運算子的左側 (LHS) 必須是查詢，而右側 (RHS) 必須是查詢或值常值。  
 *支援的二進位運算子*：`==`（等於） \| `!=` （不等於） \| `>`（大於） \| `>=`（大於或等於） \| `<`（小於） \| `<=`（小於或等於） \| `IN`（在形式 【x、y、z】 的清單中  
 *支援的 unary 運算子*： `exists` \| `empty` \| `is_string` \| `is_list` \| `is_struct` \| `not(!)`  
 *必要*：是

`query|value literal`  <a name="clauses-properties-value-literal"></a>
查詢或支援的值常值，例如 `string`或 `integer(64)`。  
*支援的值常值*：  
+ 所有基本類型：`string`、`integer(64)`、`float(64)`、`bool`、`char`、 `regex`
+ 表達 `integer(64)`、 `float(64)`或 範圍的所有專用`char`範圍類型，表示為：
  + `r[<lower_limit>, <upper_limit>]`，其會轉譯為滿足下列表達`k`式的任何值： `lower_limit <= k <= upper_limit`
  + `r[<lower_limit>, <upper_limit>`)`k`，其會轉譯為滿足下列表達式的任何值： `lower_limit <= k < upper_limit`
  + `r(<lower_limit>, <upper_limit>]`，其會轉譯為滿足下列表達`k`式的任何值： `lower_limit < k <= upper_limit`
  + `r(<lower_limit>, <upper_limit>),` 可轉換為滿足下列表達`k`式的任何值： `lower_limit < k < upper_limit`
+ 巢狀索引鍵/值結構資料的關聯陣列 （對應）。例如：

  `{ "my-map": { "nested-maps": [ { "key": 10, "value": 20 } ] } }`
+ 基本類型或關聯陣列類型的陣列
 *必要*：有條件；使用二進位運算子時為必要。

`custom message`  <a name="clauses-properties-custom-message"></a>
提供 子句相關資訊的字串。訊息會顯示在 `validate`和 `test`命令的詳細輸出中，有助於了解或偵錯階層資料上的規則評估。  
 *必要*：否

## 在 子句中使用查詢
<a name="clauses-queries"></a>

如需撰寫查詢的資訊，請參閱 [定義查詢和篩選](query-and-filtering.md)和 [在 Guard 規則中指派和參考變數](variables.md)。

## 在 子句中使用運算子
<a name="clauses-operators"></a>

以下是 CloudFormation 範本`Template-1`和 的範例`Template-2`。為了示範如何使用支援的運算子，本節中的範例查詢和子句會參考這些範例範本。

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

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

### 使用 unary 運算子的子句範例
<a name="clauses-unary-operators"></a>
+ `empty` – 檢查集合是否為空。您也可以使用它來檢查查詢在階層資料中是否有值，因為查詢會導致集合。您無法使用它來檢查字串值查詢是否已定義空字串 (`""`)。如需詳細資訊，請參閱[定義查詢和篩選](query-and-filtering.md)。

  下列子句會檢查範本是否已定義一或多個資源。它評估為 ，`PASS`因為具有邏輯 ID 的資源`S3Bucket`是在 中定義`Template-1`。

  ```
  Resources !empty
  ```

  下列子句會檢查是否為`S3Bucket`資源定義一或多個標籤。它會評估 為 ，`PASS`因為 中`S3Bucket`有兩個為 `Tags` 屬性定義的標籤`Template-1`。

  ```
  Resources.S3Bucket.Properties.Tags !empty
  ```
+ `exists` – 檢查每個查詢的出現是否具有值，並可用於取代 `!= null`。

  下列子句會檢查是否已為 定義 `BucketEncryption` 屬性`S3Bucket`。它評估為 ，`PASS`因為 `BucketEncryption` 是在 `S3Bucket`中為 定義的`Template-1`。

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

**注意**  
`empty` 和 `not exists`檢查會在周遊輸入資料時評估 `true` 是否遺失屬性索引鍵。例如，如果未在 的範本中定義 `Properties`區段`S3Bucket`，則 子句會`Resources.S3Bucket.Properties.Tag empty`評估為 `true`。`exists` 和 `empty`檢查不會在錯誤訊息中顯示文件內的 JSON 指標路徑。這兩個子句通常都有無法維護此周遊資訊的擷取錯誤。
+ `is_string` – 檢查查詢的每個出現是否為 `string`類型。

  下列子句會檢查是否為 `S3Bucket` 資源的 `BucketName` 屬性指定字串值。它會評估 為 ，`PASS`因為字串值`"MyServiceS3Bucket"`是在 `BucketName`中為 指定的`Template-1`。

  ```
  Resources.S3Bucket.Properties.BucketName is_string
  ```
+ `is_list` – 檢查查詢的每個出現是否為 `list`類型。

  下列子句會檢查是否為 `S3Bucket` 資源的 `Tags` 屬性指定清單。它評估為 ，`PASS`因為在 `Tags`中為 指定了兩個鍵值對`Template-1`。

  ```
  Resources.S3Bucket.Properties.Tags is_list
  ```
+ `is_struct` – 檢查查詢是否每次出現都是結構化資料。

  下列子句會檢查是否為 `S3Bucket` 資源的 `BucketEncryption` 屬性指定結構化資料。它會評估 為 ，`PASS`因為 `BucketEncryption` 是使用 中的`ServerSideEncryptionConfiguration`屬性類型 {{（物件）}} 指定`Template-1`。

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

**注意**  
若要檢查反轉狀態，您可以使用 (` not !`) 運算子搭配 `is_string`、 `is_list`和 `is_struct`運算子 。

### 使用二進位運算子的子句範例
<a name="clauses-binary-operators"></a>

下列子句會檢查 中`S3Bucket`資源`BucketName`屬性指定的值是否`Template-1`包含字串 `encrypt`，無論大小寫為何。這會評估 ，`PASS`因為指定的儲存貯體名稱`"MyServiceS3Bucket"`不包含字串 `encrypt`。

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

下列子句會檢查 中`NewVolume`資源`Size`屬性指定的值是否`Template-2`在特定範圍內：50 <= `Size` <= 200。它會評估 為 ，`PASS`因為 `100` 是針對 所指定`Size`。

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

下列子句會檢查 中`NewVolume`資源`VolumeType`屬性指定的值是否為 `Template-2` `io1`、 `io2`或 `gp3`。它會評估 為 ，`PASS`因為 `io1` 是針對 所指定`NewVolume`。

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

**注意**  
本節中的範例查詢示範使用具有邏輯 IDs `S3Bucket`和 的資源來使用運算子`NewVolume`。資源名稱通常是使用者定義的，並且可以在基礎設施中任意命名為程式碼 (IaC) 範本。若要撰寫一般規則並套用至範本中定義的所有`AWS::S3::Bucket`資源，最常使用的查詢形式是 `Resources.*[ Type == ‘AWS::S3::Bucket’ ]`。如需詳細資訊，請參閱 [定義查詢和篩選](query-and-filtering.md) 以取得用量的詳細資訊，並探索 `cloudformation-guard` GitHub 儲存庫中[的範例](https://github.com/aws-cloudformation/cloudformation-guard/tree/main/guard-examples)目錄。

## 在 子句中使用自訂訊息
<a name="clauses-custom-messages"></a>

在下列範例中， 的 子句`Template-2`包含自訂訊息。

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

## 合併子句
<a name="combining-clauses"></a>

在 Guard 中，在新行上寫入的每個子句會使用 結合 （布林`and`邏輯） 隱含地與下一個子句結合。請參閱以下範例。

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

您也可以透過`or|OR`在第一個子句結尾指定 ，使用 解散來結合子句與下一個子句。

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

在 Guard 子句中，會先評估接合點，接著評估接合點。Guard 規則可以定義為將評估為 (`PASS`) 或 `true`() 的 子句 `false`( `or|OR``and|AND`的 ) 解譯的組合`FAIL`。這類似於 [Conjunctive 正常形式](https://en.wikipedia.org/wiki/Conjunctive_normal_form)。

下列範例示範 子句的評估順序。

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

所有以範例為基礎的子句`Template-1`都可以使用 結合來合併。請參閱以下範例。

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

## 搭配 Guard 規則使用區塊
<a name="blocks"></a>

區塊是從一組相關子句、條件或規則中移除詳細程度和重複性的組合。區塊有三種類型：
+ 查詢區塊
+ `when` 區塊
+ 具名規則區塊

### 查詢區塊
<a name="query-blocks"></a>

以下是以範例 為基礎的 子句`Template-1`。結合用於結合 子句。

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

每個子句中的查詢表達式部分都會重複。您可以使用查詢區塊，改善可編譯性，並從具有相同初始查詢路徑的一組相關子句中移除詳細程度和重複性。可以寫入同一組子句，如下列範例所示。

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

在查詢區塊中，區塊前面的查詢會設定區塊內子句的內容。

如需使用區塊的詳細資訊，請參閱 [編寫具名規則區塊](named-rule-block-composition.md)。

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

您可以使用採用下列格式的區塊來有條件地評估`when`區塊。

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

`when` 關鍵字會指定`when`區塊的開頭。 `condition` 是 Guard 規則。只有在條件的評估結果為 `true`() 時，才會評估 區塊`PASS`。

以下是以 為基礎的範例`when`區塊`Template-1`。

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

只有在為 指定的值`BucketName`是字串時，才會評估`when`區塊中的 子句。如果在範本的 `Parameters`區段中參考為 `BucketName` 指定的值，如下列範例所示，則不會評估`when`區塊中的 子句。

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

### 具名規則區塊
<a name="named-rule-blocks"></a>

您可以將名稱指派給一組規則 (*規則集*)，然後在其他規則中參考這些模組化驗證區塊，稱為*命名規則區塊*。命名規則區塊採用下列形式。

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

`rule` 關鍵字會指定 name-rule 區塊的開頭。

`rule name` 是人類可讀取的字串，可唯一識別具名規則區塊。這是其封裝的 Guard 規則集的標籤。在此使用中，*Guard 規則*一詞包含子句、查詢區塊、`when`區塊和命名規則區塊。規則名稱可用來參考其封裝的規則集評估結果，這使得命名規則區塊可重複使用。規則名稱也提供 `validate`和 `test`命令輸出中規則失敗的相關內容。規則名稱會與區塊的評估狀態 (`PASS`、 `FAIL`或 `SKIP`) 一起顯示在規則檔案的評估輸出中。請參閱以下範例。

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

您也可以在規則名稱後面指定`when`關鍵字後面接著條件，以有條件的方式評估具名規則區塊。

以下是本主題先前討論的範例`when`區塊。

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

使用具名規則區塊，上述也可以編寫如下。

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

您可以使用其他 Guard 規則重複使用並分組具名規則區塊。以下是幾個範例。

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

## 使用內建函數
<a name="built-in-functions"></a>

AWS CloudFormation Guard 提供內建函數，您可以在規則中用來執行字串操作、JSON 剖析和資料類型轉換等操作。函式僅透過指派至變數來支援。

### 關鍵函數
<a name="key-functions"></a>

`json_parse(json_string)`  
從範本剖析內嵌 JSON 字串。剖析之後，您可以評估所產生物件的屬性。

`count(collection)`  
傳回查詢解析的項目數量。

`regex_replace(base_string, regex_to_extract, regex_replacement)`  
使用規則表達式取代字串的一部分。

如需可用函數的完整清單，包括字串操作、集合操作和資料類型轉換函數，請參閱 Guard GitHub 儲存庫中的[函數文件](https://github.com/aws-cloudformation/cloudformation-guard/blob/main/docs/FUNCTIONS.md)。