# 전역 도우미 함수

## 개요

프로그래밍에서 흔한 패턴은 반복되는 코드를 헬퍼 함수로 추출하는 것입니다—Panther는 이 패턴을 `global` 분석 유형으로 지원합니다. Panther는 여러 [내장 전역 헬퍼](#built-in-globals)를 제공하며, 또한 [사용자 지정 전역을 직접 추가할 수 있습니다](#adding-custom-globals). 특정 [일반적인 헬퍼](#common-helpers) 에 대해 아래에서 자세히 알아보세요.

{% hint style="warning" %}
전역 헬퍼는 잦은 변경에 가장 적합한 방식은 아닙니다. 변경을 자주 해야 *하는* 경우에는 대신 [사용자 지정 조회 테이블](https://docs.panther.com/ko/enrichment/custom)을 사용하는 것을 고려하세요. 이는 S3와의 자동 동기화를 지원하며, 업데이트를 위해 Panther 내부의 코드를 변경할 필요가 없습니다.
{% endhint %}

## Panther 관리 전역

기본적으로 Panther는 다음과 같은 내장 전역 헬퍼 모음을 제공합니다:

* [`panther_base_helpers`](https://github.com/panther-labs/panther-analysis/blob/main/global_helpers/panther_base_helpers.py): 다양한 일반 헬퍼와 로그 소스별 헬퍼를 포함합니다. 에 정의된 특정 함수에 대해서는 `panther_base_helpers` 아래의  [일반적인 헬퍼](#common-helpers).
* [`panther_디택션_helpers`](https://docs.panther.com/ko/detections/rules/caching#cache-helper-functions-in-panther_detection_helpers): 캐싱 함수를 제공합니다. Python Rules Caching의 `panther_디택션_helpers` 패키지 [에서 자세히 알아보세요](https://docs.panther.com/ko/detections/rules/caching#cache-helper-functions-in-panther_detection_helpers).

### Panther 관리 전역 사용자 지정

일부 전역은 허용 목록에 대한 값을 제공하는 것과 같이 사용자의 구성 입력이 필요합니다. 로직 수정이나 사용자 지정 메서드 추가와 같은 더 큰 변경이 필요하다면, 일반적으로 [새 전역을 만드는 것](#adding-custom-globals) 을 해당 항목에 대해 권장합니다. 이렇게 하면 디택션 소스를 업데이트할 때 복잡한 병합 충돌을 처리해야 할 가능성이 줄어듭니다.

그래도 전역 헬퍼를 수정하고 싶다면, 다음 Panther Knowledge Base 문서를 참조하세요: [Panther 관리 전역 헬퍼 함수를 사용자 지정하는 가장 좋은 방법은 무엇인가요?](https://help.panther.com/articles/3976369474-managing-panther-global-helpers-overwriting-vs-cloning)

## 전역 사용하기

### 전역 보기

{% tabs %}
{% tab title="콘솔" %}

* 콘솔에서 Panther 제공 헬퍼 파일과 사용자 지정 헬퍼 파일을 보려면, Panther Console의 왼쪽 탐색 모음에서 **Detections,** 를 클릭한 다음 **Helpers** 탭을 클릭하면 Panther Console에서 Panther가 제공하는 디택션 팩 목록을 볼 수 있습니다.

<figure><img src="https://2400888838-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-6813c95d1619d99e9bc013275a7e20dd827644ff%2FScreenshot%202024-07-31%20at%203.15.11%20PM.png?alt=media" alt="An arrow is drawn from &#x22;Detections&#x22; to &#x22;Helpers,&#x22; and a page titled &#x22;Helpers is shown, with a table with various entries, including &#x22;crowdstrike_event_streams_helpers&#x22; and &#x22;gcp_environment&#x22;." width="563"><figcaption></figcaption></figure>
{% endtab %}

{% tab title="CLI 워크플로" %}

* CLI 워크플로에서 Panther 제공 헬퍼 파일을 보려면 [`global_helpers` 디렉터리의 `panther-analysis` GitHub 리포지토리](https://github.com/panther-labs/panther-analysis/tree/main/global_helpers).
  {% endtab %}
  {% endtabs %}

### 사용자 지정 전역 추가

새 전역은 [Panther Analysis Tool](https://docs.panther.com/ko/panther/detections-repo/pat) 또는 Panther Console에서 생성할 수 있습니다.

{% hint style="warning" %}
Panther의 디택션 내에서 외부 API 요청을 수행하는 것은 강력히 권장되지 않습니다. 일반적으로 디택션은 매우 큰 규모로 처리되며, API 요청을 수행하면 요청을 받는 시스템에 과부하를 일으키고 규칙이 [15초 런타임 제한](https://docs.panther.com/ko/detections/rules/..#rule-errors-and-scheduled-rule-errors).
{% endhint %}

{% tabs %}
{% tab title="Panther Console" %}
Panther Console에서 새 전역을 만들려면:

1. Panther Console의 왼쪽 탐색 표시줄에서 **Detections**.
2. 을 클릭합니다. **Helpers** 탭을 클릭하면 Panther Console에서 Panther가 제공하는 디택션 팩 목록을 볼 수 있습니다.
3. 오른쪽 상단 모서리에서 **Create New**.\
   ![On the Helpers page in the Panther Console, there is a blue "Create New" button in the upper right.](https://2400888838-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-844434c91c2f59fec117f94d881083449c99145a%2FScreen%20Shot%202022-08-02%20at%2012.05.56%20PM.png?alt=media)
4. Python 함수를 입력한 다음 다음을 클릭합니다 **생성**. 이 글로벌은 이제 룰 또는 정책에서 가져올 수 있습니다.

<figure><img src="https://2400888838-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-4a8b9c1f86be5217aeba66283489794d1c67028a%2Fhelper-setting.png?alt=media" alt="The Helper Settings page shows fields for Helper Name and Description. Under Helper Definition, there is a code block with sample Python code written in it."><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Panther Analysis Tool" %}
글로벌 함수는 공통 로직을 룰 또는 정책 전반에서 공유할 수 있게 합니다. 이를 코드로 선언하려면 `global_helpers` 폴더에 룰 및 정책과 유사한 패턴으로 추가하세요.

{% hint style="info" %}
다음 폴더 외부에 정의된 글로벌은 `global_helpers` 로드되지 않습니다.
{% endhint %}

1. Python 파일을 생성합니다 (`global_helpers/acmecorp.py`):

```python
from fnmatch import fnmatch

RESOURCE_PATTERN = 'acme-corp-*-[0-9]'


def matches_internal_naming(resource_name):
  return fnmatch(resource_name, RESOURCE_PATTERN)
```

2\. 사양 파일을 생성합니다:

```yaml
AnalysisType: global
GlobalID: acmecorp
Filename: acmecorp.py
Description: acme-corp 내부용 헬퍼 세트
```

3\. 정책(또는 룰)에서 이 헬퍼를 사용합니다:

```python
import acmecorp


def policy(resource):
  return acmecorp.matches_internal_naming(resource['Name'])
```

{% endtab %}
{% endtabs %}

### 탐지에서 글로벌 가져오기

분석 파일 맨 위에서 `import` 문을 사용하여 글로벌 헬퍼를 가져온 다음, 다른 Python 라이브러리와 마찬가지로 헬퍼를 호출합니다.

예를 들면 다음과 같습니다:

```python
import panther_aws_helpers

def 룰(event):
  return event['name'] == 'test-bucket'

def title(event):
  # 계정 ID로 계정 이름 조회
  account_name = panther_aws_helpers.lookup_aws_account_name(event['accountId'])
  return '계정 ' + account_name + '에 수상한 요청이 수행되었습니다'
```

### 탐지에서 헬퍼 함수 참조 제거

* 탐지에서 종속성을 제거하기로 결정한 경우, 다음을 권장합니다 [변경 사항을 단계적으로 적용하는 것](https://help.panther.com/Detections/Detection_Features/Why_do_I_receive_rule_import_errors_after_removing_helper_functions_from_my_Panther_detection%3F).

## 일반적인 헬퍼

### `deep_get()`

{% hint style="warning" %}
`deep_get()` 은(는) 다음으로도 사용할 수 있습니다 [이벤트 객체 자체의 함수](https://docs.panther.com/ko/detections/rules/python/..#deep_get). 편의를 위해 이 글로벌 헬퍼 함수 대신 해당 이벤트 함수를 사용하는 것이 좋습니다.
{% endhint %}

다음 위치에 있으며 [panther\_base\_helpers](https://github.com/panther-labs/panther-analysis/blob/master/global_helpers/panther_base_helpers.py).

`deep_get()` Python 딕셔너리 내에 중첩된 키를 반환하는 데 사용할 수 있습니다. 이 함수는 중첩된 키를 안전하게 반환하고 `AttributeError` 키가 존재하지 않을 때 이를 방지하는 데 유용합니다.

액세스하려는 키가 목록 내부에 중첩되어 있다면, [`deep_walk()`](#deep_walk) 를 대신 사용하는 것을 고려하세요.

#### 예시

다음 JSON에서 deep\_get 함수는 result의 값을 반환합니다.

```python
{ "outcome": { "reason": "VERIFICATION_ERROR", "result": "FAILURE" }}
```

```python
deep_get(event, "outcome", "result") == "FAILURE"
```

다음 항목에서 찾을 수 있습니다. [Geographically Improbable Okta Login](https://github.com/panther-labs/panther-analysis/blob/cd220c87982011d4ad156c7daecd2857c358d154/rules/okta_rules/okta_geo_improbable_access.py) 디택션.

#### default

`deep_get()` 는 선택적 `default` 매개변수를 받습니다. 키가 예상 위치에 없거나 해당 위치의 값이 `None`이면, 기본값이 반환됩니다.

```python
deep_get(event, "outcome", "nonexistent_key", default="Key Not Found") == "Key Not Found"
```

### `deep_walk()`

{% hint style="warning" %}
`deep_walk()` 은(는) 다음으로도 사용할 수 있습니다 [이벤트 객체 자체의 함수](https://docs.panther.com/ko/detections/rules/python/..#deep_walk). 편의를 위해 이 글로벌 헬퍼 함수 대신 해당 이벤트 함수를 사용하는 것이 좋습니다.
{% endhint %}

다음 위치에 있으며 [panther\_base\_helpers](https://github.com/panther-labs/panther-analysis/blob/3ecca4a198646ab6dcad0320968fe075420572a7/global_helpers/panther_base_helpers.py#L313-L370).

`deep_walk()` 는 Python 딕셔너리에서 깊게 중첩된 키와 연결된 값을 반환하는 데 사용할 수 있으며, 딕셔너리나 리스트가 여러 개 포함될 수 있습니다. 이 기능은 `deep_walk()` 와 [`deep_get()`](#deep_get).

에서 핵심적인 차이점입니다. `deep_get()`와 마찬가지로, 이 탐색은 안전하며 어떤 예외나 오류도 방지합니다. 구조에 키가 없으면 기본값이 반환됩니다.

#### 예시

다음 객체가 주어지면, `deep_walk()` 는 다음의 값을 반환합니다. `very_nested_key`:

<pre class="language-json"><code class="lang-json"><strong>{"key": {"multiple_nested_lists_with_dict": [[[{"very_nested_key": "very_nested_value"}]]]}}
</strong></code></pre>

```python
deep_walk(event, "key", "multiple_nested_lists_with_dict", "very_nested_key", default="") == "very_nested_value"
```

다음 항목에서 찾을 수 있습니다. [GCP Service Account Access Denied](https://github.com/panther-labs/panther-analysis/blob/master/rules/gcp_audit_rules/gcp_service_account_access_denied.py) 디택션.

#### default

와 마찬가지로 `deep_get()`, `deep_walk()` 는 선택적 `default` 매개변수를 받습니다. 제공된 이벤트에 키가 없거나, 키가 `None`이거나, 키가 빈 리스트이면 기본값이 대신 반환됩니다.

위의 예시를 사용하면:

```python
deep_walk(event, "key", "multiple_nested_lists_with_dict", "very_nested_nonexistent_key", default="") == ""
```

#### return\_val

와 달리 `deep_get()`, `deep_walk()` 는 세 가지 서로 다른 값 분류를 반환할 수 있습니다:

* `all`
* `first`
* `last`

**`all`**

기본적으로, `deep_walk()` 를 호출하면 다음을 반환합니다. `all` 주어진 키의 값을 반환합니다. 이는 이벤트에 동일한 키가 중복되어 있을 때 유용합니다. 그러나 `all` 가 반환한 값의 수가 하나이면 그 값만 반환됩니다.

예를 들면 다음과 같습니다:

```json
{"key": {"inner_key": [{"nested_key": "nested_value"}, {"nested_key": "nested_value2"}]}}
```

```python
deep_walk(event, "key", "inner_key", "nested_key", default="") == ['nested_value', 'nested_value2']
```

를 사용할 때 `all` 그리고 여러 값을 반환하는 경우, 리스트의 요소는 다른 Python 리스트처럼 접근할 수 있습니다.

**`first`**

키에 대해 처음 발견된 값만 반환하려면 `return_val="first"`.

예를 들면 다음과 같습니다:

```python
deep_walk(event, "key", "inner_key", "nested_key", default="", return_val="first") == "nested_value"
```

**`last`**

키에 대해 마지막으로 발견된 값만 반환하려면 `return_val="last"`.

예를 들면 다음과 같습니다:

```python
deep_walk(event, "key", "inner_key", "nested_key", default="", return_val="last") == "nested_value2"
```

### `is_ip_in_network()`

다음 위치에 있으며 [panther\_base\_helpers](https://github.com/panther-labs/panther-analysis/blob/master/global_helpers/panther_base_helpers.py).

`is_ip_in_network()` 는 IP 주소가 IP 범위 목록 안에 있는지 확인하는 함수입니다. 이 함수는 알려진 내부 네트워크 목록과 함께 사용하여 디택션에 추가적인 맥락을 더할 수 있습니다.

예시:

```python
SHARED_IP_SPACE = [
    "192.168.0.0/16",
]

if is_ip_in_network(event.get("ipaddr"), SHARED_IP_SPACE):
    ...
```

예제는 다음에서 찾을 수 있습니다. [OneLogin Active Login Activity](https://github.com/panther-labs/panther-analysis/blob/cd220c87982011d4ad156c7daecd2857c358d154/rules/onelogin_rules/onelogin_active_login_activity.py) 디택션.

### `pattern_match()`

다음 위치에 있으며 [panther\_base\_helpers](https://github.com/panther-labs/panther-analysis/blob/master/global_helpers/panther_base_helpers.py).

래퍼로 감싼 [fnmatch](https://docs.python.org/3/library/fnmatch.html) 기본 패턴 글롭용입니다. 이는 정규식을 사용할 필요 없이 단순한 패턴 매칭이 필요할 때 사용할 수 있습니다.

예시:

다음 JSON에서 pattern\_match() 함수는 true를 반환합니다.

```python
{ "operation": "REST.PUT.OBJECT" }
```

```python
pattern_match(event.get("operation", ""), "REST.*.OBJECT")
```

예제는 AWS S3 Access Error 디택션에서 찾을 수 있습니다.

### `pattern_match_list()`

다음 위치에 있으며 [panther\_base\_helpers](https://github.com/panther-labs/panther-analysis/blob/master/global_helpers/panther_base_helpers.py).

와 유사하게 `pattern_match()`, `pattern_match_list()` 문자열이 주어진 목록의 어떤 패턴과 일치하는지 확인할 수 있습니다.

예시:

다음 JSON에서 pattern\_match\_list() 함수는 true를 반환합니다.

```python
{ "userAgent": "aws-sdk-go/1.29.7 (go1.13.7; darwin; amd64) APN/1.0 HashiCorp/1.0 Terraform/0.12.24 (+https://www.terraform.io)" }
```

```python
ALLOWED_USER_AGENTS = {
    "* HashiCorp/?.0 Terraform/*",
    # 'console.ec2.amazonaws.com',
    # 'cloudformation.amazonaws.com',
}

pattern_match_list(event.get("userAgent"), ALLOWED_USER_AGENTS)
```

예제는 다음에서 찾을 수 있습니다. [AWS EC2 수동 보안 그룹 변경](https://github.com/panther-labs/panther-analysis/blob/cd220c87982011d4ad156c7daecd2857c358d154/rules/aws_cloudtrail_rules/aws_ec2_security_group_modified.py) 디택션.

### `aws_strip_role_session_id()`

다음 위치에 있으며 [panther\_aws\_helpers](https://github.com/panther-labs/panther-analysis/blob/main/global_helpers/panther_aws_helpers.py).

`aws_strip_role_session_id()` arn에서 세션 ID를 제거합니다.

예시:

다음 값으로, `aws_strip_role_session_id()` 는 다음을 반환합니다 `arn:aws:sts::123456789012:assumed-role/demo`

```python
{ "arn": "arn:aws:sts::123456789012:assumed-role/demo/sessionName" }
```

```python
aws_strip_role_session_id(user_identity.get("arn", ""))
```

예제는 다음에서 찾을 수 있습니다. [AWS 승인되지 않은 API 호출](https://github.com/panther-labs/panther-analysis/blob/main/rules/aws_cloudtrail_rules/aws_unauthorized_api_call.py) 디택션.

### `is_base64()`

다음 위치에 있으며 [panther\_base\_helpers](https://github.com/panther-labs/panther-analysis/blob/master/global_helpers/panther_base_helpers.py).

`is_base64()` 문자열이 base64로 인코딩되었는지 확인하고, 그렇다면 디코딩된 문자열을 반환합니다. 그렇지 않으면 빈 문자열을 반환합니다.

예제는 다음에서 확인하세요. [`Crowdstrike.Base64EncodedArgs` 디택션](https://github.com/panther-labs/panther-analysis/blob/release/rules/crowdstrike_rules/crowdstrike_base64_encoded_args.py).

### `get_string_set()`

다음 위치에 있으며 [panther\_디택션\_helpers](https://pypi.org/project/panther-detection-helpers/). 다음에 대해 자세히 알아보세요. `panther_디택션_helpers` 패키지 [에서 자세히 알아보세요](https://docs.panther.com/ko/detections/rules/caching#cache-helper-functions-in-panther_detection_helpers).

`get_string_set` 는 키를 기반으로 Panther가 관리하는 캐시에서 값을 가져오는 데 사용됩니다. 이는 디택션 호출 간 상태를 검색하는 데 유용합니다.

[panther-analysis에서 사용된 예제는 여기에서 찾을 수 있습니다](https://github.com/panther-labs/panther-analysis/blob/a0b6039dbe1966d29ddd80937b9a790a59ef9cfe/rules/standard_rules/impossible_travel_login.py#L105-L106).

### `put_string_set()`

다음 위치에 있으며 [panther\_디택션\_helpers](https://pypi.org/project/panther-detection-helpers/). 다음에 대해 자세히 알아보세요. `panther_디택션_helpers` 패키지 [에서 자세히 알아보세요](https://docs.panther.com/ko/detections/rules/caching#cache-helper-functions-in-panther_detection_helpers).

`put_string_set` 는 키를 기반으로 Panther가 관리하는 캐시에 값을 저장하는 데 사용됩니다. 이는 디택션 호출 간 상태를 저장하는 데 유용합니다.

[panther-analysis에서 사용된 예제는 여기에서 찾을 수 있습니다](https://github.com/panther-labs/panther-analysis/blob/a0b6039dbe1966d29ddd80937b9a790a59ef9cfe/rules/standard_rules/impossible_travel_login.py#L111-L115).
