FleetDM API 활용한 Osquery 자동 수행 및 결과 수집 분석
FleetDM API를 통해 설치된 에이전트 호스트 정보를 가져오기 위해서는 다음 단계들이 필요합니다.
1. API Token 발급
FleetDM API를 사용하려면 API 토큰이 필요합니다. FleetDM 웹 인터페이스를 통해 토큰을 발급받아야 합니다.
- FleetDM 웹 인터페이스에 로그인합니다.
- 오른쪽 상단의 프로필 아이콘을 클릭하고 "API Tokens"를 선택합니다.
- "Create an API token"을 클릭하고 토큰을 생성합니다.
- 생성된 토큰을 기록해 둡니다. 이 토큰은 API 요청 시 인증에 사용됩니다.
2. API 요청 준비
FleetDM API는 RESTful API로, 호스트 정보를 가져오기 위한 엔드포인트는 /api/v1/fleet/hosts
입니다. 요청을 보내기 위해 cURL을 사용하거나 Python 등 다양한 방법을 사용할 수 있습니다.
cURL을 사용한 예시
curl -X GET https://<your_fleetdm_url>/api/v1/fleet/hosts \
-H "Authorization: Bearer <your_api_token>" \
-H "Content-Type: application/json"
Python을 사용한 예시
import requests
url = 'https://<your_fleetdm_url>/api/v1/fleet/hosts'
headers = {
'Authorization': 'Bearer <your_api_token>',
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
hosts = response.json()
print(hosts)
else:
print(f"Failed to retrieve hosts: {response.status_code}")
3. API 응답 처리
API 호출에 성공하면 JSON 형식의 데이터가 반환됩니다. 예를 들어, 반환된 데이터는 다음과 같습니다.
{
"hosts": [
{
"id": 1,
"hostname": "host1",
"primary_ip": "192.168.1.1",
"osquery_version": "4.6.0",
"status": "active",
"last_seen_at": "2024-06-26T10:00:00Z"
},
{
"id": 2,
"hostname": "host2",
"primary_ip": "192.168.1.2",
"osquery_version": "4.6.0",
"status": "offline",
"last_seen_at": "2024-06-25T15:00:00Z"
}
]
}
4. 추가 옵션
호스트 정보를 가져올 때 특정 필터를 적용하거나, 페이지네이션 등을 설정할 수 있습니다.
예시: 특정 필터 적용
curl -X GET 'https://<your_fleetdm_url>/api/v1/fleet/hosts?status=active' \
-H "Authorization: Bearer <your_api_token>" \
-H "Content-Type: application/json"
- API 토큰을 안전하게 관리하고 노출되지 않도록 주의합니다.
- HTTPS를 사용하여 통신 데이터를 암호화합니다.
- 최소 권한 원칙을 적용하여 필요한 권한만 부여된 API 토큰을 사용합니다.
활용 사례
- 정기적으로 호스트 정보를 가져와서 인벤토리 업데이트
- 호스트 상태 모니터링 및 리포트 생성
- 특정 조건에 맞는 호스트에 대한 자동화된 대응 조치 수행
FleetDM API를 활용하면 효율적으로 호스트를 관리하고, 보안 이벤트에 빠르게 대응할 수 있습니다. FleetDM API를 사용하여 현재 등록된 쿼리 목록과 스케줄 정보를 가져오는 방법입니다.
1. API Token 발급
API 토큰을 FleetDM 웹 인터페이스에서 발급받습니다. (앞서 설명한 방법 참조)
2. 등록된 쿼리 목록 가져오기
FleetDM API 엔드포인트 /api/v1/fleet/queries
를 사용하여 등록된 쿼리 목록을 가져올 수 있습니다.
cURL을 사용한 예시
curl -X GET https://<your_fleetdm_url>/api/v1/fleet/queries \
-H "Authorization: Bearer <your_api_token>" \
-H "Content-Type: application/json"
Python을 사용한 예시
import requests
url = 'https://<your_fleetdm_url>/api/v1/fleet/queries'
headers = {
'Authorization': 'Bearer <your_api_token>',
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
queries = response.json()
print(queries)
else:
print(f"Failed to retrieve queries: {response.status_code}")
3. 스케줄 정보 가져오기
FleetDM API 엔드포인트 /api/v1/fleet/scheduled_queries
를 사용하여 스케줄 정보를 가져올 수 있습니다.
cURL을 사용한 예시
curl -X GET https://<your_fleetdm_url>/api/v1/fleet/scheduled_queries \
-H "Authorization: Bearer <your_api_token>" \
-H "Content-Type: application/json"
Python을 사용한 예시
import requests
url = 'https://<your_fleetdm_url>/api/v1/fleet/scheduled_queries'
headers = {
'Authorization': 'Bearer <your_api_token>',
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
scheduled_queries = response.json()
print(scheduled_queries)
else:
print(f"Failed to retrieve scheduled queries: {response.status_code}")
4. API 응답 처리
API 호출에 성공하면 JSON 형식의 데이터가 반환됩니다. 각각의 엔드포인트에서 반환되는 데이터는 다음과 같습니다.
쿼리 목록 예시
{
"queries": [
{
"id": 1,
"name": "query_name",
"description": "query_description",
"query": "SELECT * FROM osquery_info;",
"author_id": 1,
"author_name": "admin",
"created_at": "2024-06-01T12:00:00Z",
"updated_at": "2024-06-10T12:00:00Z"
},
// 추가 쿼리 정보
]
}
스케줄 정보 예시
{
"scheduled_queries": [
{
"id": 1,
"pack_id": 1,
"query_id": 1,
"interval": 3600,
"platform": "all",
"version": "2.9.0",
"shard": 100,
"created_at": "2024-06-01T12:00:00Z",
"updated_at": "2024-06-10T12:00:00Z"
},
// 추가 스케줄 정보
]
}
활용 사례
- 정기적으로 쿼리 및 스케줄 정보를 가져와서 인벤토리 업데이트
- 특정 조건에 맞는 쿼리를 자동화하여 보안 이벤트 모니터링
- 쿼리 스케줄을 최적화하여 시스템 자원 사용 효율성 향상
이 방법을 통해 FleetDM에서 등록된 쿼리 목록과 스케줄 정보를 쉽게 가져올 수 있습니다. 실제 운영을 위해서 특정 쿼리를 수행하는 n8n 노드를 구성하는 방법입니다.
n8n에서 HTTP Request 노드 구성
FleetDM API를 호출하기 위해 n8n에서 HTTP Request 노드를 사용합니다.
- HTTP Request 노드 추가
- n8n 에디터에서 "HTTP Request" 노드를 추가합니다.
- HTTP Request 노드 설정
- Method:
POST
- URL:
https://<your-fleetdm-server>/api/v1/fleet/queries/run
- Authentication: Bearer Token
- Access Token: FleetDM API 키 입력
- Body Parameters
query
: 실행할 osquery 쿼리 입력hosts
: 쿼리를 실행할 호스트 ID 목록 입력
- Method:
설정이 완료되면 워크플로우를 저장하고 실행합니다. 워크플로우가 실행되면 지정된 호스트에서 osquery 쿼리가 실행되고 결과를 반환받습니다. 이렇게 구성한 n8n 노드를 통해 FleetDM API를 호출하여 osquery 쿼리를 수행할 수 있습니다.
추가적인 워크플로우 자동화 작업도 n8n을 통해 손쉽게 설정할 수 있습니다. FleetDM API를 통해 쿼리를 수행한 후 결과를 가져오고, 이를 n8n에서 집계하여 Slack으로 알림을 보내는 워크플로우를 구성할 수 있습니다.
HTTP Request 노드: 쿼리 결과 확인
쿼리가 실행된 후, 쿼리 ID를 통해 결과를 가져옵니다.
- HTTP Request 노드 추가
- Method:
GET
- URL:
https://<your-fleetdm-server>/api/v1/fleet/results/<query_id>
- Authentication: Bearer Token
- Access Token: FleetDM API 키 입력
- Method:
Set 노드: 결과 집계
쿼리 결과를 가져온 후 필요한 데이터를 집계합니다.
- Set 노드 추가
- 필요한 데이터를 집계 및 가공합니다.
Slack 노드: 알림 보내기
집계된 데이터를 Slack으로 알림을 보냅니다.
- Slack 노드 추가
- Slack API 키를 사용하여 메시지를 전송합니다.
- 채널 및 메시지 내용을 설정합니다.
이 워크플로우를 통해 FleetDM API를 호출하여 쿼리를 실행하고, 결과를 가져와 집계한 후, Slack으로 알림을 보낼 수 있습니다. 쿼리 실행 후 결과를 바로 수집할 수 없는 상황을 고려하여, 쿼리 실행 후 일정 시간 간격으로 결과를 확인하고 결과가 준비되면 Slack으로 알림을 보내는 방법으로 n8n에서 반복 작업을 수행하는 워크플로우를 구성할 수 있습니다.
- HTTP Request 노드: 쿼리 실행
- Wait 노드: 일정 시간 대기
- HTTP Request 노드: 쿼리 결과 확인
- IF 노드: 결과가 준비되었는지 확인
- Set 노드: 결과 집계
- Slack 노드: 알림 보내기
- Loop 노드: 결과가 준비되지 않은 경우 다시 체크
1. HTTP Request 노드: 쿼리 실행
{
"parameters": {
"requestMethod": "POST",
"url": "https://<your-fleetdm-server>/api/v1/fleet/queries/run",
"options": {},
"authentication": "predefinedCredentialType",
"sendBinaryData": false,
"jsonParameters": true,
"bodyParametersJson": {
"query": "SELECT * FROM osquery_info;",
"hosts": [1, 2, 3]
},
"headerParametersJson": {
"Authorization": "Bearer YOUR_FLEETDM_API_KEY"
}
},
"name": "Run Query",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"position": [450, 300]
}
2. Wait 노드: 일정 시간 대기
{
"parameters": {
"interval": "1",
"unit": "minutes"
},
"name": "Wait 1 Minute",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"position": [750, 300]
}
3. HTTP Request 노드: 쿼리 결과 확인
{
"parameters": {
"requestMethod": "GET",
"url": "https://<your-fleetdm-server>/api/v1/fleet/results/={{$json[\"query_id\"]}}",
"options": {},
"authentication": "predefinedCredentialType",
"sendBinaryData": false,
"headerParametersJson": {
"Authorization": "Bearer YOUR_FLEETDM_API_KEY"
}
},
"name": "Check Results",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"position": [1050, 300]
}
4. IF 노드: 결과가 준비되었는지 확인
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json[\"status\"]}}",
"value2": "completed"
}
]
}
},
"name": "If Results Ready",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [1350, 300]
}
5. Set 노드: 결과 집계
{
"parameters": {
"keepOnlySet": false,
"values": {
"string": [
{
"name": "message",
"value": "Query results: {{$json[\"results\"]}}"
}
]
},
"options": {}
},
"name": "Aggregate Results",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [1650, 300]
}
6. Slack 노드: 알림 보내기
{
"parameters": {
"authentication": "predefinedCredentialType",
"channel": "#alerts",
"text": "{{$json[\"message\"]}}"
},
"name": "Send to Slack",
"type": "n8n-nodes-base.slack",
"typeVersion": 1,
"position": [1950, 300]
}
7. Loop 노드: 결과가 준비되지 않은 경우 다시 체크
{
"parameters": {},
"name": "Loop",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [1050, 600]
}
이 워크플로우는 쿼리 실행 후 일정 시간 간격으로 결과를 확인하며, 결과가 준비되면 이를 Slack으로 알림을 보냅니다. FleetDM을 통해 전체 시스템에 특정 쿼리를 전송하고, 일정 시간 후에 결과를 수집하여 리포팅하는 전체 워크플로우 예시입니다.
{
"nodes": [
{
"name": "Run Query",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"position": [450, 300],
"parameters": {
"requestMethod": "POST",
"url": "https://<your-fleetdm-server>/api/v1/fleet/queries/run",
"authentication": "predefinedCredentialType",
"sendBinaryData": false,
"jsonParameters": true,
"bodyParametersJson": {
"query": "SELECT * FROM osquery_info;",
"hosts": [1, 2, 3]
},
"headerParametersJson": {
"Authorization": "Bearer YOUR_FLEETDM_API_KEY"
}
}
},
{
"name": "Wait 5 Minutes",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"position": [750, 300],
"parameters": {
"interval": 5,
"unit": "minutes"
}
},
{
"name": "Check Results",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"position": [1050, 300],
"parameters": {
"requestMethod": "GET",
"url": "https://<your-fleetdm-server>/api/v1/fleet/results/={{$json["query_id"]}}",
"authentication": "predefinedCredentialType",
"sendBinaryData": false,
"headerParametersJson": {
"Authorization": "Bearer YOUR_FLEETDM_API_KEY"
}
}
},
{
"name": "If Results Ready",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [1350, 300],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json["status"]}}",
"value2": "completed"
}
]
}
}
},
{
"name": "Loop",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [1050, 600],
"parameters": {}
},
{
"name": "Aggregate Results",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [1650, 300],
"parameters": {
"keepOnlySet": false,
"values": {
"string": [
{
"name": "message",
"value": "Query results: {{$json["results"]}}"
}
]
},
"options": {}
}
},
{
"name": "Send to Slack",
"type": "n8n-nodes-base.slack",
"typeVersion": 1,
"position": [1950, 300],
"parameters": {
"authentication": "predefinedCredentialType",
"channel": "#alerts",
"text": "{{$json["message"]}}"
}
}
],
"connections": {
"Run Query": {
"main": [
[
{
"node": "Wait 5 Minutes",
"type": "main",
"index": 0
}
]
]
},
"Wait 5 Minutes": {
"main": [
[
{
"node": "Check Results",
"type": "main",
"index": 0
}
]
]
},
"Check Results": {
"main": [
[
{
"node": "If Results Ready",
"type": "main",
"index": 0
}
]
]
},
"If Results Ready": {
"main": [
[
{
"node": "Aggregate Results",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait 5 Minutes",
"type": "main",
"index": 0
}
]
]
},
"Aggregate Results": {
"main": [
[
{
"node": "Send to Slack",
"type": "main",
"index": 0
}
]
]
}
}
}
이 워크플로우는 FleetDM을 통해 쿼리를 실행하고, 일정 시간 후 결과를 확인하여, 결과가 준비되면 이를 집계하여 Slack으로 리포팅합니다.