Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions operation-team-account/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Terraform 관련 파일 무시
.terraform/ # terraform init 시 생성되는 폴더
*.tfstate # 상태 파일 (리소스 실제 정보 포함)
*.tfstate.* # 상태 파일 백업
*.tfvars
*.tfstate.backup
.terraform.lock.hcl
terraform.tfvars # 민감 정보 입력용 파일
crash.log # Terraform 충돌 로그
.terraform
# AWS CLI 자격 증명
.aws/ # ~/.aws/credentials, config 등

# 시스템 자동 생성 파일 (Windows/macOS)
.DS_Store # macOS
Thumbs.db # Windows
ehthumbs.db # Windows
*.log # 일반 로그 파일
*.tmp # 임시 파일

# VSCode 설정 (선택사항)
.vscode/
28 changes: 28 additions & 0 deletions operation-team-account/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module "s3" {
source = "./modules/s3"
}

module "opensearch" {
source = "./modules/opensearch"
sso_role_name = var.sso_role_name
sso_user_name = var.sso_user_name
firehose_role_arn = module.firehose.firehose_role_arn
}

module "firehose" {
source = "./modules/firehose"
opensearch_domain_arn = module.opensearch.domain_arn
s3_bucket_arn = module.s3.bucket_arn
}

module "cloudwatch" {
source = "./modules/cloudwatch"

subscription_filter_name = "cw-to-firehose"
log_group_name = var.log_group_name
firehose_arn = module.firehose.delivery_stream_arn
role_arn = module.firehose.firehose_role_arn
}
module "securitylake" {
source = "./modules/securitylake"
}
12 changes: 12 additions & 0 deletions operation-team-account/modules/cloudwatch/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
resource "aws_cloudwatch_log_group" "target" {
name = var.log_group_name
retention_in_days = 14
}

resource "aws_cloudwatch_log_subscription_filter" "logs_to_firehose" {
name = var.subscription_filter_name
log_group_name = var.log_group_name
filter_pattern = "{ $.level = \"ERROR\" }"
destination_arn = var.firehose_arn
role_arn = var.role_arn
}
19 changes: 19 additions & 0 deletions operation-team-account/modules/cloudwatch/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
variable "subscription_filter_name" {
description = "CloudWatch Logs Subscription Filter 이름"
type = string
}

variable "log_group_name" {
description = "대상 CloudWatch 로그 그룹 이름"
type = string
}

variable "firehose_arn" {
description = "로그를 전송할 Kinesis Firehose ARN"
type = string
}

variable "role_arn" {
description = "CloudWatch Logs → Firehose 연결용 IAM Role ARN"
type = string
}
84 changes: 84 additions & 0 deletions operation-team-account/modules/firehose/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
resource "aws_iam_role" "firehose_role" {
name = "siem-firehose-role"

assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Principal = {
Service = "firehose.amazonaws.com"
},
Action = "sts:AssumeRole"
}
]
})
}

resource "aws_iam_role_policy" "firehose_policy" {
name = "firehose-access"
role = aws_iam_role.firehose_role.id

policy = jsonencode({
Version = "2012-10-17"
Statement = [
# 1) OpenSearch 접근 권한: 도메인 자체와 색인 아래 객체만 허용
{
Effect = "Allow"
Action = [
"es:DescribeElasticsearchDomain",
"es:DescribeElasticsearchDomains", # Note: 이 액션은 리소스 지정이 불가능하여 "*" 사용 필요
"es:DescribeElasticsearchDomainConfig",
"es:ESHttpPost",
"es:ESHttpPut",
"es:ESHttpGet",
]
Resource = [
var.opensearch_domain_arn,
"${var.opensearch_domain_arn}/*",
]
},

# 2) S3 버킷 접근 권한: 버킷 메타데이터 조회와 객체 Put만 해당 버킷으로 제한
{
Effect = "Allow"
Action = [
"s3:ListBucket", # 버킷 목록 조회(버킷 이름에 한정)
"s3:GetBucketLocation", # 리전 조회
]
Resource = var.s3_bucket_arn
},
{
Effect = "Allow"
Action = [
"s3:PutObject", # 객체 업로드
]
Resource = "${var.s3_bucket_arn}/*"
}
]
})
}


resource "aws_kinesis_firehose_delivery_stream" "to_opensearch" {
name = "siem-delivery"
destination = "opensearch"

opensearch_configuration {
domain_arn = var.opensearch_domain_arn
role_arn = aws_iam_role.firehose_role.arn
index_name = "cw-logs"
type_name = "log"

s3_backup_mode = "FailedDocumentsOnly"

s3_configuration {
role_arn = aws_iam_role.firehose_role.arn
bucket_arn = var.s3_bucket_arn
buffering_interval = 300
buffering_size = 5
compression_format = "GZIP"
prefix = "backup/"
}
}
}
9 changes: 9 additions & 0 deletions operation-team-account/modules/firehose/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "delivery_stream_arn" {
value = aws_kinesis_firehose_delivery_stream.to_opensearch.arn
description = "ARN of the Firehose delivery stream"
}

output "firehose_role_arn" {
value = aws_iam_role.firehose_role.arn
description = "ARN of the Firehose IAM role"
}
7 changes: 7 additions & 0 deletions operation-team-account/modules/firehose/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
variable "opensearch_domain_arn" {
type = string
}

variable "s3_bucket_arn" {
type = string
}
50 changes: 50 additions & 0 deletions operation-team-account/modules/opensearch/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
data "aws_caller_identity" "current" {}

resource "aws_opensearch_domain" "siem" {
domain_name = "siem-domain"
engine_version = "OpenSearch_2.9"

cluster_config {
instance_type = "t3.small.search"
instance_count = 1
}

ebs_options {
ebs_enabled = true
volume_size = 10
}

domain_endpoint_options {
enforce_https = true
tls_security_policy = "Policy-Min-TLS-1-2-2019-07"
}

node_to_node_encryption {
enabled = true
}

encrypt_at_rest {
enabled = true
}

access_policies = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
AWS = [
"arn:aws:sts::${data.aws_caller_identity.current.account_id}:assumed-role/${var.sso_role_name}/${var.sso_user_name}",
var.firehose_role_arn,
]
}
Action = "es:*"
# 도메인 및 그 하위 인덱스·도큐먼트 전체 리소스
Resource = [
aws_opensearch_domain.siem.arn,
"${aws_opensearch_domain.siem.arn}/*",
]
}
]
})
}
3 changes: 3 additions & 0 deletions operation-team-account/modules/opensearch/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "domain_arn" {
value = aws_opensearch_domain.siem.arn
}
15 changes: 15 additions & 0 deletions operation-team-account/modules/opensearch/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
variable "sso_role_name" {
description = "SSO에서 부여된 IAM 역할 이름"
type = string
}

variable "sso_user_name" {
description = "SSO 세션 사용자 이름 (예: 이메일)"
type = string
}

variable "firehose_role_arn" {
description = "ARN of the Firehose IAM role to allow write access"
type = string
}

49 changes: 49 additions & 0 deletions operation-team-account/modules/s3/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
resource "random_id" "bucket_id" {
byte_length = 4
}

resource "aws_s3_bucket" "firehose_backup" {
bucket = "siem-firehose-backup-${random_id.bucket_id.hex}"
force_destroy = true
}

resource "aws_s3_bucket_public_access_block" "block" {
bucket = aws_s3_bucket.firehose_backup.id

block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}

# S3 버킷에 Lifecycle 정책 붙이기
resource "aws_s3_bucket_lifecycle_configuration" "firehose_backup" {
bucket = aws_s3_bucket.firehose_backup.id

rule {
id = "ExpireBackup"
status = "Enabled"

filter { prefix = "backup/" }

expiration { days = 7 } # 7일 지난 백업은 자동 삭제
}
}

resource "aws_kms_key" "s3_cmk" {
description = "KMS key for encrypting Firehose backup S3 bucket"
deletion_window_in_days = 10
enable_key_rotation = true
}

# 암호화 설정
resource "aws_s3_bucket_server_side_encryption_configuration" "default" {
bucket = aws_s3_bucket.firehose_backup.id

rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_key.s3_cmk.arn
}
}
}
3 changes: 3 additions & 0 deletions operation-team-account/modules/s3/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "bucket_arn" {
value = aws_s3_bucket.firehose_backup.arn
}
42 changes: 42 additions & 0 deletions operation-team-account/modules/securitylake/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# # 1. 메타스토어 관리자 IAM 역할 생성
# resource "aws_iam_role" "securitylake_manager" {
# name = "securitylake-meta-store-manager"

# assume_role_policy = jsonencode({
# Version = "2012-10-17",
# Statement = [
# {
# Effect = "Allow",
# Principal = { Service = "securitylake.amazonaws.com" },
# Action = "sts:AssumeRole"
# }
# ]
# })
# }

# # 2. 조직 단위 Security Lake 활성화 (조직 전체 설정)
# resource "aws_securitylake_organization_configuration" "org_config" {
# auto_enable {
# all_regions = false
# regions = ["ap-northeast-2"]
# }
# }

# # 3. 특정 리전(ap-northeast-2)에서 Data Lake 활성화 및 라이프사이클 설정
# resource "aws_securitylake_data_lake" "this" {
# meta_store_manager_role_arn = aws_iam_role.securitylake_manager.arn

# configuration {
# region = "ap-northeast-2"

# lifecycle_configuration {
# expiration {
# days = 30 # 데이터 30일 보관
# }
# transition {
# days = 7
# storage_class = "ONEZONE_IA" # 7일 후 저비용 스토리지로 전환
# }
# }
# }
# }
1 change: 1 addition & 0 deletions operation-team-account/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

13 changes: 13 additions & 0 deletions operation-team-account/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.11.0"
}
}
}

provider "aws" {
region = "ap-northeast-2"
profile = "my-profile"
}
14 changes: 14 additions & 0 deletions operation-team-account/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
variable "sso_role_name" {
description = "SSO에서 부여된 IAM 역할 이름"
type = string
}

variable "sso_user_name" {
description = "SSO 세션 사용자 이름"
type = string
}

variable "log_group_name" {
description = "전송할 CloudWatch Log Group 이름"
type = string
}
Loading