# 병합 충돌을 방지하기 위해 파생 디택션 사용

## 배경

사용해야 하는 가장 설득력 있는 이유 중 하나는 [파생 디택션](/ko/detections/rules/derived.md)입니다. CLI 워크플로를 사용해 Panther 디택션 콘텐츠를 관리하는 팀이라면, 병합 충돌 문제를 피하면서도 자체 팀만이 관리하고 업데이트하는 것이 아닌 디택션을 사용하고 맞춤화할 수 있습니다. 이러한 병합 충돌은 동일한 디택션이 외부 팀에 의해 업데이트될 때 발생할 수 있습니다.

이 시나리오는 Panther의 Threat Research 팀이 다음을 통해 생성 및 배포하는 디택션을 사용할 때 발생할 수 있습니다. [`panther-analysis` repository](https://github.com/panther-labs/panther-analysis), 알려진 이름은 [Panther가 관리하는 탐지](/ko/detections/panther-managed.md)입니다. 병합 충돌은 `panther-analysis` 의 포크를 유지 관리하려고 할 때 발생할 수 있습니다. 여기에서 Panther가 관리하는 디택션을 맞춤화했지만, 동시에 포크를 업스트림 리포지토리와 동기화하여 Panther의 콘텐츠 변경 사항도 최신 상태로 유지하려는 경우입니다.

이 경우 파생이 유용합니다. Panther가 관리하는 디택션을 Panther가 수정하는 파일과는 완전히 별개의 파일을 편집하여 맞춤화할 수 있기 때문입니다. 즉, 나중에 병합 충돌을 생성하지 않고도 Panther의 콘텐츠 업데이트를 받을 수 있습니다.

## 파생이 유용한 시나리오 살펴보기

아래 시나리오에서는 사용자가 Panther가 관리하는 디택션을 수정하려고 합니다. 디택션 파생 없이, 그리고 디택션 파생을 사용하여 업데이트가 어떻게 이루어지는지 확인해 보세요.

### 시나리오

다음을 사용하고 싶다고 가정해 보겠습니다. `AWS.Console.LoginWithoutMFA` Panther가 관리하는 디택션(다음 참조: [여기의 Python 파일](https://github.com/panther-labs/panther-analysis/blob/main/rules/aws_cloudtrail_rules/aws_console_login_without_mfa.py) 및 [여기의 YAML 파일](https://github.com/panther-labs/panther-analysis/blob/main/rules/aws_cloudtrail_rules/aws_console_login_without_mfa.yml))이지만, 귀하는 *또한* 여기에 다음과 같은 수정을 하고 싶습니다:

* 로그인되는 계정이 dev 계정인 경우에는 알러트하지 않기를 원합니다
  * 이에 맞추어 이 로직을 반영하도록 테스트도 변경하고 싶습니다
* 심각도를 `낮음` 로그인되는 계정이 내부용 비-dev 계정인 경우로 설정하고, `High` 그 외의 경우에는
* 런북을 변경하고 싶습니다

### 파생 없이 이러한 수정을 수행하는 방법

파생을 사용하지 않는다면 CLI 워크플로에서 다음과 같은 변경을 수행하게 됩니다:

* 다음을 수정합니다. `aws_console_login_without_mfa.py` 파일을 다음과 같은 방식으로:

  * 다음을 변경합니다. `룰()` 함수에 다음과 유사한 로직을 포함하도록 합니다:

  ```python
  def 룰(event):
  		# dev 계정인 경우 디택션을 단락 평가하는 사용자 지정 로직
  		dev_accounts = [
  				"123456789001",
  				"123456789002"
  		]
  		if event.get("recipientAccountId") in dev_accounts:
  				return False
  ....
  ```

  * 다음을 추가합니다. [`severity()`](/ko/detections/rules/python.md#severity) 다음과 유사한 함수:

  ```python
  def severity(event):
  		internal_non_dev_accounts = [
  				"123456789003",
  				"123456789004"
  		]
  		if event.get("recipientAccountId") in internal_non_dev_accounts:
  				return "LOW"
  		return "HIGH"
  ```
* 다음을 수정합니다. `aws_console_login_without_mfa.yml` 파일을 다음과 같은 방식으로:
  * 다음을 교체합니다. `테스트` 섹션을 새로운 일련의 테스트로 교체합니다. 여기에는 dev 계정 ID를 포함하는 로그에 대한 테스트 하나와, 포함하지 않는 로그에 대한 테스트 하나가 포함됩니다
  * 다음 값 `런북` 을(를) 사용자 지정 런북 링크로 업데이트합니다

이러한 변경을 수행한 후에는 해당 룰이 조직의 요구 사항에 맞게 맞춤화됩니다. 그러나 이 시점부터 Panther가 두 파일 중 하나라도 변경하면, 업데이트를 가져올 때 병합 충돌이 발생할 가능성이 높습니다.

모든 동일한 사용자 지정을 적용하면서 병합 충돌을 피하기 위해 파생을 사용하는 방법을 아래에서 확인하세요.

### 파생을 사용하여 이러한 수정을 만드는 방법

파생 워크플로우에서는 기본적으로 Base Detection의 모든 측면을 상속하는 Derived Detection을 먼저 생성합니다:

```yaml
# aws_console_login_without_mfa_account_filter.yml
AnalysisType: 룰
BaseDetection: AWS.Console.LoginWithoutMFA
RuleID: AWS.Console.LoginWithoutMFA.Account.Filter
```

그다음 다음 항목부터 시작하여 오버라이드를 추가합니다 `런북`:

```yaml
# aws_console_login_without_mfa_account_filter.yml
...
# 사용자 지정 runbook
Runbook: <https://runbooks.security.corp/secops/AWS/ConsoleLoginWithoutMFA>
```

추가하세요 [`InlineFilters`](/ko/detections/rules/inline-filters.md) 를 추가하여 로그인 중인 AWS 계정이 dev 계정인 경우 룰이 실행되지 않도록 지정합니다:

```yaml
# aws_console_login_without_mfa_account_filter.yml
...
# dev 계정 이벤트 필터링 
InlineFilters:
    - All:
        - KeyPath: recipientAccountId
          Condition: IsNotIn
          Values:
            - '123456789002'
            - '123456789001'
```

추가하세요 [`DynamicSeverities`](/ko/detections/rules/writing-simple-detections.md#dynamicseverities) 를 추가하여 계정이 staging 계정인 경우 심각도를 조정합니다:

```yaml
# aws_console_login_without_mfa_account_filter.yml
...
# staging 계정이면 심각도를 Low로 설정
DynamicSeverities:
  - ChangeTo: LOW
    Conditions:
      - KeyPath: recipientAccountId
        Condition: IsIn
        Values:
          - '123456789003'
          - '123456789004'
```

마지막으로, `테스트` 를 추가하여 추가한 디택션과 필터를 테스트할 수 있도록 자신만의 테스트 세트를 추가합니다. 아래는 앞서 언급한 모든 오버라이드를 추가한 후의 완전한 Derived Detection입니다:

```yaml
# aws_console_login_without_mfa_account_filter.yml
AnalysisType: 룰
BaseDetection: AWS.Console.LoginWithoutMFA
RuleID: AWS.Console.LoginWithoutMFA.Account.Filter

# 사용자 지정 Runbook
Runbook: <https://runbooks.security.corp/secops/AWS/ConsoleLoginWithoutMFA>

# dev 계정 이벤트 필터링 
InlineFilters:
  - All:
    - KeyPath: recipientAccountId
      Condition: IsNotIn
      Values:
        - '123456789001'
        - '123456789002'

# staging 계정이면 심각도를 Low로 설정
DynamicSeverities:
  - ChangeTo: LOW
    Conditions:
      - KeyPath: recipientAccountId
        Condition: IsIn
        Values:
          - '123456789003'
          - '123456789004'

# 필터와 룰을 테스트하는 테스트
Tests:
  -
      Name: No MFA Login - IAM User
      예상 결과: true
      Mocks:
        - objectName: check_account_age
          returnValue: "False"
      Log:
        {
          "eventVersion": "1.05",
          "userIdentity": {
            "type": "IAMUser",
            "principalId": "1111",
            "arn": "arn:aws:iam::123456789012:user/tester",
            "accountId": "123456789012",
            "userName": "tester"
          },
          "eventTime": "2019-01-01T00:00:00Z",
          "eventSource": "signin.amazonaws.com",
          "eventName": "ConsoleLogin",
          "awsRegion": "us-east-1",
          "sourceIPAddress": "111.111.111.111",
          "userAgent": "Mozilla",
          "requestParameters": null,
          "responseElements": {
            "ConsoleLogin": "Success"
          },
          "additionalEventData": {
            "LoginTo": "<https://console.aws.amazon.com/console/>",
            "MobileVersion": "아니요",
            "MFAUsed": "아니요"
          },
          "eventID": "1",
          "eventType": "AwsConsoleSignIn",
          "recipientAccountId": "123456789012"
        }
  -
      이름: Dev 계정의 MFA 없는 로그인 - IAM 사용자
      예상 결과: false
      Mocks:
        - objectName: check_account_age
          returnValue: "False"
      Log:
        {
          "eventVersion": "1.05",
          "userIdentity": {
            "type": "IAMUser",
            "principalId": "1111",
            "arn": "arn:aws:iam::123456789012:user/tester",
            "accountId": "123456789012",
            "userName": "tester"
          },
          "eventTime": "2019-01-01T00:00:00Z",
          "eventSource": "signin.amazonaws.com",
          "eventName": "ConsoleLogin",
          "awsRegion": "us-east-1",
          "sourceIPAddress": "111.111.111.111",
          "userAgent": "Mozilla",
          "requestParameters": null,
          "responseElements": {
            "ConsoleLogin": "Success"
          },
          "additionalEventData": {
            "LoginTo": "<https://console.aws.amazon.com/console/>",
            "MobileVersion": "아니요",
            "MFAUsed": "아니요"
          },
          "eventID": "1",
          "eventType": "AwsConsoleSignIn",
          "recipientAccountId": "123456789002"
        }
```

이제 모든 오버라이드를 파생된 디택션에 추가했으므로, Panther에 업로드하여 다른 디택션과 똑같이 사용할 수 있습니다.

Panther가 기본 디택션을 업데이트할 때마다—즉, Panther가 다음 중 하나를 수정하면 `aws_console_login_without_mfa.py` 또는 `aws_console_login_without_mfa.yml` 파일—파생된 디택션에서 오버라이드를 추가한 필드에 대한 변경이 아닌 한, 수동으로 파생된 디택션을 업데이트하지 않아도 변경 사항이 자동으로 반영됩니다. 가장 중요한 점은 병합 충돌이 발생하지 않는다는 것입니다.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.panther.com/ko/detections/rules/derived/using-derived-detections-to-avoid-merge-conflicts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
