Velociraptor 구축 과정 및 서버와 클라이언트의 신뢰 관계Velociraptor 구축 과정 및 서버와 클라이언트의 신뢰 관계

Velociraptor 구축 과정 및 서버와 클라이언트의 신뢰 관계

생성 일시
Sep 30, 2026 02:22 PM
최종 편집 일시
Last updated October 4, 2026
태그
CERT
Velociraptor
작성자
@김태형
Date

🧑🏻‍🔧 구축과정

팀 근두운 인프라 구축 중, CERT 인프라 구성 과정에서 Velociraptor 서버를 EC2에 올리고, 다른 수집 대상의 다른 EC2에 Agent를 배포하는 방식으로 운영을 하려고 계획을 하였다.
먼저 Velociraptor 공식 매뉴얼(Quickstart Guide)을 확인하였는데, 설치 방법은 매우 단순했다. 서버의 플랫폼과 아키텍처를 선택한 뒤, 이에 맞는 Velociraptor 바이너리를 다운로드하고, 바이너리의 config generate -i 명령으로 서버 구성 파일인 server.config.yaml을 생성한다.
그리고, 생성된 서버 구성 파일(.yaml)을 패키지 포맷에 맞게 server --config 명령으로 서버 설치 패키지로 생성해 주고, 이 패키지를 설치만 해주면 자동으로 Velociraptor 서버가 구축이 되는 거였다.
# Debian 기반 Linux 서버 velociraptor debian server --config server.config.yaml # RPM 기반 Linux 서버 velociraptor rpm server --config server.config.yaml
이후 Agent 배포는 Client 측에도 동일하게 Velociraptor 바이너리를 다운로드하고, 이번에는 client.config.yaml(클라이언트 구성 파일)을 준비해주면 된다.
여기서 client.config.yaml 파일은 서버 설정 파일을 통해 클라이언트 구성 파일을 추출하면 된다.
# 서버 설정 파일을 통해 클라이언트 설정 파일을 추출 velociraptor --config server.config.yaml config client > client.config.yaml
⚠️ 서버 설정파일(server.config.yaml)에는 CA 개인키와 서버 개인키 등 중요한 비밀정보가 포함되므로, 클라이언트에 유출되지 않도록 주의해야 한다.
Velociraptor 바이너리와 client.config.yaml 파일 준비가 끝났으면, 패키징 또는 서비스 등록 단계를 거쳐 Agent 설치를 마무리하자.
여기서는 Agent를 설치할 클라이언트의 OS에 따라 방식이 달라지는데, 근두운에서는 클라이언트도 리눅스를 사용하고 있기 때문에 리눅스를 기준으로 설명한다.
리눅스에서는 Server 구축과 같은 방법으로 클라이언트 구성 파일(.yaml)을 패키지 포맷에 맞게 client --config 명령으로 설치 패키지를 생성하고, 이 패키지를 설치하면 Velociraptor Agent 설치가 끝난다.
# Debian 기반 Linux # 패키지 생성 velociraptor debian client --config client.config.yaml # 패키지 설치 dpkg -i <deb 패키지 파일명> # RPM 기반 Linux # 패키지 생성 velociraptor rpm client --config client.config.yaml # 패키지 설치 rpm -Uvh <rpm 패키지 파일명>
패키지 설치 후에 서비스 상태를 확인 해보고,
systemctl status velociraptor_client
서비스 데몬이 정상적으로 active(running) 상태라면, Velociraptor GUI에서 Client가 등록된 것을 확인할 수 있을 것이다.
notion imagenotion image

🫪 문제 발생

팀 근두운 인프라에 적용하기 전, 내 AWS 계정에서 Velociraptor EC2와 Agent를 설치할 Client EC2를 생성해서 직접 연결해보고, 특이사항이 없다고 판단해 팀 근두운 인프라에 동일하게 구축을 하려고 했었다. 근두운에서는 Terraform으로 인프라를 구축하고 있기에, Velociraptor 서버용 EC2를 생성하면서 user_data 인자를 통해 Velociraptor 바이너리 설치, server.config.yaml 생성 및 패키지 설치, Agent 설치용 client.config.yaml 파일 추출까지 쉘 스크립트로 자동화할 수 있게끔 설계하였다.
특별히 문제가 없을 것이라고 생각하고, 팀 레포에 PR을 올렸다. 해당 PR에 대해 PM님께서 PR에 코멘트를 달아 주셨는데, 여기서 첫 번째 실수?가 나온다.
notion imagenotion image
지금 구성은 Velociraptor 서버 인스턴스의 사설 IP 주소를 server_urls로 하드코딩하여 server.config.yaml 파일을 구성하게끔 설계되어 있다. 코멘트를 보고, 아차 싶었던 게 나는 서버를 설치하고 Agent를 배포하면 연결이 됐네? 하고 그 다음을 생각하지는 못했었다.
실제로 지금 구성은 Velociraptor 서버 인스턴스 교체 발생 시, 사설 IP 주소가 새로 설정되기 때문에 기존에 연결되어 있던 Agent의 연결을 보장하지 못한다.
이를 수용하고자 제시해주신 해결방안대로 AWS의 Route 53 프라이빗 호스팅 존을 사용하기로 했다. Route 53 프라이빗 호스팅 존은 사용자가 지정한 VPC 내부에서만 유효한 프라이빗 도메인 이름을 생성하여 관리하는 가상 DNS 서비스이다.
즉, internal.kintoun.work라는 VPC 내부에서만 사용할 도메인 이름을 만들어서 VPC 내부 자원이 해당 도메인 이름을 통해서 사설 IP의 주소를 획득해 통신할 수 있게 되는 것이다.
나는 해당 프라이빗 호스팅 존을 활용해 velo.internal.kintoun.work 도메인 이름을 Velociraptor 서버 사설 IP를 가리키는 A 레코드 형태로 만들었다.
이후 생성한 도메인 이름을 server_urls에 하드코딩해서 server.config.yaml 파일을 구성하도록 하여 서버 인스턴스 교체 시에도 Agent가 도메인 이름으로 조회하여 서버와 통신을 유지하도록 해결한 것이다.
이제는 정말 문제가 없을 것이라고 생각하고 수정 커밋을 올렸다. 여기서 두 번째 실수?가 나온다. 정확히 말하면, 실수보다는 놓친 부분이라고 할 수 있다.
notion imagenotion image
코멘트에 적힌 대로, 서버 인스턴스가 교체가 되면, server_urls에 하드코딩되어 있던 사설 IP 주소만 바뀌는 것이 아니라 이러한 값을 담고 있는 server.config.yaml 파일 자체가 config generate를 통해 새롭게 구성된다는 것을 놓치고 있었다.
즉, 사설 IP뿐만 아니라 CA 인증 키값, 서버 인증서 등도 새롭게 만들어지는 것이다. 따라서 인스턴스 교체 시 Agent는 여전히 Server와의 연결성을 확보하지 못한다.
해당 문제를 해결하기 위해 Velociraptor에서 CA의 메커니즘, Server와 Agent의 신뢰관계에 대해 공부가 필요함을 느꼈다.

🕵️‍♂️ Velociraptor에서 Agent가 Server를 어떻게 신뢰하나?

먼저 우리는 CA에 대해 정확히 짚고 넘어갈 필요가 있다. CA는(Certificate Authority) 웹사이트, 기업, 개인 등의 디지털 신원을 확인하고 디지털 인증서를 발급하는 신뢰할 수 있는 제3자 기관을 의미한다.
예를 들어, A(Client)와 B(Provider)가 CA를 신뢰한다고 해보자. 그럼 A는 자신의 공개 키와 신원 정보를 담아 CA에게 인증서 발급을 요청하고, CA는 A의 신원을 확인한 후, CA의 개인 키로 전자 서명을 해 A의 인증서를 만들어 준다. 그리고, B도 동일한 과정을 통해 CA의 공개 키를 가지고 있다.
이제 A가 B의 서비스를 이용한다고 하면, A는 CA가 발급해준 인증서를 B에게 서비스 요청 시 같이 제시하고, B는 가지고 있던 CA 공개키로 검증하여 신뢰할 수 있는 대상인지 확인하여 서비스를 제공한다.
sequenceDiagram
	participant A as Client
	participant CA as Certificate Authority
	participant B as Provider
	
	CA<<-->>B: CA 인증서
	A->>CA: 1️⃣ 인증서 발급 요청(공개 키, 신원정보)
	CA-->>A: 2️⃣ A 인증서 발급(CA 개인키 전자서명)
	A->>B: 3️⃣ 서비스 요청(A 인증서)
	B->>B: 4️⃣ CA 공개 키로 검증
	B-->>A: 5️⃣ 서비스 제공
이 과정이 일반적인 CA를 통한 신원 확인 방법이다. 그렇다면 Velociraptor에서는 어떻게 Server와 Agent가 신뢰 관계를 맺을까?
위에서 한 번 언급했지만, Velociraptor의 server.config.yaml 파일에는 CA 개인키가 들어있다. config generate 명령이 CA 인증서와 CA 개인키, CA가 서명한 서버 인증서와, 서버 개인키를 생성해 server.config.yaml 파일 안에 해당 정보들을 담아주기 때문이다.
구분
포함 정보
역할
Client.ca_certificate
CA 공개 인증서
Agent가 서버 인증서를 검증해 신뢰 관계를 맺을 때 사용
CA.private_key
CA 개인키
서버 인증서 발급 시 사용
Frontend.certificate
CA가 서명한 서버 내부 인증서
서버의 신원을 Agent에 제시
Frontend.private_key
서버 개인키
서버가 Agent와 통신하기 위해 사용
즉, Velociraptor 아키텍처에서는 서버가 내부적으로 직접 자체 CA 역할을 수행하는 것이다.
Velociraptor는 서버가 직접 CA가 되어 자신이 관리하는 Agent(클라이언트)들의 신원을 통제하는 사설 PKI 구조
그리고, Velociraptor는 Agent 배포용 client.config.yaml 파일을 생성할 때 server.config.yaml의 Client 부분에서 추출한 CA의 공개 인증서(Client.ca_certificate)를 포함한다.
client.config.yaml 파일 내용client.config.yaml 파일 내용
client.config.yaml 파일 내용
 
Client CA 공개 인증서에는 CA 공개키가 포함된 인증서 정보가 있다.
따라서, Velociraptor에서는 Agent가 Server의 접속 주소(server_urls)로 /server.pem을 요청해 Frontend.certificate(서버 인증서)를 받고, 이를 보관 중인 CA 공개키로 검증하여 Server를 신뢰하게 된다.
sequenceDiagram
	participant CA as Velociraptor<br/>Server 내부 CA
	participant SERVER as Velociraptor<br/>Server
	participant CLIENT as Velociraptor<br/>Agent(Client)
	
	CA->>CA: 1️⃣ config generate: CA 인증서와 CA 개인키 생성
	SERVER->>SERVER: 2️⃣ config generate: Frontend 인증서용 공개키・개인키 생성
	SERVER->>CA: 3️⃣ 서버 공개키가 담긴 인증서에 대한 서명 요청
	CA-->>SERVER: 4️⃣ CA 개인키로 서명된 Frontend.certificate
	CLIENT->>CLIENT: 5️⃣ 배포받은 client.config.yaml<br/>(Client.ca_certificate와 server_urls 포함)
	CLIENT->>SERVER: 6️⃣ /server.pem 요청
	SERVER-->>CLIENT: 7️⃣ Frontend.certificate 제시
	CLIENT->>CLIENT: 8️⃣ CA 공개키로 검증<br/>(Frontend.certificate 서명)
	CLIENT->>SERVER: 9️⃣ 인증서 검증 후 내부 암호화된 요청 전송
	SERVER-->>CLIENT: 🔟 Frontend.private_key를 이용한 내부 암호화 통신
	
	
	
	
 
반대로 Server가 Agent를 신뢰하는 경우를 보면,
각 Agent는 client.config.yaml과 별개로 고유한 암호화 키(writeback 파일에 저장, 이 파일에 client_id도 포함)를 보유하는데, Server는 Agent가 처음 연결될 때 Agent의 암호화 신원 정보를 등록하고, 이후 통신에서 해당 Agent의 키에 기반한 신원을 확인한다. Velociraptor Security Configuration
Agent의 /etc/velociraptor.writeback.yaml 파일Agent의 /etc/velociraptor.writeback.yaml 파일
Agent의 /etc/velociraptor.writeback.yaml 파일
 
즉, 다른 Agent의 개인키를 갖고 있지 않다면 하나의 Agent는 다른 Agent를 사칭할 수 없다.
정리하면, Agent가 Server를 신뢰할 때는 배포받은 client.config.yaml 내 CA 인증서를 기준으로 Server를 검증하고, Server가 Agent를 신뢰할 때는 최초 등록 단계에서 Agent의 고유한 암호화 키를 기준으로 Agent를 검증하여 양방향 신뢰 구조를 맺는다.
그렇기 때문에, Velociraptor EC2 인스턴스 교체 시 config generate에 의해 CA 인증서가 새롭게 생성되어 기존 Agent가 Server를 신뢰하지 못하게 된다.

🧙‍♀️ 문제해결

이를 해결하기 위해서는 코멘트에서 제시했던 것처럼 server.config.yaml 파일을 Secrets Manager 또는 데이터 EBS에 보관하는 방식을 활용해야 한다. 두 방법을 비교해 보면, 다음과 같다.
구분
Secrets Manager
별도 EBS
server.config.yaml 파일 유지
가능
가능
데이터스토어 (Velociraptor 서버가 알고 있는 모든 기록을 저장하는 저장소)
불가능
가능
IAM 권한(파일 읽기 기준)
GetSecretValue 필요
불필요
파일을 가져오는 방법
부팅 시 Secrets Manager에서 가져와서 사용
인스턴스에 연결되어 있어 계속 사용
가용 영역
상관 없음
인스턴스와 같은 AZ
Secrets Manager는 DB 비밀번호, API 키, 인증서 같은 비밀값을 KMS로 암호화해 보관해주는 역할로, 기존 server.config.yaml 파일을 유지할 수는 있지만 지금 문제상황과는 목적이 조금 다르다. Secrets Manager만 사용하게 되면, Velociraptor 데이터스토어는 root 볼륨 내 경로를 사용하게 되고 조사 데이터는 root 볼륨에서 관리가 된다.
root 볼륨은 기본적으로 인스턴스와 수명을 같이 하기 때문에, 인스턴스 교체 시 hunt 결과, 수집 파일, GUI 사용자 계정이 모두 사라지게 된다.
이에 반해 별도 EBS는 외장 하드디스크 같은 역할을 하며, 인스턴스와 독립된 수명을 가지고 있다. 이 데이터 볼륨을 /data에 마운트하고 /data/velociraptor에 server.config.yaml 파일을 저장해 준다. 그리고 server.config.yaml 파일의 Datastore.location과 Datastore.filestore_directory가 같은 경로(/data/velociraptor)를 가리키도록 설정해주면, Velociraptor의 신원과 기억이 모두 데이터 볼륨에 남게 된다.
독립된 수명을 가지기 때문에, 인스턴스가 교체되어도 별도 EBS는 새로운 인스턴스에 다시 붙어 저장되어 있는 신원과 기억 정보를 그대로 사용할 수 있게 되는 것이다.
따라서, 이번 PR에서는 별도 EBS를 만들어 server.config.yaml 파일과 Velociraptor의 조사 기록을 이 데이터 볼륨에서 관리하도록 구성하여 해결할 계획이다.

🧐 CA 개인키를 Velociraptor 서버에 보관하는 게 안전할까?

Velociraptor는 앞서 언급했던 것처럼 일반적인 웹 사이트 요청처럼 별도의 공인 CA 기관을 통해 신원 검증을 하는 것이 아니고, Velociraptor 서버 내부에서 CA 역할을 하기 때문에, CA 개인키(CA.private_key)를 Velociraptor 서버가 server.config.yaml 파일에 저장해서 관리하고 있다.
여기서 만약 서버가 탈취된다면?
CA 개인키까지 유출될 위험이 있기 때문에, 보안 수준이 낮은 상태라고 볼 수 있다. 보안을 엄격하게 관리하기 위해서는 server.config.yaml 원본 파일을 별도로 안전하게 보관하고, 운영 서버의 CA.private_key 값을 제거하는 것이 좋다.
실제로 Velociraptor 공식 문서에도 이를 권장 아키텍처로 설명하고 있다. Velociraptor Security Configuration
그러면 CA.private_key 값이 없어도 서버를 운영하는 데는 문제가 없을까? 라는 생각이 들었다.
찾아보니, Velociraptor의 일반적인 Agent 수집/통신 단계에서는 해당 키 값이 필요 없고, 오직 새로운 API 키를 발급하거나 서버의 인증서(Frontend.certificate, 기본 유효기간 1년)를 갱신할 때만 사용한다고 되어 있었다.
그럼 CA.private_key를 어떻게 분리하여 보관할 수 있을까?
AWS에서는 위에서 언급했던 Secrets Manager 서비스를 활용해, CA.private_key 값이 포함된 원본 server.config.yaml 파일을 백업해 보관하고, Velociraptor 운영 서버의 server.config.yaml에 있는 CA.private_key 값은 제거하는 것을 권장한다.
그리고, 해당 비밀의 ARN에만 접근하는 권한(secretsmanager:GetSecretValue)을 관리자에게 부여하여 인증서 갱신 필요 시에만 관리자가 원본 설정 파일을 활용해 서버 인증서(Frontend.certificate)를 발급하고 Velociraptor 서버에 배포하는 방식으로 관리한다.
별도 안전한 오프라인 환경(관리자의 보안 USB/외장하드 등)에 보관하는 방식도 있지만, 분실과 고장의 위험이 있으니 주의해야 한다.
팀 근두운에서는 CA 개인키를 우선 서버에 유지하고, 후속 조치 과제로 CA 개인키 분리를 진행해 볼 것이다.

💁 마무리

PR 코멘트를 해결하면서, Velociraptor가 가지는 특징과 Server, Agent의 신뢰 관계에 대해 자세히 공부할 수 있어 좋았다.
이제 이번 과정에서 얻은 이해를 바탕으로 PR을 마무리해보자..!