메인 인덱스 | BoB-Yamong | CCG-Platform | Shield4U

이 문서는 제가 각 프로젝트 팀에서 발생한 선택과 시행착오를 정리해 둔 문서입니다.

resume

김현석 이력서

메인 인덱스 | 채용 요약

기본 정보

구분: 신입
출생: 2001년생 (25세)
메일: [email protected]

짧은 자기소개

보안과 인프라를 함께 다뤄 온 컴퓨터공학 전공 재학생입니다. 취약점 진단, DevOps, Linux/가상화 환경, Python 기반 자동화 경험을 중심으로 실무 역량을 쌓아 왔고, 보안 교육·교내 보안 활동·대회·인턴 경험을 통해 관련 역량을 확장해 왔습니다. 고등학생 때부터 약 10년 동안 홈 서버 목적으로 Proxmox VE 서버 안에서 여러 서비스를 운영하며 네트워크, 클라우드, 컨테이너, CI/CD를 실제로 다뤄 왔습니다.

학력

조선대학교 컴퓨터공학전공

  • 기간: 2020.03 ~ 재학중
  • 구분: 4년제 재학 중
  • 학점: 4.185 / 4.5

경력

한전케이디엔㈜ 정보보호실 · 인턴/수습 · 정보보안

  • 기간: 2026.01 ~ 2026.02
  • 근무 기간: 총 2개월
  • 업무
    • 사내 서비스 점검 지원
    • 물리 보안 업무 지원

기술 스택

  • 인프라/가상화: Proxmox VE, VMware, Ubuntu, CentOS, SDN
  • 보안: 취약점진단, 모의해킹, DLP
  • 개발/운영: Python, DevOps

경험 · 활동 · 교육

SkillsToWork 강사

  • 기간: 2025.07
  • 구분: 사회활동
  • 내용
    • 데이터센터 관련 기술 교육 진행
    • 서울디지텍고등학교 대상 2025.07.10 ~ 2025.07.16 (35시간)
    • 선린인터넷고등학교 대상 2025.07.22 ~ 2025.07.28 (35시간)

차세대 보안리더 양성 프로그램(Best of the Best)

  • 기간: 2024.07 ~ 2025.03
  • 구분: 교육 이수 내역
  • 내용
    • WhiteHat 10 선정
    • eBPF를 통한 컨테이너 보안 솔루션 제작 프로젝트
      • 우수 프로젝트 선정
    • 보안제품개발 트랙 교육 이수
    • 취약점 점검, 포렌식, 보안컨설팅 공통교육 이수
    • TOP 30 교육 이수

해커스페이스 / 국가사이버안보센터

  • 기간: 2023.03 ~ 2026.03
  • 구분: 사회활동
  • 내용
    • 모의해킹 활동
    • 전력 계열 공기업(2025.11 ~ 2025.12) 및 지역 산하 기관(2023.04) 대상 활동 참여
    • MITRE ATT&CK 기반 취약점 체인 정리 및 보고서 작성

조선대학교 교내 침해사고대응팀

  • 기간: 2023.03 ~ 2024.06
  • 구분: 교내활동
  • 내용
    • 교내 사이트 취약점 점검
    • OWASP TOP 10 및 교육부/국가정보원 취약점 가이드를 통한 수동 점검 수행
    • 취약점 제보 29건
    • 취약점 조치 이행 점검

Hackerlogin / 조선대학교

  • 기간: 2020.03 ~ 2026.03
  • 구분: 동아리
  • 내용
    • 운영진 (2023.01 ~ 2023.12)
    • 부회장 (2024.01 ~ 2024.12)
    • 동아리 신입생 선발 시험 전 교육 (2024.03 ~ 2024.06)
    • SDN 및 VPN 프로토콜/서비스 분석 (WireGuard, Tailscale, Cloudflare Tunnel) (2023.07 ~ 2023.08)
    • 웹 공방전 참여 (2023.01 ~ 2023.02)
    • 웹 공방전 운영 및 피드백, 취약점 조치 이행 점검 (2023.07 ~ 2023.08)

수상

  • 2026.03 2026년 AI 원클릭 해킹대회(우수상) · 한국인터넷진흥원
  • 2025.12 2025년 TS 보안 허점을 찾아라!(장려상) · 한국교통안전공사
  • 2025.10 조선대학교 대학생 프로그래밍 경시대회(2025 ICPC)(금상) · 조선대학교
  • 2025.08 AI + 보안 연합 세미나(장려상) · 광주과학기술원 AI대학원
  • 2025.06 2025 제3회 전라남도 웹 취약점 경진대회(장려상) · 한국융합보안학회
  • 2025.03 Best of the Best 우수 수료(White Hat 10) · 한국정보기술연구원
  • 2024.12 2024 한국소프트웨어종합학술대회(우수논문상) · 한국정보과학회
  • 2024.11 2024 호남지역 정보보호 해커톤(호남정보보호지원센터장상) · 호남정보보호지원센터
  • 2023.12 2023년 TS 보안 허점을 찾아라!(장려상) · 한국교통안전공단
  • 2023.09 HCCC2023(호남 대학간 침해대응/분석 대회 2023)(장려상) · 한국농수산식품유통공사
원본 링크

BoB-Yamong

조직 메모 | 요약

TL;DR

이 프로젝트는 Best Of The Best 13기에서 진행한 팀 프로젝트로, eBPF를 이용해 컨테이너를 시스템콜 레벨에서 모니터링하고 제어하는 보안 솔루션을 제작하였습니다. 저는 Docker 기반 POC에서 Kubernetes 운영 구조까지 이어지는 흐름 속에서, 팀 전반의 개발 환경 설정과 테스트 환경 조성, API 규약 설정, CI/CD 파이프라인 구축, 링 버퍼 및 Kafka 데이터 전송 최적화, 컨테이너 식별 방법론 개발, Grafana를 통한 대시보드 시각화를 주도적으로 진행하였으며, 그 외에도 프로젝트 전반에 참여하였습니다. 6명이 4개월을 9명이서 3개월을 추가로 진행하며 프로젝트가 고도화 되고 서비스화 되어가는 과정을 설명할 수 있습니다. 최종적으로 goorm사 내부의 개발환경에서 성공적으로 정책이 적용되어 행위를 탐지, 차단할 수 있음을 확인하였으며 자체 테스트베드에서 구상한 시나리오(측면이동, 내부망 스캐닝, 크립토 마이닝)에 대해 1회성, Rate Limit, SVM 기반으로 어떤 컨테이너에서 행위가 이루어지는지 파악하고 차단할 수 있는지 테스트 완료하였습니다. 이러한 세밀한 모니터링 상황에서 CPU가 90% 이상인 과부하 상황에서 조차 서비스 전반의 응답시간이 5% 미만으로 감소하며 시스템콜 하나 놓치지 않고 모두 로그에 남길 수 있다는 조사결과를 논문으로 작성하여 정보과학회 우수논문 수상 및 KCI 등재하였습니다.(링크) 현재는 프로젝트를 가지고 PM을 필두로 창업하여 계속 발전시켜 나가고 있다고 합니다.(링크)

원본 링크

맡은 범위

CI/CD와 이미지 배포

Jenkins에서 GitHub Actions로 옮긴 이유

처음에는 당시 기준 CI/CD의 가장 대표적이었던 Jenkins를 도입했습니다. 이후 팀원들은 GitHub와 더 자연스럽게 붙는 GitHub Actions를 원했습니다. 당시 제가 확인했던 hosted GitHub Actions 환경만으로는 eBPF 최신 기능을 모두 사용할 수 있는 리눅스 커널버전 6.8.0 이상의 환경을 만족시킬 수 없었기 때문에, 기존 Jenkins처럼 운영체제까지의 세팅은 직접 하면서 GitHub와 융화되는 self-hosted GitHub Actions runner를 두고 검증 흐름을 다시 잡았습니다.

이후에는 Runner 자체를 Kubernetes 안에서 확장하는 쪽으로 나아갔습니다. ARC(actions-runner-controller, Runner로 사용할 수 있는 도커 이미지가 한정되어 있었고 해당 이미지에서 eBPF 빌드 실패)를 참고하여, Repository별로 기본 Runner를 하나 GitHub에 등록 해두고 작업이 들어오면 Kubernetes 안에서 Runner를 늘리고 GitHub에 자동으로 등록되도록 하였습니다.

eBPF를 제외한 모든 모듈은 Ephemeral Runner로 설정하여 사용하였습니다. Clone 하고 빌드하는데 대부분 3분 미만이기에 작업에 큰 어려움이 없었습니다. 하지만 eBPF 모듈은 처음부터 빌드 시 10분~20분 정도 걸리기 때문에 빌드 성공 여부를 판단하는데 너무 오랜 시간이 필요했습니다. eBPF 개발 환경에서 한번 빌드를 성공한 경우에만 Push 할 수 있도록 팀 내 규칙을 정하고 일반 Runner로 이전 빌드 잔여 파일을 가지고 수정된 부분만 빌드 하도록 설정하였습니다. dev, main 브랜치에 PR이 올라갈 때 와 명시적으로 지정할 때만 Ephemeral Runner로 구동되게 하여 전체 빌드가 완벽히 에러가 없는지 확인하였습니다. 이를 통하여 일반 Commit에 대해서도 환경에 따른 에러가 없는지 빠르게 확인하고 전체 빌드 과정에서 기존 빌드 과정에 의해서 통과되던 매우 지엽적인 버그들(eBPF 모듈 로드하는 부분이 코드에서 제거되었는데 기존 빌드되었던 모듈 잔여파일 때문에 정상 빌드되는 버그 등)까지 다시 확인하였습니다.

Docker registry를 직접 운영한 이유

빌드한 이미지는 self-hosted Docker Registry로 푸시했습니다. 당시에는 테스트 환경에 이미지를 반복 배포하는 흐름에 제가 직접 운영 가능한 Registry가 더 맞다고 판단했습니다. Harbor도 후보였지만, 그 시점에는 Docker Registry 운영 경험이 제게 더 익숙했습니다.

처음에는 단순 Registry만 두고 시작했고, 운영하다 보니 UI, 외부 접근, 인증 같은 요소를 뒤에서 계속 덧붙였습니다. 지금 돌아보면 Harbor로 옮기는 편이 운영 측면에서는 더 나았을 수도 있다고 판단합니다. docker-back.md kube-back.md release-downloader.md

youmuu-deploy에서 배포 구성을 나눈 이유

youmuu-deploy.md에서 제가 중요하게 본 것은, 우리 시스템을 컨테이너로 올리면 우리 시스템이 우리 자신도 직접 모니터링할 수 있다는 점이었습니다. 호스트 바이너리나 systemd 서비스로도 올릴 수는 있었겠지만, 배포 편의와 자기 자신을 관찰하는 구조까지 같이 가져가려면 Docker Compose 쪽이 더 적합하다고 판단하였습니다.

agent는 실제 모니터링/제어 대상 컨테이너 시스템과 같이 떠 있으면 되는 부분이었고, manageragent가 보낸 데이터를 받아서 알람과 분석을 수행하고, LSM 룰셋을 배포해 컨테이너 단위 제어를 가능하게 하는 시스템이었습니다. 별도로 둔 compact 구성은 goorm 쪽 내부 테스트베드에서 LSM 정책과 알람 흐름만 최소 단위로 검증해 보기 위한 구성이었습니다.

agent가 배포될 때 컨테이너 시스템에서 강한 권한을 요구하는 점은 분명히 인지하고 있었습니다. 하지만 eBPF로 시스템을 모니터링하고 제어하는 것이 시스템의 근본 수준 권한이 필요한 일입니다. 즉, 호스트에 직접 배포하든 컨테이너를 통해서 배포하든 운영 위험성은 크게 달라지지 않는다고 판단하였고, 그렇다면 배포 및 관리가 편한 컨테이너 부분에서 배포하는 것이 더 낫다고 의견을 모았습니다.

지금 다시 보면 가장 바꾸고 싶은 부분은 이미지 배포 인증 방식입니다. ID와 비밀번호를 CLI에 직접 넣는 구조는 위험하다고 느꼈고, 이 부분은 더 안전한 방식으로 바꾸는 것이 맞다고 판단하였습니다.

엔진 구조와 로그 취합

모듈을 잘게 나눴다가 다시 합친 이유

초기에는 rawTracePoint, TracePoint, LSM, ring buffer parser, user space 전송 부까지 너무 잘게 나뉘어 있었습니다. 짧은 기간 안에 병렬로 개발하려다 보니 서로 범위를 침범하지 않는 쪽으로 쪼개졌고, 그 결과 버전 관리가 가장 어려운 문제가 됐습니다. xx.xx.xx 형식으로 {서비스단계}.{호환버전}.{각모듈별버전} 이렇게 관리를 했는데 각 모듈 단위로 분리는 되어있지만 너무 강하게 결합해 있어서 호환 버전의 숫자만 너무 빠르게 올라가는 문제점이 발생하였습니다.

시간이 지나면서 syscall Monitoring과 Control이라는 핵심 목표는 이미 달성됐고, 이후의 큰 수정은 대부분 Ring Buffer로 데이터를 넘기는 부분, 그 데이터를 Kafka로 전송하는 부분에 몰리게 됐습니다. 그 시점에는 모듈별로 독립적인 수명 주기를 유지할 만큼 병렬 작업이 있지 않았고, 각 모듈이 따로 살아 있어야 할 이유도 약해졌습니다. 그래서 나중에는 엔진 모듈을 다시 합치는 쪽이 더 맞았습니다. youmuu.md youmuu-db.md

youmuu에서 C++를 쓴 이유와 이후 Go로 옮긴 이유

youmuu.md는 Docker 기반 POC 성격이 강한 Repository였습니다. 당시 저는 Python, Go, C++, Rust로 eBPF 관련 구현을 모두 테스트하였고, 성능 측면에서는 C++ 와 Rust가 더 우세하다고 판단하였습니다. 하지만 팀원들이 Rust에는 익숙하지 않았고, C++에는 더 익숙했습니다. 당시 리눅스 문서와 eBPF 관련 자료도 결국 C 계열 기준 설명이 중심이었기 때문에, POC를 실제로 밀고 가기에는 C++가 더 현실적이었습니다.

이후 gomumu.md처럼 Kubernetes와 붙는 구조로 넘어오면서 생각이 달라졌습니다. 커널 쪽 코드는 결국 C로 돌아가고, user-space에서는 Kafka로 데이터를 보내는 쪽의 메모리 관리, 네트워크 최적화, 운영 편의가 더 중요하다고 판단하였습니다. eBPF에 대한 이해가 높아진 뒤에는 Kernel은 어차피 C로 빌드되어 작동하고 user-space는 Go로 옮겨도 성능상 큰 손해가 크지 않다고 판단하였고, Docker와 Kubernetes 환경과의 결합은 Go가 더 편했습니다.

컨테이너를 식별하는 기준

팀에서 중요하게 본 것은 컨테이너 식별자로 특정 런타임의 API보다, 컨테이너라면 고유하게 생길 수밖에 없는 cgroup과 namespace를 사용해야 한다는 것입니다. Docker socket은 컨테이너 메타데이터를 얻어 표적을 식별하는 것에만 사용하였습니다. 즉 yaml 로 작성된 rule에 cgroup이나 namespace로 작동하게 하기 힘들 수 있으니 컨테이너 관련 정보(이미지 등)를 토대로 룰을 작성하면 에이전트 쪽에서 cgroup, namespace로 치환하여 엔진이 이해할 수 있는 형식으로 다시 작성해 적용합니다.

이 철학은 youmuu.mdgomumu.md를 같이 볼 때 더 분명합니다. 하나는 Docker 기반 POC이고, 다른 하나는 Kubernetes 쪽으로 넘어간 Repository지만, 컨테이너를 식별하려는 기준 자체는 가능한 한 런타임에 덜 묶이게 가져가려 했습니다.

로그 전달 경로가 Kafka 중심으로 이동한 이유

초기에는 Postgres Message Queue를 통해 기존 기술 스펙 위에 로그 전달 경로 넣어서 사용했지만, 노드와 컨테이너의 수가 늘어나면서 DB 쪽 부하가 과해지고 네트워크 트래픽도 급증하며 대체제가 필요해졌습니다. 그래서 대안으로 Kafka를 이용하기로 하였습니다. 여러 로그를 각각의 토픽으로 작성해 관리할 수 있고, 향후 분석 및 시각화와 연결할 때도 더 적합하다고 판단하였습니다. 또 압축 전송 기술을 통하여 네트워크 트래픽도 크게 절약할 수 있을 것으로 판단하였습니다. Kafka로 전환 후 topic 단위 관리, 클러스터로 부하 분산, gzip 압축으로 네트워크 트래픽 70% 절감 등의 도입 성능을 낼 수 있었습니다.

LDAP 실험과 제가 지금 보는 현실성

ldap-tutorial.md은 아이디어는 LDAP의 사용자를 eBPF 정책에까지 연결할 수 있는지 보는 실험하기 위해 만든 Repository입니다.

저희 팀이 당시에 부딪힌 문제는, 웹 서버에서 발생하는 시스템 콜이 결국 로그인한 최종 사용자가 아니라 웹 서버 프로세스 권한으로 실행된다는 점이었습니다. 그래서 웹에서 로그인한 사용자를 LDAP 사용자와 매칭시키고 그 사용자별 UID를 통하여 모니터링하고 식별하면 어떨까? 하는 아이디어였습니다. 당시에는 복잡한 테스트라서 넘어갈 수밖에 없었지만, 여전히 이 아이디어가 완전히 불가능하다고까지 보지는 않습니다. 일반적인 웹 서버 구조에서는 그대로 적용하기 어려울 수 있지만 웹 서버를 만드는 과정부터 고려한다면 가능할 것으로 생각합니다.

CCG-Platform

조직 메모 | 요약

TL;DR

이 프로젝트는 사용자가 웹에서 요청하면 게임별 프로파일에 맞는 컨테이너와 Pod를 동적으로 생성하고, Selkies 기반 스트리밍으로 바로 접속할 수 있게 만드는 클라우드 게임 플랫폼입니다. 저는 4명 팀의 팀장으로서 POC, demo, TerraformLearn, PodManager_V2로 이어지는 흐름 안에서 게임 실행 환경, GPU warm pool, Pod 관리 API, 배포 구조를 구상하고 발전시키며 프로젝트를 계속 이어가고 있습니다.

원본 링크

맡은 범위

Selkiesgame-container를 선택한 이유

이 프로젝트의 목적은 리눅스 위에서도 실제 게임이 돌아갈 정도로 레이턴시가 낮은 온라인 VDI를 만드는 것이었습니다. 국내에서 비교할 수 있는 대안으로는 GeForce Now, Xbox Cloud Gaming, 그리고 라이선스 문제 가능성이 있는 피시방 공유 계열 솔루션들이 떠오를 수 있었지만, 각각 비용, 입력 방식, 운영 리스크 때문에 실제로 게임을 하기에는 여러 문제가 있었습니다. 저는 이 프로젝트를 단순 스트리밍 서비스가 아니라, 사용자에게 게임별 최적화된 스펙의 리눅스 기반 게임 실행 환경을 제공하는 플랫폼으로 경제성 있게 사용할 수 있는 것을 목적으로 삼았습니다.

제가 Selkies 계열을 고른 이유는 “컨테이너 격리 + GPU Slice + 게임별 프로파일 기반 호스팅”이라는 목표에 가장 가까웠기 때문입니다. 당시 검토한 후보를 간단히 정리하면 아래와 같았습니다.

후보제가 본 장점제가 덜 적합하다고 본 이유
Selkies웹 기반 접근이 가능하고, 컨테이너 내부에서 게임 실행 환경을 구성하는 방향과 잘 맞았습니다.위 목표에 가장 가까워 채택하였습니다.
KasmVNC웹 기반 접근이 가능했습니다.레이턴시가 높아 게임 실행 환경에는 덜 적합하다고 판단하였습니다.
Guacamole웹 클라이언트를 바로 제공할 수 있었습니다.게임 용도로 보기에는 레이턴시 한계가 있었습니다.
Moonlight 계열스트리밍 자체는 강점이 있었습니다.웹 클라이언트가 없었고, 컨테이너 내부 실행 및 단일 호스트 병렬 운영 구조와는 거리가 있었습니다.

처음부터 원격 실행 스택을 직접 모두 조립해야 할 이유는 크지 않았습니다. 오히려 컨테이너 안에 게임 실행에 필요한 것들을 하나씩 추가하다 보니, 결국은 selkies-egl-desktop 위에 Steam을 더하는 형태로 수렴하였습니다.

이 판단은 game-container.md의 Dockerfile과도 맞닿아 있습니다. 이 Repository는 ghcr.io/selkies-project/nvidia-egl-desktop:latest를 베이스로 삼고, 그 위에 Steam과 entrypoint를 얹는 방식으로 구성돼 있습니다. 즉 핵심은 “스트리밍 플랫폼을 만드는 것”보다 “게임 실행 환경을 얹은 컨테이너를 안정적으로 제공하는 것”에 더 가깝습니다.

왜 POC와 demo 단계를 따로 두었는가

POC.mddemo.md는 같은 방향을 보지만 역할이 다릅니다. POC는 Docker 기반에서 “컨테이너를 동적으로 만들고, 그 안에서 게임이 실제로 돌아가며, 외부에서 coturn을 통해 접근할 수 있는가”를 먼저 확인하는 단계였습니다.

그다음 단계가 demo였습니다. demo로 넘어오면서는 로컬 Kubernetes 기반에서 요청이 들어올 때마다 컨테이너를 동적으로 생성하는 흐름과, GPU MPS 슬라이싱까지 같이 시험했습니다. 그래서 demo.md는 단순 소개용 Repository가 아니라, EKS 상에서 만들고자 한 MVP를 로컬에서 계속 구현하고 검증하던 흔적으로 보는 편이 맞습니다.

TerraformLearn이 실제 IaC 중심이 된 이유 + GPU 노드에 대한 고민

TerraformLearn.md은 원래 연습용으로 시작한 Repository였지만, 계속 진행하다 보니 현재 IaC의 메인 Repository가 됐습니다. 서비스 Repository 안에 Terraform을 섞는 대신 분리해 둔 이유는, 인프라를 독립적으로 만지고 실험하기 더 편했기 때문입니다. 합치는 편이 낫는지 고민은 했지만, 현재는 분리해 두는 쪽을 유지하고 있습니다.

제가 이 Repository에서 오래 고민하였던 것은 GPU Warm Pool입니다. 이 프로젝트의 핵심은 사용자가 웹에서 컨테이너 배포를 눌렀을 때 거의 바로 떠야 한다는 점이었습니다. 그러려면 노드가 이미 하나 이상 살아 있어야 했습니다. 단순 Auto Scaling만으로는 목표 속도(1분 이내에 컨테이너 원격 접속 성공)를 맞추기 어려웠습니다.

추가로 이 프로젝트는 Karpenter 위에서 MPS나 vGPU처럼 GPU를 잘라 쓰는 방식을 고려했습니다. 그런데 Karpenter가 보는 단위와 제가 소비하려는 단위가 완전히 같지 않았습니다. 제가 MPS나 vGPU 기준으로 자원을 소모하면 GPU 기준 Node Claim이 원하는 시점에 안 생기는 문제가 있었고, 반대로 컨테이너가 GPU 전체를 요청하게 두면 GPU 슬라이싱 자체가 의미를 잃을 수 있었습니다. 그래서 Warm Pool이 필요했습니다.

PodManager_V2로 넘어가며 바뀐 점

PodManager_V2.md는 직접 관리자가 Pod를 생성하는 도구라기보다, 백엔드가 명령을 내리면 실제 클러스터에서 컨테이너를 생성하는 내부 API로 정리되는 단계였습니다. AWS 인증 정보와 클러스터 권한은 PodManager 쪽이 가지고, 생성 트리거와 사용자 흐름은 상위 백엔드가 맡는 구조로 가는 편이 더 맞다고 봤습니다.

그래서 이 시점에는 외부 웹 UI를 계속 키우기보다, 클러스터 내부에서만 쓰는 Pod Manager API 쪽으로 수렴했습니다. manageruser-app 이미지를 나눈 것도 같은 이유입니다. 하나는 control plane 역할이고, 다른 하나는 실제 사용자 워크스페이스를 담는 실행 표면이라서 분리하는 것이 자연스러웠습니다.

현재 구조가 Jinja 템플릿 기반인 이유도 여기와 연결됩니다. 게임 프로파일별로 서로 다른 스펙의 컨테이너를 만들어야 했기 때문에, Pod / Service / IngressRoute / NetworkPolicy를 조립형으로 생성할 필요가 있었습니다. 지금 단계에서는 그 요구를 빠르게 반영하는 쪽에 가까웠고, 장기적으로는 더 정석적인 방식이 무엇인지 계속 고민할 필요가 있다고 보고 있습니다.

Shield4U

조직 메모 | 요약

이 섹션은 Shield4U에서 제가 맡았던 구조와 서비스 연결 아이디어를 정리한 문서입니다. 이 프로젝트는 20시간 정도 진행된 해커톤이었기 때문에, 구현 완성도보다 “이 구조가 실제로 다음 단계까지 이어질 수 있는가”를 더 중요하게 보았습니다.

TL;DR

이 프로젝트는 웹 취약점 평가를 한 번의 선형 스캔으로 끝내지 않고, controller가 각 모듈의 결과물을 받아 다음 목적지로 다시 라우팅하는 구조를 목표로 한 해커톤 프로젝트입니다. 저는 팀장으로서 전체 서비스 구조, 통신 규약, 크롤링과 오케스트레이션 연결부를 맡았고, crawler, llm, scanner를 반복적으로 엮을 수 있는 구조를 오케스트레이션을 중심으로 구상하였고, 모듈을 자유롭게 추가하여 얼마든지 확장해나갈 수 있는 구조로 완성하였습니다. 20시간 정도의 짧은 해커톤 시간동안 확장 가능성을 보여주기 위하여 노력하였습니다. 현재 구성은 데모에서 웹 취약점 점검을 자동화 하는것을 보여주기 위한 모듈 설계입니다.

원본 링크

맡은 범위

왜 선형 파이프라인 대신 controller 중심 라우팅을 택했는가

처음부터 controller -> crawler -> llm -> scanner -> report처럼 한 방향으로만 지나가는 구조를 만들고 싶지는 않았습니다. 제가 원했던 것은, 한 단계가 끝났을 때 결과가 0개 이상 나올 수 있고, 그 결과물마다 다음에 어디로 가야 할지가 달라질 수 있는 구조였습니다. 어떤 결과는 바로 LLM 분석으로 넘길 수 있지만, 어떤 경우에는 다시 크롤링을 더 깊게 해야 할 수도 있고, 어떤 결과는 스캐너로 바로 보내는 편이 나을 수도 있기 때문입니다.

그래서 Shield4U의 핵심은 “고정된 단계표”보다 “결과물 기반 라우팅”에 가깝습니다. controller는 단순히 첫 API 요청을 받는 서비스가 아니라, 각 모듈이 만든 결과를 다음 단계가 받기 좋은 형식으로 가공해 다시 넘겨주는 중심점이었습니다. 저는 이런 구조여야 같은 도구를 같은 입력에 반복해서 무의미하게 돌리는 일을 줄일 수 있고, 새 모듈이 생겨도 입력과 출력 형식만 맞추면 전체 흐름에 다시 연결할 수 있다고 판단하였습니다.

이 구조 덕분에 Crawler에서 나온 데이터를 토대로 다시 Crawler를 호출하는 흐름도 가능하게 되었습니다. 웹 스캐닝은 주 페이지 하나 보고 끝나는 문제가 아니라고 보았습니다. 실제로는 여러 페이지를 따라가며 더 깊이 들어가야 하고, 어떤 결과는 다시 크롤러 쪽으로 되돌아가 더 많은 입력을 확보해야 다음 스캔이 의미 있게 될 수 있기 때문입니다.

왜 LLM을 보고서 생성기 이상으로 두었는가

Shield4U에서 LLM은 단순 보고서 생성기만은 아니었습니다. 지금 구조에서는 보고서 생성뿐 아니라, Nuclei 룰 생성기 역할과 다음 모듈에 맞게 데이터를 가공하는 역할도 맡고 있습니다.

페이로드 직접 생성 대신 Nuclei 템플릿을 생성하도록 한 이유는, LLM이 실행용 payload를 직접 안정적으로 만들기에는 제약이 있었고, 구조화된 Nuclei 룰 형태가 의도를 더 읽기 쉬우며 이후 스캐너가 받아 처리하기에도 더 적합했기 때문입니다. 즉 LLM을 “설명만 하는 모듈”이 아니라, 다음 단계에서 실제 도구가 사용할 수 있는 결과를 만드는 모듈로 두고자 하였습니다. 이 지점은 llm.mdscanner.md를 같이 보면 더 설명하기 좋습니다.

해커톤에서 끝까지 유지하고 싶었던 구조

이 프로젝트에서 제가 끝까지 유지하고 싶었던 기준은 세 가지였습니다.

  • 모듈 분리
  • 모듈 추가 용이성
  • controller 중심 라우팅

실제로 사용하기 위한 도구를 만들고 싶었기 때문에, 한 번 돌고 끝나는 데모보다 결과에 따라 다음 단계가 계속 달라질 수 있는 구조가 더 중요했습니다. 해커톤이라서 구현을 충분히 다듬을 시간은 부족했지만, 적어도 이후에 기능을 더 붙이고 흐름을 확장할 수 있는 뼈대는 남기고 싶었습니다.

지금 다시 보면 이 구조는 중앙에서 다음 행동을 정하고 여러 모듈을 붙여 쓰는 오케스트레이션 방식에 가깝습니다. 당시 모델과 도구 환경에서는 지금처럼 정확도 높은 tool calling을 기대하기 어려웠기 때문에, 더 명시적인 controller 중심 구조를 먼저 깔아 두는 편이 현실적이라고 판단했습니다. 그래서 이 프로젝트에서 제가 끝까지 지키고 싶었던 것은 구현 완성도보다도, 다음 단계로 이어질 수 있는 구조였습니다.