# PantherFlow 문

## 개요

{% hint style="info" %}
PantherFlow는 Panther 버전 1.110부터 오픈 베타로 제공되며, 모든 고객이 사용할 수 있습니다. 버그 보고 및 기능 요청이 있으면 Panther 지원팀에 공유해 주세요.
{% endhint %}

PantherFlow 쿼리는 하나 이상의 문으로 구성됩니다. 문에는 두 가지 유형이 있습니다: [표 형식 표현식 문](#tabular-expression-statements) 및 [`let` 문](#let-statements).

같은 쿼리 안의 여러 문은 세미콜론(`;`)으로 구분해야 합니다. 마지막 문에는 세미콜론이 필요하지 않습니다.

## 표 형식 표현식 문

표 형식 표현식 문은 보통 "파이프드 쿼리"라고 들을 때 떠올리는 것입니다—데이터 원본과 일반적으로 하나 이상의 연산자로 구성되며, 파이프 문자(`|`)로 구분됩니다. 각 연산자는 데이터를 받아 작업을 수행한 다음, 변환된 데이터를 다음 연산자에 전달합니다.

{% hint style="info" %}
다음의 [검색](https://docs.panther.com/ko/search/search-tool#using-pantherflow-in-search), 데이터베이스와 테이블 이름(아래에 표시됨) 또는 `union` 연산자로 쿼리를 시작할 수 있습니다. 이 둘 중 어느 것도 제공되지 않으면 Search는 [데이터베이스 및 테이블 드롭다운 필드](https://docs.panther.com/ko/search/search-tool#using-database-table-and-date-range-filters).
{% endhint %}

```kusto
panther_logs.public.aws_cloudtrail
| where accountId != '1234567'
| summarize Count=agg.count() by eventName
| extend tooHigh = Count > 100
| where tooHigh
| sort Count
| limit 10
```

### 데이터 원본

각 PantherFlow 쿼리에는 데이터 원본을 지정해야 합니다. 다음 중 아무 것이나 데이터 원본으로 사용할 수 있습니다:

* 표 형식 표현식 문
* [테이블 변수](#table-variables)
* [`datatable`](https://docs.panther.com/ko/pantherflow/operators/datatable)
* [`union`](https://docs.panther.com/ko/pantherflow/operators/union)
* [`range`](https://docs.panther.com/ko/pantherflow/operators/range)

## `let` 문

A `let` 문은 변수에 값을 할당하며, 이 변수는 이후의 문에서 사용할 수 있습니다. `let` 문은 두 가지 유형의 변수를 정의할 수 있습니다:

* **테이블 변수**: 표 형식 표현식을 나타내며, 나중에 테이블처럼 사용할 수 있음
* **스칼라 변수**: 스칼라 값을 나타내거나, 스칼라 값으로 평가되는 표현식

변수는 참조되기 전에 `let` 문에서 정의되어야 합니다. 모든 `let` 문은 다른 문이 뒤따를 경우 세미콜론(`;`)으로 끝나야 합니다.

### 테이블 변수

테이블 변수는 `let`를 사용해 표 형식 표현식 문을 변수에 할당할 때 생성됩니다. 그러면 이를 표 형식 표현식 문처럼 참조할 수 있습니다(즉, 가능한 [데이터 원본](#data-sources)).

테이블 변수에 할당된 표 형식 표현식 문은 이후 문에서 해당 변수가 참조되거나 "호출"될 때까지 실행되지 않습니다.

다음과 같은 경우 테이블 변수로 쿼리에 이름을 지정하는 것이 유용할 수 있습니다:

* 같은 쿼리를 두 번 이상 작성하고 싶지 않을 때
* 다른 사람들이 쿼리가 무엇을 하는지 더 쉽게 이해하도록 하고 싶을 때

**예시**

다음 예제는 테이블 변수 `elbOK`를 선언합니다. 아래에서 `elbOK` 는 `let` 문에서 정의된 그대로 정확히 실행됩니다:

```kusto
let elbOK = panther_logs.public.aws_alb
| where elbStatusCode == 200;

elbOK
```

여기서 추가 연산자가 `elbOK` 표 형식 표현식 문 내에서 적용됩니다:

```kusto
let elbOK = panther_logs.public.aws_alb
| where elbStatusCode == 200;

elbOK 
| where p_event_time > time.ago(1h)
```

테이블 변수를 데이터셋을 참조하는 곳이면 어디에서나 사용할 수 있으며, 다음도 포함됩니다: [`union` 연산자](https://docs.panther.com/ko/pantherflow/operators/union):

```kusto
let ec2Events = panther_logs.public.aws_cloudtrail
| where p_event_time > time.ago(1h)
| where eventSource == "ec2.amazonaws.com";

let s3Events = panther_logs.public.aws_cloudtrail
| where p_event_time > time.ago(1h)
| where eventSource == "s3.amazonaws.com";

union ec2Events, s3Events
| summarize count=agg.count() by eventName, eventSource
| sort count desc
```

### 스칼라 변수

스칼라 변수는 비표 형식 표현식을 변수에 할당할 때 생성됩니다. 그런 다음 스칼라 변수는 이후의 쿼리 전반에서 참조할 수 있습니다.

스칼라 변수를 선언하는 것은 다음과 같은 경우 유용할 수 있습니다:

* 특히 같은 값을 여러 번 사용할 때 쿼리를 더 읽기 쉽고 유지 관리하기 쉽게 만들기
* 그렇지 않으면 오해될 수 있는 값에 이름 붙이기

아래의 [스칼라 변수 제한 사항을 참고하세요](#scalar-variable-limitations).

#### **예시**

다음 예제는 스칼라 변수 `threshold`를 선언한 다음, 이를 [`where`](https://docs.panther.com/ko/pantherflow/operators/where) 절에서 참조합니다:

```kusto
let threshold = 100;

panther_logs.public.aws_cloudtrail
| where p_event_time > time.ago(1d)
| summarize count=agg.count() by eventName
| where count > threshold
```

스칼라 변수의 값은 [함수](https://docs.panther.com/ko/pantherflow/functions)를 사용할 수 있으며, 스칼라 변수는 함수의 매개변수로 사용할 수 있습니다:

```kusto
let domain = "example.com";
let searchSuffix = strings.cat("@", domain);

panther_logs.public.aws_cloudtrail
| where strings.ends_with(userIdentity.principalId, searchSuffix)
| summarize count=agg.count() by eventName
```

스칼라 변수와 함께 산술 표현식도 사용할 수 있습니다:

```kusto
let hourInSeconds = 60 * 60;
let dayInSeconds = hourInSeconds * 24;
let weekInSeconds = dayInSeconds * 7;

panther_logs.public.aws_cloudtrail
| extend ageInSeconds = time.diff("s", p_event_time, time.now())
| extend ageCategory = case(
    ageInSeconds < hourInSeconds, "1시간 미만",
    ageInSeconds < dayInSeconds, "1일 미만",
    ageInSeconds < weekInSeconds, "1주 미만",
    "1주 초과"
)
| summarize count=agg.count() by ageCategory
```

강력한 쿼리를 위해 스칼라 변수와 테이블 변수를 함께 사용할 수 있습니다:

```kusto
// 스칼라 변수
let minSeverity = 3;
let timeRange = 7d;
let criticalServices = ["ec2.amazonaws.com", "iam.amazonaws.com", "s3.amazonaws.com"];

// 테이블 변수
let baseQuery = panther_logs.public.aws_cloudtrail
| where p_event_time > time.ago(timeRange)
| where eventSource in criticalServices;

// 테이블 변수
let failedActions = baseQuery
| where errorCode != ""
| extend severity = case(
    errorCode == "AccessDenied", 4,
    errorCode == "UnauthorizedOperation", 3,
    strings.starts_with(errorCode, "Client"), 2,
    1
);

// 표 형식 표현식 문
failedActions
| where severity >= minSeverity
| summarize count=agg.count() by eventSource, errorCode, severity
| sort severity desc, count desc
```

### 변수 명명 규칙

변수 이름은 다음 규칙을 따라야 합니다:

* 첫 글자는 문자, 밑줄(`_`), 또는 달러 기호(`$`).
* )여야 합니다. 첫 글자 이후의 문자는 문자, 숫자, 또는 밑줄이어야 합니다.
* 기존 테이블 이름은 변수 이름으로 사용할 수 없습니다.
  * 예를 들어, 이미 `aws_cloudtrail`라는 이름의 테이블이 있다면 `aws_cloudtrail` 를 변수 이름으로 사용할 수 없습니다.
* 한 번 사용된 변수 이름은 같은 PantherFlow 검색에서 다시 사용할 수 없습니다. 즉, 변수는 재정의할 수 없습니다.

**예시**

<table><thead><tr><th width="158.21954345703125">유효한 변수 이름</th><th width="360.1328125">유효하지 않은 변수 이름</th></tr></thead><tbody><tr><td><code>myVar123</code></td><td><code>123myVar</code> (숫자로 시작)</td></tr><tr><td><code>my_var</code></td><td><code>my-var</code> (잘못된 문자)</td></tr><tr><td><code>_my_var</code></td><td><code>my.var</code> (잘못된 문자)</td></tr><tr><td><code>$my_var</code></td><td><code>my_var$</code> (<code>$</code> 첫 글자에만 허용)</td></tr></tbody></table>
