조인 코드 없이 데이터를 섞는 법, RML

아키텍처9분

보안관제 자동화 제품을 만들고 있다. 여러 SIEM에서 탐지 이벤트를 받아 위협을 판정하고, 확실한 위협은 사람이 보기 전에 장비에서 먼저 차단(선차단)하는 것이 목표다. 그런데 지금 구조에서는 SIEM을 하나 붙일 때마다 그 SIEM 전용 어댑터를 새로 짜야 한다. 수집 코드, 필드 변환 규칙, 다른 데이터와 엮는 조인 코드가 SIEM마다 따로 생긴다.

문제는 같은 대상을 시스템마다 다르게 부른다는 데서 시작한다. 탐지 테이블은 IP를 src_ip, 위협 정보 API는 value, 자산 목록은 addr라고 부른다. 어댑터 구조에서는 “이 필드와 저 필드를 비교하라”는 코드를 소스 조합마다 짜야 하고, SIEM이 늘수록 그 조합이 늘어난다. 자동 차단처럼 판단을 기계에 맡기는 단계로 갈수록, 이 연결이 어디서 어떻게 이뤄지는지 한눈에 보이지 않는다는 것 자체가 위험이 된다.

그래서 어댑터 대신 온톨로지를 들이기로 했다. 다만 온톨로지를 들인다는 건 여러 일을 포함한다. 개념을 설계하고, 흩어진 데이터를 그 개념에 맞춰 정규화하고, 개념이 바뀔 때 버전을 관리하고, 누가 무엇을 바꿀 수 있는지 정하고, 그 위에서 대응을 자동화하는 일이다. 이 글은 그중 데이터 정규화와 관리, 즉 여러 소스의 데이터를 온톨로지의 개념에 맞춰 들여오는 영역만 다룬다. 그 도구로 살펴본 것이 매핑 언어 RML이다.

이 문제는 결국 “세 시스템이 말하는 IP는 같은 개념”이라는 사실을 어디에 적어 두느냐의 문제다. 그 개념의 목록이 온톨로지이고, 각 시스템의 필드를 그 개념에 연결하는 문서가 RML(RDF Mapping Language) 매핑이다. 결론부터 말하면, 소스를 섞는 일은 조인 엔진이 아니라 같은 틀로 만든 이름표에서 일어난다.

온톨로지 = 개념 지도

온톨로지는 한 분야의 개념과, 그 개념들 사이의 관계를 정의해 둔 것이다. 웹 표준으로는 RDF Schema와 OWL로 쓴다. 보안 데이터라면 이 정도로 시작할 수 있다.

ex:Detection  a owl:Class .
ex:Indicator  a owl:Class .
ex:IPAddress  a owl:Class .

ex:sourceAddress  rdfs:domain ex:Detection ;  rdfs:range ex:IPAddress .
ex:matches        rdfs:domain ex:Indicator ;  rdfs:range ex:IPAddress .

“탐지에는 출발지 IP가 있고, 위협 지표는 IP와 일치할 수 있다”는 뜻이다. 온톨로지는 무엇이 있는지만 말하고, 실제 데이터가 어디서 오는지는 모른다.

RML이 하는 일

여기서 매핑이 등장한다. 데이터는 RDF 문장, 즉 “주어 · 관계 · 대상” 세 칸으로 바뀌고, 대상마다 http://example.com/ip/10.0.0.5 같은 고유 이름표(IRI)가 붙는다. RML 매핑은 소스마다 이 이름표를 찍는 틀(템플릿)과, 어떤 온톨로지 개념·관계에 넣을지를 적는다.

<#Indicator> a rml:TriplesMap ;
  rml:logicalSource [ rml:source "cti.json" ;
                      rml:referenceFormulation rml:JSONPath ;
                      rml:iterator "$.indicators[*]" ] ;
  rml:subjectMap [ rml:template "http://example.com/indicator/{id}" ;
                   rml:class ex:Indicator ] ;                 # 온톨로지의 개념
  rml:predicateObjectMap [ rml:predicate ex:matches ;         # 온톨로지의 관계
                           rml:objectMap [ rml:template "http://example.com/ip/{value}" ] ] .

탐지 CSV와 자산 CSV도 같은 방식으로 카드 한 장씩 쓴다. 세 카드가 IP를 가리킬 때 같은 틀 ip/{…}를 쓰면 이렇게 된다.

위협 정보 JSON  ── ip/{value}  ──┐
탐지 CSV        ── ip/{src_ip} ──┼──▶  <ip/10.0.0.5>  (ex:IPAddress 개체 하나)
자산 CSV        ── ip/{addr}   ──┘

필드 이름은 다르지만 찍힌 이름표가 같으니 결과 그래프에서 한 노드, 온톨로지로 말하면 같은 개체가 된다. 비교 코드는 어디에도 없다. 새 소스는 카드 한 장으로 붙고, 온톨로지와 그래프를 쓰는 쪽 코드는 바뀌지 않는다.

이름표를 맞출 수 없을 때는 조인 조건을 쓴다. 탐지에 자산 번호만 있다면 “탐지의 asset_id와 자산의 id가 같은 줄끼리 이어라”라고 선언한다.

rml:objectMap [ rml:parentTriplesMap <#Asset> ;
                rml:joinCondition [ rml:child "asset_id" ; rml:parent "id" ] ] .

정리하면 역할이 셋으로 나뉜다. 온톨로지는 무엇이 있는지, 매핑은 어느 필드가 어느 개념인지, 엔진은 그 매핑대로 문장을 만드는 일을 맡는다. RML이 맡는 건 이 중 매핑과 엔진, 곧 데이터를 개념에 맞춰 넣는 일까지다. 온톨로지 자체를 설계하고 고쳐 가는 일은 RML의 몫이 아니다.

R2RML에서 RML까지

이 방식의 원조는 관계형 DB용 R2RML이다. 2012년 9월 27일 W3C 권고가 됐다. 2014년 겐트대 연구진이 이를 JSON·CSV·XML로 넓힌 RML을 발표했고, 지금은 W3C KG-Construct 커뮤니티 그룹이 Core, IO, FNML(함수) 같은 모듈로 나눠 다듬는다(RML 포털). RML은 아직 W3C 표준이 아니다. RML-Core 명세는 “Draft Community Group Report” 상태이고, 표준화를 맡을 Working Group 헌장은 2026년 10월 현재 다듬는 단계다.

직접 돌려 보니

로컬 맥북에서 Python 엔진 Morph-KGC 2.10.0으로 세 소스를 돌렸다. 문장 16개가 나왔고, SPARQL 한 번으로 “점수 80 이상인 위협 IP에서 난 탐지와 그 자산 담당자”가 나왔다. 세 소스를 엮은 코드는 매핑 문서 한 장이 전부였다.

그런데 함정이 있었다. JSON 값을 공식 테스트와 같은 {$.id} 표기로 쓰자, 이 엔진은 오류 없이 위협 정보 문장 6개를 빠뜨렸다(16개 → 10개). 숫자 90도 명세 테스트(RMLTC0002a-JSON)가 기대하는 정수 타입이 아니라 문자열로 나왔다. 파이프라인은 성공으로 끝나고, 빠진 데이터는 나중에야 드러나는 종류의 문제다.

그래서 엔진은 속도보다 적합성으로 고른다. 커뮤니티 그룹은 모듈별 공식 테스트(2026년 10월 기준 365개)와 엔진별 통과 결과를 구현 보고서로 공개한다. 고른 뒤에도 결과 건수를 기대값과 대조한다.

남는 숙제는 사람 몫이다

매핑 언어는 “무엇을 같은 대상으로 볼지” 적을 자리만 준다. 사내 IP 10.0.0.5는 회사마다 똑같이 쓰이므로, 틀을 ip/{value}로만 만들면 다른 회사의 장비가 한 개체로 합쳐진다. 선차단까지 자동화한 시스템이라면 엉뚱한 회사의 장비를 막는 사고로 바로 이어진다. ip/{회사}/{value}처럼 구분자를 넣는 판단은 사람이 해야 한다. 온톨로지로 말하면 “개체의 정체성 기준”을 정하는 일이고, 어떤 엔진도 대신해 주지 않는다.

정리

  • SIEM마다 짜던 어댑터를 매핑 카드로 바꾸면, SIEM 추가가 코드 작성이 아니라 선언이 되고 어떤 필드가 어떤 판단에 쓰였는지 문서로 남는다.
  • 온톨로지는 무엇이 있는지, RML 매핑은 어느 필드가 어느 개념인지, 엔진은 그 매핑대로 문장을 만든다.
  • 소스를 섞는 일은 같은 이름표 틀에서 일어나고, 틀이 다르면 조인 조건으로 잇는다.
  • RML은 R2RML(2012년 W3C 권고)을 넓힌 커뮤니티 명세이고, 아직 W3C 표준은 아니다.
  • 엔진은 공식 적합성 결과로 고르고, 오류가 없어도 결과 건수를 확인한다.
  • 결과의 품질은 엔진보다 “무엇을 같은 개체로 볼지” 정하는 틀에서 갈린다.

이 글이 다룬 건 온톨로지의 한 영역, 데이터 정규화와 관리뿐이다. 개념이 바뀔 때 매핑과 데이터를 함께 옮기는 버저닝, 누가 개념과 매핑을 바꿀 수 있는지 정하는 거버넌스, 정규화된 그래프 위에서 판단하고 차단까지 이어 가는 대응 자동화는 다음 글들에서 차례로 다룰 예정이다.

참고