テスト AWS CloudFormation Guard ルール - AWS CloudFormation Guard

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

テスト AWS CloudFormation Guard ルール

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

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

前提条件

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

ガードユニットテストファイルの概要

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

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

構文

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

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

プロパティ

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

input

ルールをテストするデータ。次の例に示すように、最初のテストでは空の入力を使用することをお勧めします。

--- - name: MyTest1 input {}

後続のテストでは、テストする入力データを追加します。

必須: はい

expectations

特定のルールが入力データに対して評価された場合に期待される結果。各ルールの期待される結果に加えて、テストする 1 つ以上のルールを指定します。期待される結果は、次のいずれかである必要があります。

  • PASS – 入力データに対して実行すると、ルールは に評価されますtrue

  • FAIL – 入力データに対して実行すると、ルールは に評価されますfalse

  • SKIP – 入力データに対して実行すると、ルールはトリガーされません。

expectations: rules: check_rest_api_is_private: PASS

必須: はい

ガードルールユニットテストファイルの記述のチュートリアル

以下は、 という名前のルールファイルです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
  2. 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
  3. ユニットテストファイルに別のテストを追加します。次に、テストを拡張して空のリソースを含めます。更新された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
  4. 更新されたユニットテストファイル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
  5. ユニットテストファイルにさらに 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
  6. 更新されたユニットテストファイル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
  7. ユニットテストファイルにテスト 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
  8. --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 は引き続き評価を行い、正しい結果を提供しました。

  9. 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
  10. --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) です。組み合わせには 1 つの句 がありますProperties.EndpointConfiguration.Types[*] == "PRIVATE"。したがって、詳細な出力には 1 つの句が表示されます。パスは、入力内のどの値が比較されるか/Resources/apiGw/Properties/EndpointConfiguration/Types/1を示します。この場合、 は 1 でTypesインデックス付けされた 要素です。

ではGuard ルールに対する入力データの検証、このセクションの例を使用して、 validate コマンドを使用して入力データをルールと照合できます。