

# Lambda 関数とレイヤーのガバナンス戦略を作成する
<a name="governance-concepts"></a>

サーバーレスのクラウドネイティブアプリケーションを構築してデプロイするには、適切なガバナンスとガードレールを備えた俊敏性と市場投入までのスピードを考慮する必要があります。ビジネスレベルの優先事項を設定し、最優先事項として俊敏性を重視したり、ガバナンス、ガードレール、統制によるリスク回避を重視したりします。現実的には、「二者択一」戦略ではなく、ソフトウェア開発ライフサイクルにおけるアジリティとガードレールの両方のバランスを取る「両立」戦略を採用することになります。これらの要件が会社のライフサイクルのどの段階にあっても、ガバナンス機能はプロセスやツールチェーンの実装要件になる可能性が高くなります。

組織が Lambda に実装する可能性のあるガバナンスコントロールの例をいくつか紹介します。
+ Lambda 関数へのパブリックアクセスを許可してはなりません。
+ Lambda 関数は VPC にアタッチされている必要があります。
+ Lambda 関数では非推奨のランタイムを使用してはなりません。
+ Lambda 関数は、必要なタグのセットでタグ付けする必要があります。
+ Lambda レイヤーは組織の外部からアクセスできないようにする必要があります。
+ セキュリティグループがアタッチされている Lambda 関数では、関数とセキュリティグループのタグが一致している必要があります。
+ レイヤーがアタッチされた Lambda 関数は承認されたバージョンを使用する必要があります
+ Lambda 環境変数は、カスタマーマネージド型キーを使用して保存時に暗号化する必要があります。

次の図は、ソフトウェアの開発とデプロイのプロセス全体にわたってコントロールとポリシーを実装する詳細なガバナンス戦略の例です。

 ![\[Governance strategy that uses AWS CloudFormation Guard, AWS Config, and Amazon Inspector.\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-concepts.png) 

以下のトピックでは、スタートアップとエンタープライズの両方を対象に、組織で Lambda 関数を開発およびデプロイするためのコントロールを実装する方法について説明します。組織でツールが設定済みである場合があります。以下のトピックでは、これらのコントロールをモジュール方式で行うため、実際に必要なコンポーネントを自由に選択できます。

**Topics**
+ [AWS CloudFormation Guard による Lambda のプロアクティブコントロール](governance-cloudformation-guard.md)
+ [AWS Config を使用して Lambda の予防的コントロールを実装する](governance-config.md)
+ [AWS Config を使用して非準拠の Lambda デプロイと設定を検出する](governance-config-detection.md)
+ [AWS Signer で Lambda コード署名を行う](governance-code-signing.md)
+ [Amazon Inspector を使用して Lambda のセキュリティ評価を自動化する](governance-code-scanning.md)
+ [Lambda のセキュリティとコンプライアンスのためのオブザーバビリティの実装](governance-observability.md)

# AWS CloudFormation Guard による Lambda のプロアクティブコントロール
<a name="governance-cloudformation-guard"></a>

[AWS CloudFormation Guard](https://docs.aws.amazon.com/cfn-guard/latest/ug/what-is-guard.html) は、オープンソースの汎用ポリシーアズコード評価ツールです。Infrastructure as Code (IaC) テンプレートとサービス構成をポリシールールに照らして検証することで、ガバナンスとコンプライアンスの予防を行えます。これらのルールは、チームや組織の要件に基づいてカスタマイズできます。Lambda 関数の場合、Lambda 関数の作成または更新時に必要なプロパティ設定を定義することで、Guard ルールを使用してリソースの作成と設定の更新を制御できます。

コンプライアンス管理者は、Lambda 関数のデプロイと更新に必要なコントロールとガバナンスポリシーのリストを定義します。プラットフォーム管理者は、コードリポジトリを備えたコミット前の検証 Webhook として CI/CD パイプラインにコントロールを実装し、ローカルワークステーションでテンプレートとコードを検証するためのコマンドラインツールを開発者に提供します。開発者はコードを作成し、コマンドラインツールでテンプレートを検証し、コードをリポジトリにコミットします。リポジトリは、AWS 環境へのデプロイ前に CI/CD パイプラインを介して自動的に検証されます。

Guard では、以下のようにドメイン固有の言語を使用して[ルールを記述](https://docs.aws.amazon.com/cfn-guard/latest/ug/writing-rules.html)し、コントロールを実装できます。

 ![\[Guard rules include resource type, property name, operator, expression value, and optional comment\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-cloudformation-guard.png) 

例えば、開発者が必ず最新のランタイムのみを選択するように指定するとします。2 つの異なるポリシーを指定できます。1 つは廃止済みの[ランタイム](lambda-runtimes.md)を識別するためのもので、もう 1 つは間もなく廃止されるランタイムを識別するためのものです。これを行うには、以下の `etc/rules.guard` ファイルを記述します。

```
let lambda_functions = Resources.*[
    Type == "AWS::Lambda::Function"
]

rule lambda_already_deprecated_runtime when %lambda_functions !empty {
    %lambda_functions {
        Properties {
            when Runtime exists {
                Runtime !in ["dotnetcore3.1", "nodejs12.x", "python3.6", "python2.7", "dotnet5.0", "dotnetcore2.1", "ruby2.5", "nodejs10.x", "nodejs8.10", "nodejs4.3", "nodejs6.10", "dotnetcore1.0", "dotnetcore2.0", "nodejs4.3-edge", "nodejs"] <<Lambda function is using a deprecated runtime.>>
            }
        }
    }
}

rule lambda_soon_to_be_deprecated_runtime when %lambda_functions !empty {
    %lambda_functions {
        Properties {
            when Runtime exists {
                Runtime !in ["nodejs16.x", "nodejs14.x", "python3.7", "java8", "dotnet7", "go1.x", "ruby2.7", "provided"] <<Lambda function is using a runtime that is targeted for deprecation.>>
            }
        }
    }
}
```

ここで、Lambda 関数を定義する次の `iac/lambda.yaml` CloudFormation テンプレートを作成するとします。

```
  Fn:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.7
      CodeUri: src
      Handler: fn.handler
      Role: !GetAtt FnRole.Arn
      Layers:
        - arn:aws:lambda:us-east-1:111122223333:layer:LambdaInsightsExtension:35
```

Guard ユーティリティを[インストール](https://docs.aws.amazon.com/cfn-guard/latest/ug/setting-up.html)したら、テンプレートを検証します。

```
cfn-guard validate --rules etc/rules.guard --data iac/lambda.yaml
```

出力は次のようになります。

```
lambda.yaml Status = FAIL
FAILED rules
rules.guard/lambda_soon_to_be_deprecated_runtime
---
Evaluating data lambda.yaml against rules rules.guard
Number of non-compliant resources 1
Resource = Fn {
  Type      = AWS::Lambda::Function
  Rule = lambda_soon_to_be_deprecated_runtime {
    ALL {
      Check =  Runtime not IN  ["nodejs16.x","nodejs14.x","python3.7","java8","dotnet7","go1.x","ruby2.7","provided"] {
        ComparisonError {
          Message          = Lambda function is using a runtime that is targeted for deprecation.
          Error            = Check was not compliant as property [/Resources/Fn/Properties/Runtime[L:88,C:15]] was not present in [(resolved, Path=[L:0,C:0] Value=["nodejs16.x","nodejs14.x","python3.7","java8","dotnet7","go1.x","ruby2.7","provided"])]
        }
          PropertyPath    = /Resources/Fn/Properties/Runtime[L:88,C:15]
          Operator        = NOT IN
          Value           = "python3.7"
          ComparedWith    = [["nodejs16.x","nodejs14.x","python3.7","java8","dotnet7","go1.x","ruby2.7","provided"]]
          Code:
               86.  Fn:
               87.    Type: AWS::Lambda::Function
               88.    Properties:
               89.      Runtime: python3.7
               90.      CodeUri: src
               91.      Handler: fn.handler

      }
    }
  }
}
```

 Guard を使用すると、開発者はローカルの開発者ワークステーションを参照し、組織で許可されているランタイムを使用するにはテンプレートを更新する必要があることを確認できます。これは、コードリポジトリにコミットし、その後 CI/CD パイプライン内のチェックに失敗する前に発生します。これにより開発者がコンプライアンスに準拠したテンプレートを開発する方法に関するフィードバックを得ることができ、ビジネス価値をもたらすコードの作成に時間を割くことができます。この制御は、ローカルの開発者ワークステーション、コミット前の検証 Webhook、デプロイ前の CI/CD パイプラインに適用できます。

## 注意
<a name="governance-cloudformation-guard-considerations"></a>

AWS Serverless Application Model (AWS SAM) テンプレートを使用して Lambda 関数を定義する場合、以下のように `AWS::Serverless::Function` リソースタイプを検索するように Guard ルールを更新する必要があることに注意してください。

```
let lambda_functions = Resources.*[
    Type == "AWS::Serverless::Function"
]
```

Guard では、プロパティがリソース定義に含まれていることも想定しています。一方、AWS SAM テンプレートではプロパティを別の [[Globals]](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy-globals.html) セクションで指定できます。Globals セクションで定義されているプロパティは、Guard ルールでは検証されません。

Guard のトラブルシューティング[ドキュメント](https://docs.aws.amazon.com/cfn-guard/latest/ug/troubleshooting.html)で説明されているように、Guard は `!GetAtt`、`!Sub` のような短縮形式の組み込み関数をサポートしておらず、`Fn::GetAtt`、`Fn::Sub` の拡張形式を使用する必要があることに注意してください。([前の例](#guard-iac-yaml)では Role プロパティを評価していないため、簡潔にするために短縮形式の組み込み関数を使用しました)。

# AWS Config を使用して Lambda の予防的コントロールを実装する
<a name="governance-config"></a>

開発プロセスのできるだけ早い段階で、サーバーレスアプリケーションのコンプライアンスを確保することが不可欠です。このトピックでは、[AWS Config](https://docs.aws.amazon.com/config/latest/developerguide/WhatIsConfig.html) を使用して予防的制御を実装する方法について説明します。これにより、開発プロセスの早い段階でコンプライアンスチェックを実装でき、CI/CD パイプラインにも同じコントロールを実装できます。また、一元管理されるルールのリポジトリでコントロールが標準化され、AWS アカウント全体にコントロールを一貫して適用できるようになります。

例えば、コンプライアンス管理者が、すべての Lambda 関数に AWS X-Ray トレースが含まれるようにする要件を定義したとします。AWS Config のプロアクティブモードを使用すると、デプロイ前に Lambda 関数リソースのコンプライアンスチェックを実行できます。不適切に設定された Lambda 関数をデプロイするリスクを軽減し、インフラストラクチャに関するフィードバックをコードテンプレートとして迅速に提供することで、開発者の時間を節約できます。以下は AWS Config による予防コントロールのフローを視覚化したものです。

 ![\[CloudFormation requests must pass AWS Config rules before provisioning.\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-config-1.png) 

すべての Lambda 関数でトレースを有効にする必要があるという要件を考えてみましょう。これを受けて、プラットフォームチームは、特定の AWS Config ルールをすべてのアカウントでプロアクティブに実行する必要があると判断しました。このルールは、X-Ray トレーシング設定が設定されていない Lambda 関数を非準拠リソースとしてフラグします。チームはルールを作成し、それを[コンフォーマンスパック](https://docs.aws.amazon.com/config/latest/developerguide/conformance-packs.html)にパッケージ化し、そのコンフォーマンスパックをすべての AWS アカウントにデプロイして、組織内のすべてのアカウントがこれらのコントロールを統一的に適用できるようにします。ルールは AWS CloudFormation Guard 2.x.x 構文で記述し、次のような形式を取ります。

```
rule name when condition { assertion }
```

以下は、Lambda 関数でトレースが有効になっていることを確認する Guard ルールのサンプルです。

```
rule lambda_tracing_check {
  when configuration.tracingConfig exists {
      configuration.tracingConfig.mode == "Active"
  }
}
```

 プラットフォームチームは、すべての AWS CloudFormation デプロイで事前作成/更新[フック](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/hooks-structure.html)を呼び出すことを義務付けることで、さらなる措置を講じます。また、このフックを開発してパイプラインを構成し、コンプライアンスルールの一元管理を強化し、すべてのデプロイメントで一貫した適用を維持する全責任を負います。フックを開発、パッケージ化、登録するには、CloudFormation コマンドラインインターフェイス (CFN-CLI) ドキュメントの「[Developing AWS CloudFormation Hooks](https://docs.aws.amazon.com/cloudformation-cli/latest/hooks-userguide/hooks-develop.html)」を参照してください。[CloudFormation CLI](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/initiating-hooks-project-python.html) を使用してフックプロジェクトを作成できます。

```
cfn init
```

このコマンドは、フックプロジェクトに関する基本情報の入力を求め、以下のファイルを含むプロジェクトを作成します。

```
README.md
<hook-name>.json
rpdk.log
src/handler.py
template.yml
hook-role.yaml
```

フック開発者は、必要なターゲットリソースタイプを `<hook-name>.json` 設定ファイルに追加する必要があります。以下の設定では、CloudFormation を使用して Lambda 関数が作成される前にフックが実行されるように設定されています。`preUpdate` および `preDelete` アクションにも同様のハンドラーを追加できます。

```
    "handlers": {
        "preCreate": {
            "targetNames": [
                "AWS::Lambda::Function"
            ],
            "permissions": []
        }
    }
```

また、CloudFormation フックに AWS Config API を呼び出すための適切な権限があることを確認する必要があります。そのためには、`hook-role.yaml` という名前のロール定義ファイルを更新します。ロール定義ファイルには、デフォルトで以下の信頼ポリシーがあります。これにより、CloudFormation がロールを引き受けることができます。

```
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - hooks.cloudformation.amazonaws.com
                - resources.cloudformation.amazonaws.com
```

このフックで config API を呼び出せるようにするには、ポリシーステートメントに以下の権限を追加する必要があります。次に、`cfn submit` コマンドを使用してフックプロジェクトを送信します。ここで、CloudFormation は必要な権限を持つロールを作成します。

```
      Policies:
        - PolicyName: HookTypePolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - "config:Describe*"
                  - "config:Get*"
                  - "config:List*"
                  - "config:SelectResourceConfig"
                Resource: "*
```

次に、Lambda 関数を `src/handler.py` ファイルに記述する必要があります。このファイルには `preCreate`、`preUpdate`、`preDelete` という名前のメソッドがあり、プロジェクトを開始したときにすでに作成されています。目的は、AWS SDK for Python (Boto3) を使用してプロアクティブモードで AWS Config `StartResourceEvaluation` API を呼び出す、再利用可能な共通関数を作成することです。この API コールは、リソースプロパティを入力として受け取り、ルール定義と照らし合わせてリソースを評価します。

```
def validate_lambda_tracing_config(resource_type, function_properties: MutableMapping[str, Any]) -> ProgressEvent:
  LOG.info("Fetching proactive data")
  config_client = boto3.client('config')
  resource_specs = {
      'ResourceId': 'MyFunction',
      'ResourceType': resource_type,
      'ResourceConfiguration': json.dumps(function_properties),
      'ResourceConfigurationSchemaType': 'CFN_RESOURCE_SCHEMA'
  }
  LOG.info("Resource Specifications:", resource_specs)
  eval_response = config_client.start_resource_evaluation(EvaluationMode='PROACTIVE', ResourceDetails=resource_specs, EvaluationTimeout=60)
  ResourceEvaluationId = eval_response.ResourceEvaluationId
  compliance_response = config_client.get_compliance_details_by_resource(ResourceEvaluationId=ResourceEvaluationId)
  LOG.info("Compliance Verification:", compliance_response.EvaluationResults[0].ComplianceType)
  if "NON_COMPLIANT" == compliance_response.EvaluationResults[0].ComplianceType:
      return ProgressEvent(status=OperationStatus.FAILED, message="Lambda function found with no tracing enabled : FAILED", errorCode=HandlerErrorCode.NonCompliant)
  else:
      return ProgressEvent(status=OperationStatus.SUCCESS, message="Lambda function found with tracing enabled : PASS.")
```

これで、作成前フックのハンドラーから共通関数を呼び出すことができます。ハンドラーの例を示します。

```
@hook.handler(HookInvocationPoint.CREATE_PRE_PROVISION)
def pre_create_handler(
        session: Optional[SessionProxy],
        request: HookHandlerRequest,
        callback_context: MutableMapping[str, Any],
        type_configuration: TypeConfigurationModel
) -> ProgressEvent:
    LOG.info("Starting execution of the hook")
    target_name = request.hookContext.targetName
    LOG.info("Target Name:", target_name)
    if "AWS::Lambda::Function" == target_name:
        return validate_lambda_tracing_config(target_name,
            request.hookContext.targetModel.get("resourceProperties")
        )
    else:
        raise exceptions.InvalidRequest(f"Unknown target type: {target_name}")
```

このステップの後、フックを登録して、すべての AWS Lambda 関数作成イベントをリッスンするように設定できます。

 開発者は、Lambda を使用してサーバーレスマイクロサービス用の Infrastructure as Code (IaC) テンプレートを準備します。この準備には、内部標準を順守した後に、テンプレートをローカルでテストしてリポジトリにコミットすることが含まれます。IaC テンプレート例を次に示します。

```
  MyLambdaFunction:
  Type: 'AWS::Lambda::Function'
  Properties:
    Handler: index.handler
    Role: !GetAtt LambdaExecutionRole.Arn
    FunctionName: MyLambdaFunction
    Code:
      ZipFile: |
        import json

        def handler(event, context):
            return {
                'statusCode': 200,
                'body': json.dumps('Hello World!')
            }
    Runtime: python3.14
    TracingConfig:
        Mode: PassThrough
    MemorySize: 256
    Timeout: 10
```

CI/CD プロセスの一環として、CloudFormation テンプレートがデプロイされると、CloudFormation サービスは `AWS::Lambda::Function` リソースタイプをプロビジョニングする直前に事前作成/更新フックを呼び出します。フックは、プロアクティブモードで実行されている AWS Config ルールを利用して、Lambda 関数設定に必須のトレース設定が含まれていることを確認します。フックからの応答によって次のステップが決まります。準拠していれば、フックは成功を通知し、CloudFormation はリソースのプロビジョニングを続行します。そうでない場合、CloudFormation スタックのデプロイは失敗し、パイプラインはただちに停止し、システムはその詳細を記録して後で確認できるようにします。コンプライアンス通知は、関連する利害関係者に送信されます。

フックの成功/失敗に関する情報は、CloudFormation コンソールで確認できます。

 ![\[Hook success/fail information in the CloudFormation console\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-config-2.png) 

CloudFormation フックのログが有効になっている場合は、フックの評価結果をキャプチャできます。以下は、失敗ステータスのフックのサンプルログです。これは、Lambda 関数で X-Ray が有効になっていないことを示しています。

 ![\[Sample log for a hook with a failed status\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-config-3.png) 

開発者が IaC を変更して `TracingConfig Mode` 値を `Active` に更新して再デプロイすることを選択した場合、フックは正常に実行され、スタックは Lambda リソースの作成に進みます。

 ![\[CloudFormation console shows successful resource deployment\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-config-4.png) 

これにより、サーバーレスリソースを開発して AWS アカウントにデプロイするときに、AWS Config による予防的コントロールをプロアクティブモードで実装できます。AWS Config ルールを CI/CD パイプラインに統合することで、アクティブなトレーシング設定がない Lambda 関数など、非準拠のリソースのデプロイを特定し、オプションでブロックできます。これにより、最新のガバナンスポリシーに準拠するリソースのみが AWS 環境にデプロイされます。

# AWS Config を使用して非準拠の Lambda デプロイと設定を検出する
<a name="governance-config-detection"></a>

[事前評価](governance-config.md)に加えて、AWS Config は、ガバナンスポリシーに準拠していないリソースのデプロイや設定を事後的に検出することもできます。ガバナンスポリシーは、組織が新しいベストプラクティスを学び、実装するにつれて変化するため、これは重要です。

Lambda 関数をデプロイまたは更新するときに、まったく新しいポリシーを設定するシナリオを考えてみましょう。すべての Lambda 関数には、常に特定の承認された Lambda レイヤーバージョンを使用する必要があります。AWS Config を設定し、レイヤー設定の新規または更新された関数をモニタリングするようにできます。AWS Config が承認されたレイヤーバージョンを使用していない機能を検出すると、その関数は非準拠リソースとしてフラグ付けされます。オプションで、AWS Systems Manager 自動化ドキュメントを使用した修復アクションを指定することで、AWS Config がリソースを自動的に修正するように設定できます。例えば、AWS SDK for Python (Boto3) を使用して Python でオートメーションドキュメントを作成できます。これにより、非準拠関数が承認されたレイヤーバージョンを指すように更新されます。したがって、AWS Config は検出と是正の両方の制御を行い、コンプライアンス管理を自動化します。

このプロセスを次の 3 つの重要な実装フェーズに分けてみましょう。

 ![\[The three implementation phases are identify, notify, and deploy remediation.\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-config-detective-1.png) 

## フェーズ 1: アクセスリソースの特定
<a name="governance-config-detective-identify"></a>

まず、アカウント全体で AWS Config を有効にし、AWS Lambda 関数を記録するように設定します。これにより、AWS Config は Lambda 関数がいつ作成または更新されたかを確認できます。その後、AWS CloudFormation Guard 構文を使用して特定のポリシー違反をチェックする[カスタムポリシールール](https://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_develop-rules_cfn-guard.html)を設定できます。Guard ルールには次のような一般的な形式があります。

```
rule name when condition { assertion }
```

以下は、古いレイヤーバージョンにレイヤーが設定されていないことを確認するルールのサンプルです。

```
rule desiredlayer when configuration.layers !empty {
    some configuration.layers[*].arn != CONFIG_RULE_PARAMETERS.OldLayerArn
}
```

ルールの構文と構造を理解しましょう。
+ **ルール名:** 例では、ルール名は `desiredlayer` です。
+ **条件:** この句は、ルールを確認する条件を指定します。示されている例では、条件は `configuration.layers !empty` です。つまり、設定内の `layers` プロパティが空でない場合にのみ、リソースが評価されます。
+ **アサーション:** `when` 句の後に、アサーションによってルールがチェックする内容が決まります。アサーション `some configuration.layers[*].arn != CONFIG_RULE_PARAMETERS.OldLayerArn` は、Lambda レイヤの ARN のいずれかが `OldLayerArn` 値と一致しないかどうかを確認します。一致しない場合、アサーションは true でルールは成功し、一致しない場合は失敗します。

`CONFIG_RULE_PARAMETERS` は、AWS Config ルールで設定される特別なパラメータセットです。この場合、`OldLayerArn` は `CONFIG_RULE_PARAMETERS` 内部のパラメータです。これにより、ユーザーは古い、または廃止されたと思われる特定の ARN 値を指定し、ルールはその古い ARN を使用する Lambda 関数がないかをチェックします。

## フェーズ 2: 視覚化と設計
<a name="governance-config-detective-visualize"></a>

AWS Config は、設定データを収集し、そのデータを Amazon Simple Storage Service (Amazon S3) バケットに保存します。[Amazon Athena](https://aws.amazon.com/athena/) を使用して、S3 バケットから直接このデータをクエリできます。Athena を使用すると、このデータを組織レベルで集約し、すべてのアカウントにわたるリソース構成の全体像を生成できます。リソース設定データの集約を設定するには、AWS クラウド運用と管理ブログの「[Athena と Amazon Quick による AWS Config データの視覚化](https://aws.amazon.com/blogs/mt/visualizing-aws-config-data-using-amazon-athena-and-amazon-quicksight/)」を参照してください。

以下は、特定のレイヤー ARN を使用してすべての Lambda 関数を識別する Athena クエリのサンプルです。

```
WITH unnested AS (
    SELECT
      item.awsaccountid AS account_id,
      item.awsregion AS region,
      item.configuration AS lambda_configuration,
      item.resourceid AS resourceid,
      item.resourcename AS resourcename,
      item.configuration AS configuration,
      json_parse(item.configuration) AS lambda_json
    FROM
      default.aws_config_configuration_snapshot,
      UNNEST(configurationitems) as t(item)
    WHERE
      "dt" = 'latest'
      AND item.resourcetype = 'AWS::Lambda::Function'
  )
  
  SELECT DISTINCT
    region as Region,
    resourcename as FunctionName,
    json_extract_scalar(lambda_json, '$.memorySize') AS memory_size,
    json_extract_scalar(lambda_json, '$.timeout') AS timeout,
    json_extract_scalar(lambda_json, '$.version') AS version
  FROM
    unnested
  WHERE
    lambda_configuration LIKE '%arn:aws:lambda:us-east-1:111122223333:layer:AnyGovernanceLayer:24%'
```

クエリの結果は次のとおりです。

 ![\[Query results in Athena console.\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-config-detective-2.png) 

組織全体で AWS Config データを集約したら、[Amazon Quick](https://aws.amazon.com/quicksight/) を使用してダッシュボードを作成できます。Athena の結果を Quick にインポートすることで、Lambda 関数がレイヤーバージョンのルールにどれ程度忠実に適合しているかを視覚化することができます。このダッシュボードでは、[次のセクション](#governance-config-detective-implement)で説明するように、準拠しているリソースと準拠していないリソースをハイライト表示できるため、施行ポリシーを決定するのに役立ちます。以下の画像は、組織内の機能に適用されるレイヤーバージョンの分布をレポートするダッシュボードの例です。

 ![\[Example Quick dashboard shows distribution of layer versions in Lambda functions.\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-config-detective-3.png) 

## フェーズ 3: 実装と適用
<a name="governance-config-detective-implement"></a>

[フェーズ 1](#governance-config-detective-identify) で作成したレイヤーバージョンルールを、Systems Manager 自動化ドキュメントによる修復アクションとオプションで組み合わせることができるようになりました。このドキュメントは、AWS SDK for Python (Boto3) で記述した Python スクリプトとして作成します。このスクリプトは Lambda 関数ごとに [UpdateFunctionConfiguration API](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateFunctionConfiguration.html) アクションを呼び出し、新しいレイヤー ARN を使用して関数設定を更新します。あるいは、スクリプトでコードリポジトリにプルリクエストを送信し、レイヤー ARN を更新することもできます。これにより、今後のコードのデプロイも正しいレイヤー ARN で更新されます。

# AWS Signer で Lambda コード署名を行う
<a name="governance-code-signing"></a>

[AWS Signer](https://docs.aws.amazon.com/signer/latest/developerguide/Welcome.html) は完全マネージド型のコード署名サービスで、コードをデジタル署名と照合して検証し、コードが変更されていないこと、信頼できるパブリッシャーからのものであることを確認できます。AWS Signer を AWS Lambda と併用して、AWS 環境へのデプロイ前に機能やレイヤーが変更されていないことを確認できます。これにより、認証情報を取得して新しい機能を作成したり、既存の機能を更新したりする悪意のある攻撃者から組織を保護できます。

Lambda 関数のコード署名を設定するには、まずバージョニングを有効にして S3 バケットを作成します。その後、AWS Signer を使用して署名プロファイルを作成し、プラットフォームに Lambda を指定し、署名プロファイルの有効日数を指定します。例：

```
  Signer:
    Type: AWS::Signer::SigningProfile
    Properties:
      PlatformId: AWSLambda-SHA384-ECDSA
      SignatureValidityPeriod:
        Type: DAYS
        Value: !Ref pValidDays
```

次に、署名プロファイルを使用して、Lambda で署名設定を作成します。署名設定で、想定していたデジタル署名と一致しないアーティファクトが見つかった場合、「警告」(ただしデプロイは許可) または「強制」 (デプロイをブロックする) のいずれかの対処方法を指定する必要があります。以下の例は、デプロイメントを強制し、ブロックするように設定されています。

```
  SigningConfig:
    Type: AWS::Lambda::CodeSigningConfig
    Properties:
      AllowedPublishers:
        SigningProfileVersionArns:
          - !GetAtt Signer.ProfileVersionArn
      CodeSigningPolicies:
        UntrustedArtifactOnDeployment: Enforce
```

これで、AWS Signer が信頼できないデプロイをブロックするよう Lambda で設定できました。機能リクエストのコーディングが完了し、関数をデプロイする準備ができたと仮定しましょう。最初のステップは、適切な依存関係を含めてコードを圧縮し、作成した署名プロファイルを使用してアーティファクトに署名することです。そのためには、zip アーティファクトを S3 バケットにアップロードし、署名ジョブを開始します。

```
aws signer start-signing-job \
--source 's3={bucketName=your-versioned-bucket,key=your-prefix/your-zip-artifact.zip,version=QyaJ3c4qa50LXV.9VaZgXHlsGbvCXxpT}' \
--destination 's3={bucketName=your-versioned-bucket,prefix=your-prefix/}' \
--profile-name your-signer-id
```

`jobId` は送信先バケットで作成されるオブジェクトでプレフィックスであり、`jobOwner` はジョブが実行された AWS アカウント の 12 桁 ID である出力が得られます。

```
{
    "jobId": "87a3522b-5c0b-4d7d-b4e0-4255a8e05388",
    "jobOwner": "111122223333"
  }
```

これで、署名された S3 オブジェクトと作成したコード署名設定を使用して関数をデプロイできます。

```
  Fn:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: s3://your-versioned-bucket/your-prefix/87a3522b-5c0b-4d7d-b4e0-4255a8e05388.zip
      Handler: fn.handler
      Role: !GetAtt FnRole.Arn
      CodeSigningConfigArn: !Ref pSigningConfigArn
```

あるいは、元の署名されていないソース ZIP アーティファクトを使用して関数デプロイをテストすることもできます。デプロイに失敗し、以下のメッセージが表示されます。

```
Lambda cannot deploy the function. The function or layer might be signed using a signature that the client is not configured to accept. Check the provided signature for unsigned.
```

AWS Serverless Application Model (AWS SAM) を使用して関数をビルドしてデプロイする場合、package コマンドは zip アーティファクトを S3 にアップロードし、署名ジョブを開始して署名されたアーティファクトを取得します。以下のコマンドとパラメータで、これを行えます。

```
sam package -t your-template.yaml \
--output-template-file your-output.yaml \
--s3-bucket your-versioned-bucket \
--s3-prefix your-prefix \
--signing-profiles your-signer-id
```

AWS Signer は、アカウントにデプロイされた zip アーティファクトがデプロイ対象として信頼されていることを確認するのに役立ちます。上記のプロセスを CI/CD パイプラインに含め、前のトピックで説明した手法を使用してすべての機能にコード署名設定を添付することを要求できます。Lambda 関数のデプロイでコード署名を使用することにより、関数を作成または更新するための認証情報を取得した悪意のあるアクターが関数に悪意のあるコードを挿入するのを防ぐことができます。

# Amazon Inspector を使用して Lambda のセキュリティ評価を自動化する
<a name="governance-code-scanning"></a>

 [Amazon Inspector](https://aws.amazon.com/inspector/) は、既知のソフトウェアの脆弱性や意図しないネットワークの露出について、ワークロードを継続的にスキャンする脆弱性管理サービスです。Amazon Inspector が生成する検出結果は、脆弱性を説明し、影響を受けるリソースを特定し、脆弱性の重要度を評価し、修正ガイダンスを提供します。

Amazon Inspector サポートにより、Lambda 関数とレイヤーのセキュリティ脆弱性評価が継続的かつ自動的に行われます。Amazon Inspector では、2 種類の Lambda スキャンを提供しています。
+ **Lambda 標準スキャン (デフォルト):** Lambda 関数とそのレイヤー内のアプリケーションの依存関係をスキャンして、[パッケージの脆弱性](https://docs.aws.amazon.com/inspector/latest/user/findings-types.html#findings-types-package)がないか調べます。
+ **Lambda コードスキャン:** Lambda 関数内のカスタムアプリケーションコードをスキャンして、[コードの脆弱性](https://docs.aws.amazon.com/inspector/latest/user/findings-types.html#findings-types-code)がないか調べます。Lambda 標準スキャンをアクティブ化することも、Lambda コードスキャンと同時に Lambda 標準スキャンをアクティブ化することもできます。

Amazon Inspector を有効にするには、[Amazon Inspector コンソール](https://console.aws.amazon.com/inspector/)に移動し、**[設定]** セクションを展開して **[アカウント管理]** を選択します。**[アカウント]** タブで **[有効化]** を選択し、スキャンオプションのいずれかを選択します。

Amazon Inspector をセットアップするときに、複数のアカウントで Amazon Inspector を有効にし、組織の Amazon Inspector を管理するためのアクセス権限を特定のアカウントに委任できます。有効にする際には、`AWSServiceRoleForAmazonInspector2` ロールを作成して Amazon Inspector にアクセス権限を付与する必要があります。Amazon Inspector コンソールで、ワンクリックオプションを使用してこのロールを作成できます。

Lambda の標準スキャンでは、Amazon Inspector は、次のような状況で Lambda 関数の脆弱性スキャンを開始します。
+ Amazon Inspector が既存の Lambda 関数を検出した時。
+ 新しい Lambda 関数をデプロイした時。
+ 既存の Lambda 関数またはそのレイヤーのアプリケーションコードまたは依存関係に更新がデプロイされた場合。
+ Amazon Inspector がデータベースに新しい共通脆弱性識別子 (CVE) 項目を追加し、その CVE が関数に関連している場合。

Lambda コードスキャンでは、Amazon Inspector は、自動推論と機械学習を使用して Lambda 関数のアプリケーションコードを評価し、アプリケーションコードを分析して全体的なセキュリティコンプライアンスを確認します。Amazon Inspector が Lambda 関数のアプリケーションコードに脆弱性を検出すると、Amazon Inspector は詳細な **[コード脆弱性]** の検出結果を生成します。可能な検出のリストについては、「[Amazon CodeGuru Detector Library](https://docs.aws.amazon.com/codeguru/detector-library/)」を参照してください。

結果を確認するには、[Amazon Inspector コンソール](https://console.aws.amazon.com/inspector/)にアクセスしてください。**[結果]** メニューで **[Lambda 関数別]** を選択すると、Lambda 関数で実行されたセキュリティスキャン結果が表示されます。

Lambda 関数を標準スキャンから除外するには、関数に次のキーと値のペアをタグ付けします。
+ `Key:InspectorExclusion`
+ `Value:LambdaStandardScanning`

コードスキャンから Lambda 関数を除外するには、関数に次のキーと値のペアをタグ付けします。
+ `Key:InspectorCodeExclusion`
+ `Value:``LambdaCodeScanning`

例えば、以下の画像では、Amazon Inspector は脆弱性を自動的に検出し、検出結果を **[コード脆弱性]** という種類に分類しています。これは、脆弱性がコード依存ライブラリのいずれにもなく、関数のコードにあることを示します。特定の機能または複数の機能について、これらの詳細を一度に確認できます。

 ![\[Amazon Inspector finds vulnerabilities in Lambda code.\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-code-scanning-1.png) 

これらの検出結果を 1 つずつ詳しく調べて、問題を解決する方法を知ることができます。

 ![\[Amazon Inspector console displays code vulnerability details.\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-code-scanning-2.png) 

Lambda 関数を使用する際は、必ず Lambda 関数の命名規則に準拠するようにしてください。詳細については、「[Lambda 環境変数の操作](configuration-envvars.md)」を参照してください。

修復案を承認する責任はユーザーにあります。修復案を受け入れる前に、必ず確認してください。コードが意図したとおりに動作するように、修正案の編集が必要となる場合があります。

# Lambda のセキュリティとコンプライアンスのためのオブザーバビリティの実装
<a name="governance-observability"></a>

AWS Config は、非準拠の AWS サーバーレスリソースを見つけて修正するのに便利なツールです。サーバーレスリソースに加えた変更はすべて AWS Config に記録されます。さらに、AWS Config では、設定スナップショットデータを S3 に保存できます。Amazon Athena と Amazon Quick を使用して、ダッシュボードを作成し、AWS Config データを表示できます。[AWS Config を使用して非準拠の Lambda デプロイと設定を検出する](governance-config-detection.md) では、Lambda レイヤーのような特定の設定を視覚化する方法について説明しました。このトピックでは、これらの概念について詳しく説明します。

## Lambda 設定の可視性
<a name="governance-observability-configuration"></a>

クエリを使用して、AWS アカウント ID、リージョン、AWS X-Ray トレーシング設定、VPC 設定、メモリサイズ、ランタイム、タグなどの重要な設定を取得できます。Athena からこの情報を取得するために使用できるクエリ例を次に示します。

```
WITH unnested AS (
    SELECT
      item.awsaccountid AS account_id,
      item.awsregion AS region,
      item.configuration AS lambda_configuration,
      item.resourceid AS resourceid,
      item.resourcename AS resourcename,
      item.configuration AS configuration,
      json_parse(item.configuration) AS lambda_json
    FROM
      default.aws_config_configuration_snapshot,
      UNNEST(configurationitems) as t(item)
    WHERE
      "dt" = 'latest'
      AND item.resourcetype = 'AWS::Lambda::Function'
  )
  
  SELECT DISTINCT
    account_id,
    tags,
    region as Region,
    resourcename as FunctionName,
    json_extract_scalar(lambda_json, '$.memorySize') AS memory_size,
    json_extract_scalar(lambda_json, '$.timeout') AS timeout,
    json_extract_scalar(lambda_json, '$.runtime') AS version
    json_extract_scalar(lambda_json, '$.vpcConfig.SubnetIds') AS vpcConfig
    json_extract_scalar(lambda_json, '$.tracingConfig.mode') AS tracingConfig
  FROM
    unnested
```

クエリを使用して Quick ダッシュボードを構築し、データを視覚化することができます。AWS リソース設定データを集約し、Athena でテーブルを作成し、Athena から取得するデータに基づいて Quick ダッシュボードを構築する方法については、「AWS クラウド運用と管理」ブログの「[Athena と Amazon QuickSight を使用して AWS Config データを視覚化する](https://aws.amazon.com/blogs/mt/visualizing-aws-config-data-using-amazon-athena-and-amazon-quicksight/)」を参照してください。特に、このクエリは関数のタグ情報も取得します。これにより、特にカスタムタグを使用する場合に、ワークロードと環境をより深く把握できます。

 ![\[Query results in Quick dashboard\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-observability-1.png) 

実行できるアクションの詳細については、このトピックで後述する [オブザーバビリティに関する検出結果への対処](#governance-observability-addressing) セクションを参照してください。

## Lambda コンプライアンスの可視性
<a name="governance-observability-compliance"></a>

AWS Config で生成されたデータを使用して、コンプライアンスを監視するための組織レベルのダッシュボードを作成できます。これにより、以下の項目を一貫して追跡およびモニタリングできます。
+ コンプライアンススコアによるコンプライアンスパック
+ 非準拠リソースによるルール
+ コンプライアンスステータス

 ![\[AWS Config console dashboard\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-observability-2.png) 

各ルールをチェックして、そのルールに適合していないリソースを特定します。例えば、組織ですべての Lambda 関数を VPC に関連付けることが義務付けられていて、コンプライアンスを識別する AWS Config ルールをデプロイしている場合は、上のリストから `lambda-inside-vpc` ルールを選択できます。

 ![\[View non-compliant resources in AWS Config console\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-observability-3.png) 

実行できるアクションの詳細については、以下の [オブザーバビリティに関する検出結果への対処](#governance-observability-addressing) セクションを参照してください。

## Security Hub CSPM を使用した Lambda 関数の境界の可視化
<a name="governance-observability-boundaries"></a>

 ![\[Diagram of example AWS Security Hub CSPM inputs for Lambda, such as resource policy, runtime, and code\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-observability-4.png) 

Lambda を含む AWS サービスを安全に使用するために、AWS は基礎セキュリティのベストプラクティス v1.0.0 を導入しました。この一連のベストプラクティスは、AWS 環境内のリソースとデータを保護するための明確なガイドラインを提供し、強固なセキュリティ体制を維持することの重要性を強調しています。AWS Security Hub CSPM は、セキュリティとコンプライアンスの統合センターを提供することで、これを補完しています。Amazon Inspector、AWS Identity and Access Management Access Analyzer、Amazon GuardDuty などの複数の AWS サービスからセキュリティ結果を集計、整理、優先順位付けします。

AWS 組織内で Security Hub CSPM、Amazon Inspector、IAM アクセスアナライザー、および GuardDuty が有効になっている場合、Security Hub CSPM はこれらのサービスからの検出結果を自動的に集計します。例えば、Amazon Inspector を考えてみましょう。Security Hub CSPM を使用すると、Lambda 関数のコードとパッケージの脆弱性を効率的に特定できます。Security Hub CSPM コンソールで、「**AWS 統合からの最新の調査結果**」というラベルの付いた一番下のセクションに移動します。ここでは、さまざまな統合 AWS サービスから得られた結果を表示して分析できます。

 ![\[Security Hub CSPM console "Latest findings from AWS integrations" section\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-observability-5.png) 

詳細を確認するには、2 番目の列の **[結果を参照]** リンクを選択します。これにより、Amazon Inspector などの製品別にフィルタリングされた結果のリストが表示されます。検索を Lambda 関数に限定するには、`ResourceType` を `AwsLambdaFunction` に設定します。これには、Lambda 関数に関連する Amazon Inspector からの結果が表示されます。

 ![\[Filter for Amazon Inspector results related to Lambda functions\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/governance-observability-6.png) 

GuardDuty では、疑わしいネットワークトラフィックパターンを特定できます。このような異常は、Lambda 関数内に潜在的に悪意のあるコードが存在することを示唆している可能性があります。

IAM Access Analyzer を使用すると、ポリシー、特に外部エンティティへの関数アクセスを許可する条件ステートメントを含むポリシーを確認できます。さらに、IAM アクセスアナライザーは、Lambda API の [AddPermission](https://docs.aws.amazon.com/lambda/latest/api/API_AddPermission.html) オペレーションを `EventSourceToken` と共に使用したときに設定されたアクセス権限を評価します。

## オブザーバビリティに関する検出結果への対処
<a name="governance-observability-addressing"></a>

Lambda 関数の設定は多岐にわたり、要件も異なるため、標準化された修正自動化ソリューションがすべての状況に適しているとは限りません。さらに、変更の実装方法は環境によって異なります。準拠していないと思われる設定が見つかった場合は、以下のガイドラインを検討してください。

1. **タグ付け戦略**

   包括的なタグ付け戦略を実装することをお勧めします。各 Lambda 関数には、次のような重要な情報をタグ付けする必要があります。
   + **オーナー:** 関数の責任を負う個人またはチーム。
   + **環境:** 本番、ステージング、開発、またはサンドボックス。
   + **アプリケーション:** この関数が属するより広いコンテキスト (該当する場合)。

1. **オーナーへの働きかけ**

   重大な変更 (VPC 設定の調整など) は自動化せず、準拠していない機能 (所有者タグで識別) の所有者に事前に連絡し、次のいずれかを行うための十分な時間を確保してください。
   + Lambda 関数の非準拠設定を調整します。
   + 説明をして例外をリクエストするか、コンプライアンス基準を改定してください。

1. **構成管理データベース (CMDB) のメンテナンス**

   タグはコンテキストをすぐに提供できますが、一元管理された CMDB を管理することでより深い洞察を得ることができます。各 Lambda 関数、依存関係、その他の重要なメタデータに関するより詳細な情報を保持できます。CMDB は、監査、コンプライアンスチェック、および関数所有者の特定において非常に貴重なリソースです。

サーバーレスインフラストラクチャの状況は絶えず進化しているため、監視に対して積極的な姿勢をとることが不可欠です。AWS Config、Security Hub CSPM、Amazon Inspector などのツールを使用すると、潜在的な異常や非準拠の設定を迅速に特定できます。ただし、ツールだけでは完全なコンプライアンスや最適な構成を保証することはできません。これらのツールを、十分に文書化されたプロセスやベストプラクティスと組み合わせることが重要です。
+ **フィードバックループ:** 是正措置を講じたら、必ずフィードバックループを実施してください。つまり、コンプライアンス違反のリソースを定期的に見直して、更新されていないか、同じ問題がまだ発生していないかを確認します。
+ **文書化:** 観察結果、実施した措置、および認められた例外事項を必ず文書化してください。適切な文書化は、監査時に役立つだけでなく、今後のコンプライアンスとセキュリティを向上させるためのプロセスを強化するのにも役立ちます。
+ **トレーニングと啓発:** すべての利害関係者、特に Lambda 関数の所有者に定期的にトレーニングを実施し、ベストプラクティス、組織ポリシー、コンプライアンス義務について周知徹底するようにします。定期的なワークショップ、ウェビナー、トレーニングセッションなどは、セキュリティとコンプライアンスに関して全員が同じ認識を持つようにするのに大いに役立ちます。

結論として、ツールやテクノロジーは潜在的な問題を検出して報告するための強力な機能を備えていますが、理解、コミュニケーション、トレーニング、文書化といった人的要素が極めて重要です。これらを合わせることで、Lambda 関数と広範なインフラストラクチャがコンプライアンス、安全性を維持し、ビジネスニーズに合わせて最適化されることを保証する強力な組み合わせになります。