

# 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)는 오픈 소스, 범용, 코드형 정책 평가 도구입니다. 정책 규칙을 기준으로 코드형 인프라(IaC) 템플릿 및 서비스 구성을 검증함으로써 예방적 거버넌스 및 규정 준수를 위해 사용할 수 있습니다. 이러한 규칙은 팀 또는 조직의 요구 사항에 따라 사용자 지정할 수 있습니다. Lambda 함수의 경우 Guard 규칙을 사용하여 Lambda 함수를 생성 또는 업데이트하는 동안 필요한 필수 속성 설정을 정의함으로써 리소스 생성 및 구성 업데이트를 제어할 수 있습니다.

규정 준수 관리자는 Lambda 함수를 배포하고 업데이트하는 데 필요한 제어 및 거버넌스 정책 목록을 정의합니다. 플랫폼 관리자는 코드 리포지토리가 포함된 사전 커밋 검증 웹후크로 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/ko_kr/lambda/latest/dg/images/governance-cloudformation-guard.png) 

예를 들어 개발자가 최신 런타임만 선택하려고 한다고 가정합니다. 두 가지 정책을 지정할 수 있습니다. 하나는 이미 지원이 중단된 [런타임](lambda-runtimes.md)을 식별하는 정책이고 다른 하나는 곧 지원 중단 예정인 런타임을 식별하는 정책입니다. 이를 위해 다음 `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 파이프라인 내에서 검사에 실패하기 전에 확인할 수 있습니다. 따라서 개발자는 규정을 준수하는 템플릿을 개발하고 비즈니스 가치를 전달하는 코드를 작성하는 데 시간을 더 할애하는 방법에 대한 피드백을 받을 수 있습니다. 이 제어는 배포 전에 로컬 개발자 워크스테이션, 사전 커밋 검증 웹후크 및/또는 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 템플릿을 사용하면 별도의 [글로벌](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy-globals.html) 섹션에서 속성을 지정할 수 있습니다. 글로벌 섹션에 정의된 속성은 Guard 규칙으로 검증되지 않습니다.

Guard 문제 해결 [설명서에](https://docs.aws.amazon.com/cfn-guard/latest/ug/troubleshooting.html) 설명된 대로, Guard에서는 짧은 양식의 내장 함수(예: `!GetAtt` 또는 `!Sub`)를 지원하지 않으며, 대신 확장된 양식(`Fn::GetAtt` 및 `Fn::Sub`)을 사용해야 합니다. ([이전 예제](#guard-iac-yaml)에서는 역할 속성을 평가하지 않으므로 단순한 설명을 위해 짧은 양식의 내장 함수를 사용했습니다.)