> For the complete documentation index, see [llms.txt](https://genos-docs.gitbook.io/default/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://genos-docs.gitbook.io/default/v1.9.5/admin-management/settings/workflow-forward-headers.md).

# 워크플로우 전파 헤더

## 개요

사용자 요청에 실려 온 HTTP 헤더 중 **일부를 워크플로우 실행 경로 끝(도구 호출)까지 전달**하는 기능입니다. 기존에는 어떤 헤더를 전달할지가 서비스별 소스코드에 흩어져 하드코딩돼 있어, 신규 커스텀 헤더(예: 고객사 연동용 `X-SRN-ID` 등)를 추가하려면 매번 코드 수정·배포가 필요했습니다.

이 기능은 전달 대상 헤더를 **GenOS configmap(`WORKFLOW_FORWARD_HEADERS` / `WORKFLOW_FORWARD_HEADERS_DENY`)에서 관리**하도록 바꿉니다. 이제 신규 헤더는 **코드 변경 없이 configmap에 이름만 추가**하면 전파됩니다. 관리자·운영 담당이 대상 클러스터의 configmap을 편집해 사용합니다.

## 주요 개념

| 개념                                         | 설명                                                                                                                               |
| ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| 전파 헤더(forward header)                      | 사용자 요청 헤더 중 워크플로우/도구 호출까지 실어 보내는 헤더                                                                                              |
| allowlist (`WORKFLOW_FORWARD_HEADERS`)     | 전파할 헤더 이름 목록. 콤마 구분·대소문자 무시                                                                                                      |
| denylist (`WORKFLOW_FORWARD_HEADERS_DENY`) | allowlist 통과분 중 **제외**할 헤더 목록. allow 이후 적용                                                                                       |
| 와일드카드                                      | `*` = 전량 매칭 / `prefix-*` = 접두사 매칭 (예: `x-srn-*`)                                                                                 |
| subject 키                                  | 게이트웨이 라우팅·세션에 필요한 기본 식별 헤더(`x-genos-user-id`·`-group-id`·`-auth-key-id`·`-session-id`). 사용자 요청에서 받는 값이 아니라 **게이트웨이가 직접 싣는 값**입니다 |
| 서버 예약 헤더                                   | 진입 서비스가 사용자 요청에서 **절대 전달하지 않는** 헤더. `x-genos-`·`x-forwarded-`·`proxy-`로 시작하는 헤더와 `authorization`·`cookie` 등 서버가 정하는 헤더           |
| 재방출(re-emit)                               | flowise가 워크플로우 vars에서 헤더를 꺼내 도구/서빙 호출 헤더로 다시 실어 보내는 단계                                                                           |

## 전파 체인

전파 헤더는 진입 서비스부터 도구 호출까지 5개 지점을 거칩니다. 각 구간이 같은 allow/deny 규약을 씁니다.

```
[사용자 요청 헤더]
   │  ① 진입: genportal-api(채팅) / admin-api(워크플로우 테스트) ── 요청 헤더에서 전파 대상 선별(서버 예약 헤더 제외)
   ▼
[gateway-api] ── ② WorkflowClient: subject 키 + 전파 헤더를 워크플로우 요청에 병합
   ▼
[workflow pod] ── ③ run_util_v2: overrideConfig.vars 에 헤더 주입 + 재방출 키 목록 기록
   ▼
[flowise] ── ④ getGenosSubjectHeaders: subject 키 ∪ 재방출 키 목록만 도구/서빙 호출 헤더로 재방출
   ▼
[도구 호출(GenosMCP 등)] ── ⑤ 최종적으로 헤더 수신
```

* **관리자 화면 "워크플로우 테스트"**(admin-front) 경로도 동일하게 전파됩니다(admin-api `deploy_test`). 실서비스와 같은 헤더가 도구까지 흐르므로 테스트 시 실동작을 그대로 확인할 수 있습니다.
* **`*` 와일드카드로 수집**하더라도, 도구로 **재방출되는 것은 실제 매칭된 concrete 헤더 목록뿐**입니다(워크플로우 내부 vars 전량을 훑지 않음). → 내부 설정값 유출 방지(§보안 고려사항).

## 설정 방법

전파 목록은 두 configmap에 있고, **두 목록은 일부러 다르게 둡니다.** 사용자 요청을 직접 받는 쪽과, 게이트웨이를 거친 뒤의 내부 구간은 믿을 수 있는 범위가 다르기 때문입니다.

| configmap                             | 읽는 서비스                                  | 역할                                                 |
| ------------------------------------- | --------------------------------------- | -------------------------------------------------- |
| `llmops-global-configmap`             | genportal-api · gateway-api · admin-api | 사용자 요청에서 받아들일 헤더. **과금 관련 헤더를 넣으면 안 됩니다**          |
| `llmops-container-services-configmap` | workflow pod (run\_util\_v2)            | 게이트웨이를 통과한 뒤 도구·서빙까지 넘길 헤더. 과금 면제·귀속 헤더가 여기에만 있습니다 |

> 과금 관련 헤더(`x-genos-credit-exempt`·`x-genos-credit-subject`·`x-genos-chat-service-id`·`x-genos-chat-service-revision-id` 등)를 `llmops-global-configmap` 쪽 목록에 넣으면, 사용자가 헤더 하나로 과금 면제나 낮은 배수를 주장할 수 있게 됩니다. **container-services 쪽 값을 global 쪽에 그대로 복사하지 마세요.**

경로: `k8s-manifests/llmops/llmops-configmaps/`. 기본값은 다음과 같습니다.

```yaml
# llmops-global-configmap
WORKFLOW_FORWARD_HEADERS: "x-genos-user-id,x-genos-group-id,x-genos-auth-key-id,x-genos-session-id,x-genos-access-token,x-genos-loadtest-run-id"
WORKFLOW_FORWARD_HEADERS_DENY: "authorization,cookie,host,…,x-genos-headers-*,x-genos-body-*,x-genos-params-*"   # 서버 예약 헤더 전체(2차 방어선)

# llmops-container-services-configmap
WORKFLOW_FORWARD_HEADERS: "x-genos-user-id,x-genos-group-id,x-genos-auth-key-id,x-genos-session-id,x-genos-chat-service-id,x-genos-chat-service-revision-id,x-genos-credit-exempt,x-genos-credit-subject,x-genos-billing-turn-id,x-genos-agw-hop,x-genos-agw-hop-corr,x-genos-agw-session,x-genos-loadtest-run-id"
WORKFLOW_FORWARD_HEADERS_DENY: ""
```

global 쪽 deny 목록은 서버 예약 헤더를 한 번 더 막는 2차 방어선입니다. 1차 방어선은 진입 서비스 코드가 서버 예약 헤더를 막는 것이라, deny 목록을 빠뜨려도 막힙니다. 그래도 두 목록은 함께 유지합니다.

### 매칭 규칙

* **콤마 구분**, 앞뒤 공백은 무시. 빈 항목은 건너뜀.
* **대소문자 무시** — 설정값·요청 헤더 모두 소문자로 정규화해 비교하고, 전달 키도 소문자로 나갑니다(`X-SRN-ID` → `x-srn-id`).
* **와일드카드**: `*`(전량) · `prefix-*`(접두사, 예 `x-srn-*`) · 그 외는 정확히 일치.
* **deny는 allow 다음**에 적용 — allow에 걸린 헤더라도 deny에 걸리면 제외됩니다.
* 값이 비어 있는(`""`·없음) 요청 헤더는 전달하지 않습니다.
* **서버 예약 헤더는 allowlist와 상관없이 사용자 요청에서 전달되지 않습니다.** 진입 서비스(genportal-api·admin-api)가 `x-genos-`·`x-forwarded-`·`proxy-`로 시작하는 헤더와 서버가 정하는 헤더(`authorization`·`cookie`·`x-genos-user-id` 등)를 코드에서 막습니다. 그래서 커스텀 헤더 이름은 **이 접두사를 피해서** 정해야 합니다.

### 신규 커스텀 헤더 추가 (예: 고객사 연동)

전달할 헤더 이름을 **두 configmap의 allowlist 끝에 각각 추가**합니다. 소스 수정은 필요 없습니다. 이때 각 목록의 기존 값은 그대로 두고 커스텀 헤더 이름만 더합니다.

```yaml
# llmops-global-configmap
WORKFLOW_FORWARD_HEADERS: "<기존 값>,x-srn-id,x-inc-indv,x-trace-id,x-env-cd"
WORKFLOW_FORWARD_HEADERS_DENY: "<기존 값>,x-cert-key"

# llmops-container-services-configmap
WORKFLOW_FORWARD_HEADERS: "<기존 값>,x-srn-id,x-inc-indv,x-trace-id,x-env-cd"
```

위 예시는 `x-srn-id`·`x-inc-indv`·`x-trace-id`·`x-env-cd`를 추가로 전파하고, 민감한 `x-cert-key`는 제외합니다.

### 설정 반영

configmap 값은 **파드 기동 시 환경변수로 로드**됩니다. 변경 후에는 해당 서비스 파드를 **롤아웃(재시작)** 해야 반영됩니다(global → genportal/gateway/admin, container-services → workflow).

## 기본값과 동작

* 기본값은 위 「설정 방법」의 값입니다. 사용자 요청 쪽(global) allowlist에 있는 항목은 모두 `x-genos-`로 시작하는 서버 예약 헤더라, **기본 상태에서 사용자 요청 헤더가 이 메커니즘으로 전파되는 일은 없습니다.** subject 키는 게이트웨이가 직접 싣습니다.
* 커스텀 헤더를 흘리려면 운영 담당이 위 예시처럼 두 allowlist에 이름을 추가합니다.
* allowlist가 비어 있으면(`""`) 이 메커니즘으로는 아무 헤더도 전파하지 않습니다(게이트웨이가 기본으로 싣는 subject 키 전파는 별개로 유지).

## 보안 고려사항

* **내부 vars 유출 방지**: flowise는 워크플로우 vars 전체를 훑지 않고, run\_util\_v2가 넘긴 **concrete 재방출 키 목록(subject 키 + allow 매칭 헤더)만** 도구 호출에 재방출합니다. DB 접속정보·`security_level` 등 프레임워크 내부 vars는 목록에 없어 재방출되지 않습니다.
* **재방출 목록은 클라이언트가 조작 불가**: 요청자가 `x-genos-forward-header-keys` 같은 메타 헤더를 직접 보내도, run\_util\_v2가 allowlist 기준으로 재계산해 덮어씁니다.
* **과금 헤더는 사용자 요청에서 받지 않음**: 과금 면제·귀속 헤더는 container-services 쪽 목록에만 있고, 사용자 요청에서는 서버 예약 헤더로 막힙니다. global 쪽 목록에 옮기지 마세요.
* **토큰 노출 방지**: `x-genos-access-token`·`Authorization` 등 토큰은 사용자 요청에서 전파되지 않습니다(서버 예약 헤더). 재방출된 헤더는 도구/서빙 **요청 헤더**로만 나가며 사용자 응답 본문에는 실리지 않습니다.
* **`*` 와일드카드 사용 시 주의**: 임의 헤더가 vars로 유입·재방출될 수 있으므로,
  * 민감 헤더·토큰은 **반드시 deny에 추가**(`x-genos-access-token`, `authorization`, `x-genos-headers-*` 등),
  * 내부 vars 이름(`security_level`·`host`·`password`·`database` 등)과 **충돌하는 헤더명은 allowlist에 넣지 않도록** 합니다.

## 운영 시나리오

### 고객사 커스텀 헤더를 도구까지 전달한다

1. 두 configmap의 `WORKFLOW_FORWARD_HEADERS` 끝에 헤더 이름을 각각 추가(예: `...,x-srn-id,x-env-cd`). 헤더 이름이 `x-genos-`·`x-forwarded-`·`proxy-`로 시작하지 않는지 확인.
2. 각 목록의 기존 값은 그대로 둔다. **container-services 쪽의 과금 헤더를 global 쪽으로 옮기거나 두 목록을 같은 값으로 맞추지 않는다.**
3. genportal/gateway/admin, workflow 파드를 롤아웃.
4. 검증: 대상 헤더를 실어 채팅(또는 "워크플로우 테스트")을 실행 → 도구 호출 아웃바운드 헤더에 해당 값이 찍히는지 확인(헤더 에코 도구/로그).

### 특정 민감 헤더만 제외한다

allowlist는 그대로 두고 `WORKFLOW_FORWARD_HEADERS_DENY`에 제외할 헤더명을 추가(예: `x-cert-key`). 롤아웃 후 해당 헤더만 도구 호출에서 빠진다.

### 전파가 안 될 때 점검 순서

1. 커스텀 헤더가 **두 configmap 모두**에 들어갔는가(특히 workflow용 container-services 누락).
2. 헤더 이름이 **서버 예약 접두사**(`x-genos-`·`x-forwarded-`·`proxy-`)로 시작하지 않는가 — 이 경우 allowlist에 넣어도 전파되지 않음.
3. 파드가 **롤아웃**됐는가(설정은 기동 시 로드).
4. 헤더 이름 **오타/대소문자** — 내부적으로 소문자 정규화되므로 철자만 맞으면 됨.
5. deny에 걸려 있지 않은가.
6. 클라이언트가 실제로 그 헤더를 **보내고 있는가**(빈 값이면 전파 안 됨).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

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

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://genos-docs.gitbook.io/default/v1.9.5/admin-management/settings/workflow-forward-headers.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
