본문으로 건너뛰기

© 2026 Molayo

Zenn헤드라인2026. 06. 09. 00:39

로컬 AI Gateway에 Policy Engine을 구현했습니다

요약

로컬 AI Gateway에서 탐지(Detection)와 제어(Control) 로직을 분리하기 위해 Policy Engine을 구현한 사례를 소개합니다. YAML 설정을 통해 코드 수정 없이 탐지 결과에 따른 액션을 변경하고 모델 허용 리스트를 관리할 수 있습니다.

핵심 포인트

  • 탐지와 제어 로직을 분리하여 유지보수성 향상
  • YAML 설정을 통한 동적인 정책 변경 가능
  • 모델 허용 리스트(Allowlist)를 통한 비용 및 보안 관리
  • 탐지 결과와 제어 판단을 모두 감사 로그에 기록

지난 기사에서는 로컬 AI Gateway에 **감사 로그 (Audit Log)**를 구현했습니다.

이번에는 해당 게이트웨이에

Policy Engine

을 추가로 구현한 내용을 소개합니다.

왜 Policy Engine이 필요한가

AI 요청 처리에서,

"무엇을 탐지했는가"와 "그것을 어떻게 처리할 것인가"는 본래 별개의 책임입니다.

  • 탐지(Detection)는 "무엇이 있는지"를 찾는 것
  • 제어(Control)는 "그것을 어떻게 다룰지"를 결정하는 것

이 두 가지가 혼재되어 있으면,

제어를 변경할 때마다 코드를 수정해야 합니다.

예를 들어:

  • 이메일 주소 처리를 warn에서 block으로 바꾸고 싶을 때
  • 향후 운영 환경과 개발 환경에서 서로 다른 정책(Policy)을 적용하고 싶을 때

이러한 변경을 설정만으로 수행할 수 있도록,

제어 판단을 코드로부터 분리하는 것

이 이번 구현의 목적입니다.

문제는 "탐지와 액션이 분리되어 있지 않다는 것"

이전까지의 구현에서는 Detector가

"무엇을 탐지했는가"와 "어떻게 다룰 것인가 (block/warn/info)"

를 모두 담당하고 있었습니다.

즉, 이메일 주소를 warn에서 block으로 바꾸려면,

Detector의 코드를 수정해야 했습니다.

환경마다 동작을 다르게 할 수도 없었으며,

설정이 아닌 구현을 변경하는 것이 전제되어 있었다

라는 문제가 있습니다.

구현한 내용

탐지 결과(Finding)와 제어 판단(PolicyResult)을 분리하는

Policy Engine

을 구현했습니다.

구현한 내용은 다음 세 가지입니다.

  • 탐지 타입별 액션(Action)을 YAML 파일로 설정
  • 사용 가능한 모델을 허용 리스트(Allowlist)로 관리
  • 감사 로그에 탐지 결과와 제어 판단을 모두 기록

아키텍처

Detector는 "무엇을 탐지했는가"를 반환하고,
Policy Engine이 "어떻게 다룰 것인가"를 결정하며, Gateway가 block/forward를 실행합니다.

정책 설정

정책은 YAML 파일로 관리합니다.

findings:
  openai_api_key: block # API 키는 차단
  email_address: warn # 이메일 주소는 경고
...

설정할 수 있는 내용은 두 가지입니다.

findings 섹션

탐지 타입별로 block / warn / info 중 하나를 지정합니다.

models 섹션

사용을 허용할 모델을 나열합니다. 리스트에 없는 모델은 차단됩니다.

이는 비용 관리뿐만 아니라, 의도하지 않은 모델로의 전송을 방지하려는 목적도 있습니다.

평가 메커니즘

Policy Engine은 요청에 대해 두 가지 종류의 평가를 수행합니다.

모델 평가

요청에서 지정된 모델이 허용 리스트에 포함되어 있는지 확인합니다.

func (e *Engine) EvaluateModel(model string) PolicyResult {
  for _, allowed := range e.config.Models.Allowed {
    if model == allowed {
      ...

허용 리스트가 비어 있는 경우에도 모든 모델을 차단합니다.

탐지 결과 평가

탐지 결과(Finding)의 타입별로 YAML 설정을 참조하여 액션을 결정합니다.

func (e *Engine) EvaluateFindings(findings []detector.Finding) []PolicyResult {
  for _, f := range findings {
    action, ok := e.config.Findings[f.Type]
    ...

최종적으로, 평가 중 하나라도 block이 포함되어 있으면 요청을 거부합니다.

구현 시 의식한 점

탐지와 판단의 책임 분리

Detector는 "무엇을 탐지했는가"만을 반환합니다.

type Finding struct {
  Type string // 탐지 타입 (예: openai_api_key)
  Confidence string // 확신도
  ...
}

액션은 Policy Engine이 결정합니다.

이를 통해 코드를 변경하지 않고 YAML만 변경하여 제어를 바꿀 수 있습니다.

페일 세이프 (Fail-safe)

YAML에 정의되지 않은 탐지 유형 (detection type)이 나타날 경우,

기본적으로 block 처리합니다.

action, ok := e.config.Findings[f.Type]
if !ok {
action = ActionBlock // 설정에 없는 유형은 안전한 방향으로 처리
...

"누락된 설정은 통과시킨다"가 아니라, "누락된 설정은 차단한다"라는 설계입니다.

탐지와 판단을 모두 감사 로그 (Audit Log)에 남기기

감사 로그에는 findings (탐지 결과)와 policy_results (제어 판단)를 모두 기록합니다.

{
"findings": [
{"type": "email_address", "confidence": "medium", "matched": "test***"}
...

나중에 YAML을 변경하더라도,

"탐지 결과는 동일하지만, 판단만 바뀌었다"

라는 점을 추적할 수 있습니다.

SSK 설계 패턴과의 대응

이번 구현은 SSK에서 AI Gateway의 "입력을 제어한다"를 구현한 사례입니다.

제어 판단을 코드가 아닌 설정으로 외부화함으로써,

"어떻게 제어할 것인가"를 바꾸기 쉬운 상태로 만드는 것

이 이번의 주요 목적입니다.

요약

  • 탐지와 제어 판단이 분리되어 있지 않으면, 정책 변경 시마다 코드 수정이 필요함
  • Policy Engine을 도입하여 YAML로 제어 규칙을 관리할 수 있도록 함
  • 모델의 허용 목록 (allowlist)과 탐지 유형별 액션 (action)을 YAML로 설정함
  • 설정에 없는 유형은 페일 세이프 (fail-safe)로서 차단함
  • 감사 로그에 탐지 결과와 제어 판단을 모두 남겨 정책 변경을 추적 가능하게 함

Discussion

AI 자동 생성 콘텐츠

본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0