

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# AWS CloudFormation Guard ルールのテスト
<a name="testing-rules"></a>

組み込みの AWS CloudFormation Guard ユニットテストフレームワークを使用して、Guard ルールが意図したとおりに動作することを確認できます。このセクションでは、ユニットテストファイルを作成する方法と、それを使用して `test` コマンドでルールファイルをテストする方法について説明します。

ユニットテストファイルには、、`.json`、`.JSON`、、`.jsn``.yaml``.YAML`、または のいずれかの拡張子が必要です`.yml`。

**Topics**
+ [前提条件](#testing-rules-prerequisites)
+ [ガードユニットテストファイルの概要](#testing-rules-overview)
+ [ガードルールユニットテストファイルの記述のチュートリアル](#testing-rules-example)

## 前提条件
<a name="testing-rules-prerequisites"></a>

入力データを評価するための Guard ルールを記述します。詳細については、「[ガードルールの記述](writing-rules.md)」を参照してください。

## ガードユニットテストファイルの概要
<a name="testing-rules-overview"></a>

ガードユニットテストファイルは、複数の入力と、ガードルールファイル内に書き込まれたルールの期待される結果を含む JSON 形式または YAML 形式のファイルです。さまざまな期待を評価するためのサンプルが複数ある場合があります。まず空の入力をテストしてから、さまざまなルールと句を評価するための情報を段階的に追加することをお勧めします。

また、サフィックス`_test.json`または を使用してユニットテストファイルに名前を付けることをお勧めします`_tests.yaml`。たとえば、 という名前のルールファイルがある場合は`my_rules.guard`、ユニットテストファイル に名前を付けます`my_rules_tests.yaml`。

### 構文
<a name="testing-rules-syntax"></a>

以下は、YAML 形式のユニットテストファイルの構文を示しています。

```
---
- name: <TEST NAME>
  input:
     <SAMPLE INPUT>
   expectations:
     rules:
       <RULE NAME>: [PASS|FAIL|SKIP]
```

### プロパティ
<a name="testing-rules-properties"></a>

以下は、Guard テストファイルのプロパティです。

`input`  <a name="testing-rules-properties-input"></a>
ルールをテストするデータ。次の例に示すように、最初のテストでは空の入力を使用することをお勧めします。  

```
---
- name: MyTest1
  input {}
```
後続のテストでは、テストする入力データを追加します。  
 *必須:* はい 

`expectations`  <a name="testing-rules-properties-expectations"></a>
特定のルールが入力データに対して評価された場合に期待される結果。各ルールで期待される結果に加えて、テストする 1 つ以上のルールを指定します。期待される結果は、次のいずれかである必要があります。  
+ `PASS` – 入力データに対して実行すると、ルールは に評価されます`true`。
+ `FAIL` – 入力データに対して実行すると、ルールは に評価されます`false`。
+ `SKIP` – 入力データに対して実行すると、ルールはトリガーされません。

```
expectations:
    rules:
      check_rest_api_is_private: PASS
```
 *必須:* はい 

## ガードルールユニットテストファイルの記述のチュートリアル
<a name="testing-rules-example"></a>

以下は、 という名前のルールファイルです`api_gateway_private.guard`。このルールの目的は、CloudFormation テンプレートで定義されたすべての Amazon API Gateway リソースタイプがプライベートアクセス専用にデプロイされているかどうかを確認することです。また、少なくとも 1 つのポリシーステートメントが Virtual Private Cloud (VPC) からのアクセスを許可するかどうかも確認します。

```
#
# Select all AWS::ApiGateway::RestApi resources
#     present in the Resources section of the template. 
#
let api_gws = Resources.*[ Type == 'AWS::ApiGateway::RestApi']

#
# Rule intent:         
# 1) All AWS::ApiGateway::RestApi resources deployed must be private.                                            
# 2) All AWS::ApiGateway::RestApi resources deployed must have at least one AWS Identity and Access Management (IAM) policy condition key to allow access from a VPC.
#
# Expectations:        
# 1) SKIP when there are no AWS::ApiGateway::RestApi resources in the template.  
# 2) PASS when:
#     ALL AWS::ApiGateway::RestApi resources in the template have the EndpointConfiguration property set to Type: PRIVATE. 
#     ALL AWS::ApiGateway::RestApi resources in the template have one IAM condition key specified in the Policy property with aws:sourceVpc or :SourceVpc.    
# 3) FAIL otherwise.                                                                                  
#
#

rule check_rest_api_is_private when %api_gws !empty {      
    %api_gws {
        Properties.EndpointConfiguration.Types[*] == "PRIVATE"                             
    }  
}       

rule check_rest_api_has_vpc_access when check_rest_api_is_private {
    %api_gws {
        Properties {
            #
            # ALL AWS::ApiGateway::RestApi resources in the template have one IAM condition key specified in the Policy property with 
            #     aws:sourceVpc or :SourceVpc
            #           
            some Policy.Statement[*] {
                Condition.*[ keys == /aws:[sS]ource(Vpc|VPC|Vpce|VPCE)/ ] !empty
            }
        }
    }
}
```

このチュートリアルでは、最初のルールインテントをテストします。デプロイされたすべての`AWS::ApiGateway::RestApi`リソースはプライベートである必要があります。

1. 次の初期テスト`api_gateway_private_tests.yaml`を含む というユニットテストファイルを作成します。最初のテストでは、空の入力を追加し、入力として`AWS::ApiGateway::RestApi`リソースがないためルールがスキップ`check_rest_api_is_private`されることを期待します。

   ```
   ---
   - name: MyTest1
     input: {}
     expectations:
       rules:
         check_rest_api_is_private: SKIP
   ```

1. `test` コマンドを使用して、ターミナルで最初のテストを実行します。`--rules-file` パラメータには、ルールファイルを指定します。`--test-data` パラメータには、ユニットテストファイルを指定します。

   ```
   cfn-guard test --rules-file api_gateway_private.guard --test-data api_gateway_private_tests.yaml
   ```

   最初のテストの結果は です`PASS`。

   ```
   Test Case #1
   Name: "MyTest1"
     PASS Rules:
       check_rest_api_is_private: Expected = SKIP, Evaluated = SKIP
   ```

1. ユニットテストファイルに別のテストを追加します。次に、テストを拡張して空のリソースを含めます。更新された`api_gateway_private_tests.yaml`ファイルは次のとおりです。

   ```
   ---
   - name: MyTest1
     input: {}
     expectations:
       rules:
         check_rest_api_is_private: SKIP
   - name: MyTest2
     input:
        Resources: {}
     expectations:
       rules:
         check_rest_api_is_private: SKIP
   ```

1. 更新されたユニットテストファイル`test`を使用して を実行します。

   ```
   cfn-guard test --rules-file api_gateway_private.guard --test-data api_gateway_private_tests.yaml
   ```

   2 番目のテストの結果は です`PASS`。

   ```
   Test Case #1
   Name: "MyTest1"
     PASS Rules:
       check_rest_api_is_private: Expected = SKIP, Evaluated = SKIP
   Test Case #2
   Name: "MyTest2"
     PASS Rules:
       check_rest_api_is_private: Expected = SKIP, Evaluated = SKIP
   ```

1. ユニットテストファイルにさらに 2 つのテストを追加します。テストを拡張して、以下を含めます。
   + プロパティが指定されていない`AWS::ApiGateway::RestApi`リソース。
**注記**  
これは有効な CloudFormation テンプレートではありませんが、不正な形式の入力であってもルールが正しく機能するかどうかをテストすると便利です。

     `EndpointConfiguration` プロパティが指定されていないため、 に設定されていないため、このテストは失敗することが予想されます`PRIVATE`。
   + `EndpointConfiguration` プロパティを に設定して最初のインテントを満たす`PRIVATE`が、ポリシーステートメントが定義されていないため、2 番目のインテントを満たさない `AWS::ApiGateway::RestApi`リソース。このテストは合格すると予想されます。

   更新されたユニットテストファイルを次に示します。

   ```
   ---
   - name: MyTest1
     input: {}
     expectations:
       rules:
         check_rest_api_is_private: SKIP
   - name: MyTest2
     input:
        Resources: {}
     expectations:
       rules:
         check_rest_api_is_private: SKIP
   - name: MyTest3
     input:
       Resources: 
         apiGw:
           Type: AWS::ApiGateway::RestApi
     expectations:
       rules:
         check_rest_api_is_private: FAIL
   - name: MyTest4
     input:
       Resources: 
         apiGw:
           Type: AWS::ApiGateway::RestApi
           Properties:
             EndpointConfiguration:
               Types: "PRIVATE"
     expectations:
       rules:
         check_rest_api_is_private: PASS
   ```

1. 更新されたユニットテストファイル`test`を使用して を実行します。

   ```
   cfn-guard test --rules-file api_gateway_private.guard --test-data api_gateway_private_tests.yaml \
   ```

   3 番目の結果は で`FAIL`、4 番目の結果は です`PASS`。

   ```
   Test Case #1
   Name: "MyTest1"
     PASS Rules:
       check_rest_api_is_private: Expected = SKIP, Evaluated = SKIP
   
   Test Case #2
   Name: "MyTest2"
     PASS Rules:
       check_rest_api_is_private: Expected = SKIP, Evaluated = SKIP
   
   Test Case #3
   Name: "MyTest3"
     PASS Rules:
       check_rest_api_is_private: Expected = FAIL, Evaluated = FAIL
   
   Test Case #4
   Name: "MyTest4"
     PASS Rules:
       check_rest_api_is_private: Expected = PASS, Evaluated = PASS
   ```

1. ユニットテストファイルでテスト 1～3 をコメントアウトします。4 番目のテストのみの詳細コンテキストにアクセスします。更新されたユニットテストファイルを次に示します。

   ```
   ---
   #- name: MyTest1
   #  input: {}
   #  expectations:
   #    rules:
   #      check_rest_api_is_private_and_has_access: SKIP
   #- name: MyTest2
   #  input:
   #     Resources: {}
   #  expectations:
   #    rules:
   #      check_rest_api_is_private_and_has_access: SKIP
   #- name: MyTest3
   #  input:
   #    Resources: 
   #      apiGw:
   #        Type: AWS::ApiGateway::RestApi
   #  expectations:
   #    rules:
   #      check_rest_api_is_private_and_has_access: FAIL
   - name: MyTest4
     input:
       Resources: 
         apiGw:
           Type: AWS::ApiGateway::RestApi
           Properties:
             EndpointConfiguration:
               Types: "PRIVATE"
     expectations:
       rules:
         check_rest_api_is_private: PASS
   ```

1. 評価結果を確認するには、 `--verbose`フラグを使用してターミナルで `test` コマンドを実行します。詳細なコンテキストは、評価を理解するのに役立ちます。この場合、4 番目のテストが`PASS`結果で成功した理由に関する詳細情報を提供します。

   ```
   cfn-guard test --rules-file api_gateway_private.guard --test-data api_gateway_private_tests.yaml \
     --verbose
   ```

   以下は、その実行からの出力です。

   ```
   Test Case #1
   Name: "MyTest4"
     PASS Rules:
       check_rest_api_is_private: Expected = PASS, Evaluated = PASS
   Rule(check_rest_api_is_private, PASS)
       |  Message: DEFAULT MESSAGE(PASS)
       Condition(check_rest_api_is_private, PASS)
           |  Message: DEFAULT MESSAGE(PASS)
           Clause(Clause(Location[file:api_gateway_private.guard, line:20, column:37], Check: %api_gws NOT EMPTY ), PASS)
               |  From: Map((Path("/Resources/apiGw"), MapValue { keys: [String((Path("/Resources/apiGw/Type"), "Type")), String((Path("/Resources/apiGw/Properties"), "Properties"))], values: {"Type": String((Path("/Resources/apiGw/Type"), "AWS::ApiGateway::RestApi")), "Properties": Map((Path("/Resources/apiGw/Properties"), MapValue { keys: [String((Path("/Resources/apiGw/Properties/EndpointConfiguration"), "EndpointConfiguration"))], values: {"EndpointConfiguration": Map((Path("/Resources/apiGw/Properties/EndpointConfiguration"), MapValue { keys: [String((Path("/Resources/apiGw/Properties/EndpointConfiguration/Types"), "Types"))], values: {"Types": String((Path("/Resources/apiGw/Properties/EndpointConfiguration/Types"), "PRIVATE"))} }))} }))} }))
               |  Message: (DEFAULT: NO_MESSAGE)
       Conjunction(cfn_guard::rules::exprs::GuardClause, PASS)
           |  Message: DEFAULT MESSAGE(PASS)
           Clause(Clause(Location[file:api_gateway_private.guard, line:22, column:5], Check: Properties.EndpointConfiguration.Types[*]  EQUALS String("PRIVATE")), PASS)
               |  Message: (DEFAULT: NO_MESSAGE)
   ```

   出力からのキー観測値は`Clause(Location[file:api_gateway_private.guard, line:22, column:5], Check: Properties.EndpointConfiguration.Types[*] EQUALS String("PRIVATE")), PASS)`、チェックに合格したことを示す行 です。この例では、 `Types`が配列であると予想されるが、単一の値が指定されたケースも示しました。この場合、Guard は引き続き評価を行い、正しい結果を提供しました。

1. 4 番目のテストケースのようなテストケースを、 `EndpointConfiguration`プロパティが指定された `AWS::ApiGateway::RestApi`リソースのユニットテストファイルに追加します。テストケースは合格ではなく失敗します。更新されたユニットテストファイルを次に示します。

   ```
   ---
   #- name: MyTest1
   #  input: {}
   #  expectations:
   #    rules:
   #      check_rest_api_is_private_and_has_access: SKIP
   #- name: MyTest2
   #  input:
   #     Resources: {}
   #  expectations:
   #    rules:
   #      check_rest_api_is_private_and_has_access: SKIP
   #- name: MyTest3
   #  input:
   #    Resources: 
   #      apiGw:
   #        Type: AWS::ApiGateway::RestApi
   #  expectations:
   #    rules:
   #      check_rest_api_is_private_and_has_access: FAIL
   #- name: MyTest4
   #  input:
   #    Resources: 
   #      apiGw:
   #        Type: AWS::ApiGateway::RestApi
   #        Properties:
   #          EndpointConfiguration:
   #            Types: "PRIVATE"
   #  expectations:
   #    rules:
   #      check_rest_api_is_private: PASS
   - name: MyTest5
     input:
       Resources: 
         apiGw:
           Type: AWS::ApiGateway::RestApi
           Properties:
             EndpointConfiguration:
               Types: [PRIVATE, REGIONAL]
     expectations:
       rules:
         check_rest_api_is_private: FAIL
   ```

1. `--verbose` フラグを使用して、更新されたユニットテストファイルで `test` コマンドを実行します。

   ```
   cfn-guard test --rules-file api_gateway_private.guard --test-data api_gateway_private_tests.yaml \
    --verbose
   ```

   は に指定されている`EndpointConfiguration`が、 は想定されていないため`REGIONAL`、結果は想定`FAIL`どおりです。

   ```
   Test Case #1
   Name: "MyTest5"
     PASS Rules: 
       check_rest_api_is_private: Expected = FAIL, Evaluated = FAIL
   Rule(check_rest_api_is_private, FAIL)
       |  Message: DEFAULT MESSAGE(FAIL)
       Condition(check_rest_api_is_private, PASS) 
           |  Message: DEFAULT MESSAGE(PASS)
           Clause(Clause(Location[file:api_gateway_private.guard, line:20, column:37], Check: %api_gws NOT EMPTY ), PASS)
               |  From: Map((Path("/Resources/apiGw"), MapValue { keys: [String((Path("/Resources/apiGw/Type"), "Type")), String((Path("/Resources/apiGw/Properties"), "Properties"))], values: {"Type": String((Path("/Resources/apiGw/Type"), "AWS::ApiGateway::RestApi")), "Properties": Map((Path("/Resources/apiGw/Properties"), MapValue { keys: [String((Path("/Resources/apiGw/Properties/EndpointConfiguration"), "EndpointConfiguration"))], values: {"EndpointConfiguration": Map((Path("/Resources/apiGw/Properties/EndpointConfiguration"), MapValue { keys: [String((Path("/Resources/apiGw/Properties/EndpointConfiguration/Types"), "Types"))], values: {"Types": List((Path("/Resources/apiGw/Properties/EndpointConfiguration/Types"), [String((Path("/Resources/apiGw/Properties/EndpointConfiguration/Types/0"), "PRIVATE")), String((Path("/Resources/apiGw/Properties/EndpointConfiguration/Types/1"), "REGIONAL"))]))} }))} }))} }))
               |  Message: DEFAULT MESSAGE(PASS)
       BlockClause(Block[Location[file:api_gateway_private.guard, line:21, column:3]], FAIL)
           |  Message: DEFAULT MESSAGE(FAIL)
           Conjunction(cfn_guard::rules::exprs::GuardClause, FAIL)
               |  Message: DEFAULT MESSAGE(FAIL)
               Clause(Clause(Location[file:api_gateway_private.guard, line:22, column:5], Check: Properties.EndpointConfiguration.Types[*]  EQUALS String("PRIVATE")), FAIL)
                   |  From: String((Path("/Resources/apiGw/Properties/EndpointConfiguration/Types/1"), "REGIONAL"))
                   |  To: String((Path("api_gateway_private.guard/22/5/Clause/"), "PRIVATE"))
                   |  Message: (DEFAULT: NO_MESSAGE)
   ```

   `test` コマンドの詳細出力は、ルールファイルの構造に従います。ルールファイル内のすべてのブロックは、詳細出力のブロックです。一番上のブロックは各ルールです。ルールに`when`条件がある場合は、兄弟条件ブロックに表示されます。次の例では、 条件`%api_gws !empty`がテストされ、合格します。

   ```
   rule check_rest_api_is_private when %api_gws !empty {
   ```

   条件が成功したら、ルール句をテストします。

   ```
   %api_gws {
       Properties.EndpointConfiguration.Types[*] == "PRIVATE"                      
   }
   ```

   `%api_gws` は、出力`BlockClause`のレベル (line:21) に対応するブロックルールです。ルール句は、連結 (AND) 句のセットであり、各連結句は一連の差分 (`OR`s) です。連結には 1 つの句 があります`Properties.EndpointConfiguration.Types[*] == "PRIVATE"`。したがって、詳細出力には 1 つの句が表示されます。パスは、入力内のどの値が比較されるか`/Resources/apiGw/Properties/EndpointConfiguration/Types/1`を示します。この場合、 は 1 で`Types`インデックス付けされた の 要素です。

では[Guard ルールに対する入力データの検証](validating-rules.md)、このセクションの例を使用して、 `validate` コマンドを使用して入力データをルールに対して評価できます。