황준하
오늘 회의의 핵심은 SIEM 실습 인프라를 어떻게 안전하면서도 실용적으로 구축할 것인가였다. 특히 세 가지 큰 주제가 있었다.
처음엔 단순하게 생각했다. "IAM으로 하면 되겠지?"
그런데 OpenSearch가 생성 시점에 관리자 비밀번호를 무조건 요구한다. Terraform으로 랜덤 비밀번호를 생성하면 terraform.tfstate 파일에 평문으로 남는다는 게 문제였다.
선택지 A: Terraform으로 비밀번호 생성 + Secrets Manager 저장
Terraform random_password 생성
↓
OpenSearch 생성 시 사용
↓
Secrets Manager에 저장
↓
ECS(Logstash)는 Secrets Manager 참조
장점: 구조가 단순하다
단점: state 파일에 비밀번호가 평문으로 남는다
선택지 B: OpenSearch를 bootstrap 영역으로 분리
장점: 구조적으로 깔끔하다
단점: 실습 환경에서 관리 복잡도가 과도하게 올라간다
선택지 A를 채택했다.
이유는 간단하다. 이번 프로젝트는 실습 + 포트폴리오용이다. 완벽한 보안보다는 트레이드오프를 이해하고 설명할 수 있는 능력이 더 중요하다.
실무에서도 OpenSearch 초기 비밀번호를 IaC로 관리하는 경우가 많다. 중요한 건 state 파일 자체를 어떻게 보호하느냐다.
1차 방어: S3 Backend 암호화 (AES-256) + Versioning
2차 방어: DynamoDB Lock (동시성 제어)
3차 방어: IAM 기반 State 접근 통제
4차 방어: S3 Bucket Policy 제한
이 정도면 state 파일이 쉽게 노출되지 않는다. 완벽하진 않지만 합리적인 선택이다.
팀 내에서 "IAM이 더 낫다"는 의견이 나왔다. 실제로 맞는 말이다.
비밀번호는 결국 비밀값 자체가 공격 표면이다.
IAM은 자격 증명 자체가 존재하지 않는다.
그런데 OpenSearch Dashboards와 REST API는 기본적으로 Basic Auth가 필요하다. Logstash 플러그인도 IAM SigV4 지원이 불안정하다.
결론: 현 단계에서는 IAM + Secret 혼합 구조를 허용한다.
나중에 Kinesis Data Firehose 같은 AWS 관리형 서비스로 전환하면 완전 IAM 기반으로 갈 수 있다.
OpenSearch는 분석용 시스템이다.
S3는 신뢰 가능한 원본 저장소다.
OpenSearch에 로그를 영구 보관하는 건 비효율적이다. 비용도 많이 들고, 인덱스 삭제하면 로그가 영구 손실된다.
따라서 이중화 구조를 설계했다.
Bucket 1: siem-raw-logs-bucket (원본 보관)
CloudWatch Logs
↓
Kinesis Data Streams
↓
Firehose
↓
S3 (Raw)
Bucket 2: siem-normalized-logs-bucket (정제 로그)
S3 (Raw)
↓
Lambda (파싱/정규화)
↓
S3 (Normalized) + OpenSearch
원본 로그는 절대 건드리면 안 된다. 나중에 "이 로그 다시 파싱해야 하는데?" 하는 상황이 생길 수 있다.
정규화된 로그는 OpenSearch에 바로 넣을 수 있는 형태다. OpenSearch가 터지거나 인덱스를 잘못 지워도 S3에서 다시 복구할 수 있다.
{system}-{domain}-{purpose}-{env}-{YYYY.MM.DD}
| 인덱스명 | 설명 |
|---|---|
siem-web-access-dev-2025.12.16 | 웹 접근 로그 |
siem-web-attack-dev-2025.12.16 | 웹 공격 로그 |
siem-system-auth-dev-2025.12.16 | 시스템 인증 로그 |
siem-network-traffic-dev-2025.12.16 | 네트워크 트래픽 |
| 요소 | 설명 | 예시 |
|---|---|---|
system | 시스템 범주 | siem |
domain | 로그 도메인 | web, system, network |
purpose | 목적/이벤트 타입 | access, attack, auth |
env | 환경 | dev, staging, prod |
YYYY.MM.DD | 시간 기반 분할 | 2025.12.16 |
예를 들어 공격 로그만 따로 30일 이후 삭제하고, 접근 로그는 90일까지 보관하는 식으로 정책을 다르게 가져갈 수 있다.
Index State Management의 약자다. OpenSearch 인덱스의 라이프사이클을 자동으로 관리해주는 기능이다.
간단하게 말하면 "30일 지난 인덱스는 자동으로 삭제해줘" 이런 걸 설정할 수 있다.
{
"policy": {
"description": "SIEM 실습용 로그 라이프사이클",
"default_state": "hot",
"states": [
{
"name": "hot",
"actions": [],
"transitions": [
{
"state_name": "delete",
"conditions": {
"min_index_age": "30d"
}
}
]
},
{
"name": "delete",
"actions": [
{
"snapshot": {
"repository": "s3-snapshot-repo",
"snapshot": "siem-snapshot-${index}"
}
},
{
"delete": {}
}
]
}
]
}
}
인덱스 생성
↓
Hot 상태 (0~30일)
→ 실시간 분석
→ Alert 생성
→ Dashboard 조회
↓
30일 경과
↓
Delete 상태
→ S3 Snapshot 생성
→ 인덱스 삭제
실습 환경이라 비용 관리가 중요하다. 30일치 로그면 분석하기에 충분하고, 그 이상은 S3에 보관하면 된다.
실무에서는 Hot → Warm → Cold 구조로 가져가는데, 지금은 그렇게까지 복잡하게 할 필요는 없다.
문제: OpenSearch 관리자 비밀번호가 terraform.tfstate에 평문으로 기록된다.
해결 방안
.gitignore에 state 파일 등록이거 진짜 고민 많이 했다. 완벽한 해결책은 없다. 대신 리스크를 인지하고 완화하는 방향으로 갔다.
문제: Logstash OpenSearch output 플러그인의 IAM SigV4 지원이 불안정하다.
조치 계획
플러그인 문서 보면서 삽질 좀 했다. IAM으로 깔끔하게 가고 싶었는데 현실의 벽에 부딪혔다.
문제: 일 단위 인덱스 생성 시 장기 운영하면 스토리지 비용이 계속 증가한다.
해결 방안
완벽한 보안은 없다
처음엔 "IAM으로 100% 깔끔하게 가자"고 생각했다. 그런데 현실은 그렇게 호락호락하지 않더라.
OpenSearch는 생성 시점에 비밀번호가 필요하고, Logstash 플러그인은 IAM을 완벽하게 지원하지 않는다.
중요한 건 트레이드오프를 이해하고 설명할 수 있는 능력이다.
아키텍처는 계층적으로 설계해야 한다
OpenSearch와 S3를 분리한 게 정말 잘한 선택이었다. OpenSearch는 분석용, S3는 보관용으로 역할을 명확히 나눴다.
이렇게 하면 나중에 OpenSearch를 완전히 갈아엎어도 S3에 원본 로그가 있으니까 문제없다.
네이밍은 중요하다
인덱스 네이밍 규칙을 처음부터 제대로 정한 게 큰 도움이 됐다. 나중에 인덱스가 수백 개가 되면 관리가 불가능해진다.
siem-web-attack-dev-2025.12.16 이런 식으로 명확하게 구조화하니까 ISM 정책 적용하기도 쉽고, 쿼리 작성하기도 편하다.
IAM 인증을 완전히 구현하지 못한 것
Logstash 플러그인 때문에 Basic Auth를 섞어야 했다. 이게 좀 찝찝하다.
다음 단계에서는 Kinesis Data Firehose로 전환해서 완전 IAM 기반으로 가려고 한다.
테스트 환경 부족
설계는 다 했는데 실제로 구축하고 테스트하는 시간이 부족했다. 내일은 Terraform 코드 작성하고 실제로 배포해봐야겠다.
특히 Index Templates는 필드 매핑을 표준화하는 데 필수라서 제대로 공부해야겠다.
작성자: 황준하 (HoHK)
작성일: 2025-12-16
프로젝트: 2SeC-SIEM (LLM-CTI 통합 보안 분석 시스템)
팀: 2SeC Team (KT Cloud TECH UP Program)