Observability/Prometheus

EP18 [Part 6: 고급 모니터링 전략] 보안 및 성능 최적화

ygtoken 2025. 3. 25. 13:58
728x90

이번에는 모니터링 시스템의 보안과 성능 최적화에 대해 알아보겠습니다. 모니터링 시스템은 클러스터 전반의 중요한 정보에 접근할 수 있기 때문에 보안이 매우 중요하며, 대규모 환경에서는 모니터링 시스템 자체의 성능이 병목이 되지 않도록 최적화가 필요합니다. 이 글에서는 Prometheus와 Grafana를 중심으로 보안을 강화하면서도 최적의 성능을 유지하는 방법에 대해 살펴보겠습니다.


📌 모니터링 시스템의 보안 위협 및 취약점

쿠버네티스 환경에서 모니터링 시스템이 직면하는 보안 위협과 잠재적 취약점에 대해 알아보겠습니다.

✅ 주요 보안 위협 모델

쿠버네티스 모니터링 시스템 보안 위협 모델

 

모니터링 시스템이 직면할 수 있는 다양한 보안 위협을 이해하는 것이 중요합니다.

  1. 무단 접근 위험
    • 인증되지 않은 사용자의 메트릭 접근
    • 민감한 비즈니스 데이터 노출
    • 내부 시스템 구조 정보 유출
  2. 권한 상승 위협
    • 제한된 역할의 사용자가 관리자 권한 획득
    • 모니터링 구성 변경을 통한 보안 우회
    • 알림 채널을 통한 시스템 조작
  3. 데이터 무결성 위협
    • 거짓 메트릭 주입
    • 악의적인 스크래핑 타겟 추가
    • 시계열 데이터 변조
# 보안 위협 분석 및 RBAC 설정 예시
# 이 설정은 다양한 역할에 따른 권한을 세분화하여 정의합니다.

# 1. 네임스페이스 제한 역할 - 특정 네임스페이스 모니터링만 허용
apiVersion: rbac.authorization.k8s.io/v1  # RBAC API 버전
kind: Role                                # 네임스페이스 범위 역할 정의
metadata:
  name: namespace-monitoring-viewer       # 역할 이름
  namespace: app-team1                    # 적용될 네임스페이스
rules:
- apiGroups: [""]                        # 코어 API 그룹
  resources: ["services", "pods", "endpoints"]  # 접근 가능한 리소스 종류
  verbs: ["get", "list", "watch"]        # 읽기 전용 작업만 허용 (변경 불가)
- apiGroups: ["monitoring.coreos.com"]   # Prometheus Operator API 그룹
  resources: ["servicemonitors"]         # ServiceMonitor 리소스에 대한 접근
  verbs: ["get", "list", "watch"]        # 읽기 전용 권한만 부여
---
# 2. 글로벌 읽기 전용 역할 - 클러스터 전체 모니터링 정보 읽기만 허용
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole                        # 클러스터 전체 적용 역할 (네임스페이스 제한 없음)
metadata:
  name: monitoring-readonly              # 역할 이름
rules:
- apiGroups: [""]                        # 코어 API 그룹
  resources: ["nodes", "nodes/proxy", "services", "endpoints", "pods"]  # 다양한 리소스 포함
  verbs: ["get", "list", "watch"]        # 읽기 전용 작업만 허용
- apiGroups: ["monitoring.coreos.com"]   # Prometheus Operator API 그룹
  resources: ["alertmanagers", "prometheuses", "servicemonitors", "podmonitors", "prometheusrules"]
  verbs: ["get", "list", "watch"]        # 모든 모니터링 리소스에 대한 읽기 전용 권한
---
# 3. 모니터링 관리자 역할 - 모니터링 리소스 완전 관리 권한
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole                        # 클러스터 전체 적용 역할
metadata:
  name: monitoring-admin                 # 관리자 역할 이름
rules:
- apiGroups: [""]                        # 코어 API 그룹
  resources: ["namespaces", "nodes", "nodes/proxy", "services", "endpoints", "pods"]
  verbs: ["get", "list", "watch"]        # 기본 리소스는 읽기만 허용
- apiGroups: ["monitoring.coreos.com"]   # Prometheus Operator API 그룹
  resources: ["alertmanagers", "prometheuses", "servicemonitors", "podmonitors", "prometheusrules", "thanosrulers"]
  verbs: ["*"]                           # 모든 작업 허용 (생성, 수정, 삭제 포함)
                                         # 실제로는 더 세분화된 권한이 바람직함

✅ 모니터링 스택의 취약점 탐색

모니터링 시스템의 다양한 컴포넌트에서 발생할 수 있는 취약점을 살펴보겠습니다.

  1. Prometheus 취약점
    • 인증 없는 API 엔드포인트
    • 웹 인터페이스 보안 결함
    • 기본 설정의 보안 문제
  2. Grafana 취약점
    • 취약한 기본 자격 증명
    • 플러그인 보안 문제
    • 구 버전의 알려진 취약점
  3. 알림 시스템 취약점
    • 암호화되지 않은 통신
    • 인증되지 않은 알림 수신
    • 웹훅 엔드포인트 조작
# 취약점 완화를 위한 설정 예시
# 기본 설정의 보안 취약점을 해결하기 위한 구성 사례입니다.

# Prometheus 서비스를 내부망에만 노출하는 설정
apiVersion: v1                              # 쿠버네티스 API 버전
kind: Service                               # 서비스 리소스 정의
metadata:
  name: prometheus-operated                 # 서비스 이름
  namespace: monitoring                     # 모니터링 네임스페이스
  labels:
    app: prometheus                         # 서비스 레이블
spec:
  type: ClusterIP                           # 클러스터 내부에만 노출 (외부에서 직접 접근 불가)
                                            # LoadBalancer나 NodePort가 아닌 ClusterIP로 제한
  ports:
  - name: web                               # 포트 이름
    port: 9090                              # 서비스 포트
    targetPort: web                         # 대상 포트 (컨테이너 포트)
  selector:
    app: prometheus                         # 트래픽을 전달할 파드 선택기
---
# 인그레스에 인증 및 TLS 적용 (Prometheus용)
apiVersion: networking.k8s.io/v1            # 쿠버네티스 Networking API 버전
kind: Ingress                               # 인그레스 리소스 정의
metadata:
  name: prometheus-ingress                  # 인그레스 이름
  namespace: monitoring                     # 네임스페이스
  annotations:
    # 기본 인증 적용 - 인증 없이는 접근 불가
    nginx.ingress.kubernetes.io/auth-type: basic                 # 기본 HTTP 인증 사용
    nginx.ingress.kubernetes.io/auth-secret: prometheus-basic-auth  # 인증 정보가 저장된 Secret
    nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"  # 인증 영역 메시지
    # 보안 헤더 추가 - 웹 브라우저 보안 강화
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "X-Frame-Options: DENY";                  # 클릭재킹 방지 헤더
      more_set_headers "X-Content-Type-Options: nosniff";        # MIME 타입 스니핑 방지
      more_set_headers "X-XSS-Protection: 1; mode=block";        # XSS 공격 보호
spec:
  tls:                                     # TLS 설정으로 HTTPS 강제
  - hosts:
    - prometheus.example.com               # 도메인 이름
    secretName: prometheus-tls             # TLS 인증서 Secret
  rules:
  - host: prometheus.example.com           # 호스트 규칙
    http:
      paths:
      - path: /                            # 모든 경로
        pathType: Prefix                   # 경로 타입 (접두사)
        backend:
          service:
            name: prometheus-operated      # 백엔드 서비스
            port:
              name: web                    # 서비스 포트

▶️ 실제 보안 사고 사례: 한 기업은 프로덕션 Prometheus 서버를 외부 네트워크에 인증 없이 노출시켜 놓았습니다. 공격자는 메트릭 API를 통해 내부 시스템 구조, 실행 중인 컨테이너 목록, 서비스 이름 등의 정보를 수집할 수 있었고, 이를 바탕으로 더 심각한 침투 공격의 발판을 마련했습니다. 이후 회사는 모든 모니터링 인터페이스에 인증을 적용하고, 네트워크 분리를 구현하고, 중요한 메트릭의 이름과 레이블을 난독화하는 전략을 채택했습니다.


📌 모니터링 시스템 보안 강화 전략

모니터링 시스템의 보안을 강화하는 다양한 전략과 구체적인 구현 방법을 알아보겠습니다.

 

보안이 강화된 쿠버네티스 모니터링 아키텍쳐 예시

 

✅ 강력한 인증 및 권한 제어

모니터링 시스템에 대한 접근을 제한하고 권한을 세분화하는 방법입니다.

  1. 다단계 인증(MFA) 구현
    • OIDC 통합
    • OAuth2 프록시 활용
    • LDAP/AD 인증 연동
  2. 세분화된 접근 제어
    • 역할 기반 접근 제어(RBAC)
    • 네임스페이스 수준 권한 분리
    • 데이터소스 접근 제한
  3. 보안 컨텍스트 설정
    • 컨테이너 루트 권한 제거
    • 파일시스템 읽기 전용 마운트
    • 기능(capabilities) 제한
# Grafana의 강력한 인증 및 권한 설정 예시
# OAuth2와 RBAC를 활용한 보안 강화 설정입니다.

apiVersion: v1                           # 쿠버네티스 API 버전
kind: ConfigMap                          # ConfigMap 리소스 정의
metadata:
  name: grafana-security-config          # ConfigMap 이름
  namespace: monitoring                  # 네임스페이스
data:
  grafana.ini: |                         # Grafana 구성 파일
    [server]
    root_url = https://grafana.example.com   # 루트 URL 설정 (CSRF 보호에 중요)
    enable_gzip = true                   # 응답 압축 활성화
    # CSRF 및 보안 쿠키 설정
    cookie_secure = true                 # HTTPS에서만 쿠키 전송 (HTTP 세션 하이재킹 방지)
    cookie_samesite = lax                # Cross-Site 요청 제한 (CSRF 보호 향상)
    
    [security]
    # 관리자 계정 비활성화 (SSO만 사용)
    disable_initial_admin_creation = true   # 기본 관리자 계정 비활성화 (SSO로 대체)
    # 보안 설정
    strict_transport_security = true     # HSTS 헤더 활성화 (HTTPS 강제)
    strict_transport_security_max_age_seconds = 63072000  # HSTS 유효 기간 (2년)
    x_content_type_options = true        # MIME 타입 스니핑 방지
    x_xss_protection = true              # XSS 방지 헤더 활성화
    
    # OAuth 인증 설정 - 중앙화된 SSO 구현
    [auth.generic_oauth]
    name = OAuth                         # 인증 제공자 이름
    enabled = true                       # OAuth 인증 활성화
    allow_sign_up = true                 # OAuth 로그인 사용자의 자동 계정 생성 허용
    client_id = $__env{OAUTH_CLIENT_ID}  # 환경 변수에서 클라이언트 ID 로드
    client_secret = $__env{OAUTH_CLIENT_SECRET}  # 환경 변수에서 비밀값 로드
    scopes = openid profile email        # 요청할 OAuth 스코프
    auth_url = https://auth.example.com/authorize  # 인증 URL
    token_url = https://auth.example.com/oauth/token  # 토큰 URL
    api_url = https://auth.example.com/userinfo  # 사용자 정보 API
    # 역할 매핑 - 사용자 그룹에 따른 Grafana 역할 자동 할당
    role_attribute_path = contains(groups[*], 'monitoring-admins') && 'Admin' || contains(groups[*], 'monitoring-editors') && 'Editor' || 'Viewer'
                                         # 그룹 멤버십에 따라 Admin/Editor/Viewer 역할 할당
    
    # 익명 접근 비활성화
    [auth.anonymous]
    enabled = false                      # 익명 접근 완전 차단
---
# Prometheus OAuth2 프록시 설정
apiVersion: apps/v1                      # 쿠버네티스 Apps API 버전
kind: Deployment                         # Deployment 리소스 정의
metadata:
  name: oauth2-proxy                     # OAuth2 프록시 이름
  namespace: monitoring                  # 네임스페이스
spec:
  replicas: 2                            # 고가용성을 위한 복제본 수
  selector:
    matchLabels:
      app: oauth2-proxy                  # 파드 선택기
  template:
    metadata:
      labels:
        app: oauth2-proxy                # 파드 레이블
    spec:
      securityContext:
        runAsNonRoot: true               # 루트가 아닌 사용자로 실행 (보안 강화)
        runAsUser: 1000                  # UID 1000으로 실행
      containers:
      - name: oauth2-proxy               # 컨테이너 이름
        image: quay.io/oauth2-proxy/oauth2-proxy:v7.3.0  # OAuth2 프록시 이미지
        args:
        - --provider=oidc                # OIDC 제공자 사용
        - --oidc-issuer-url=https://auth.example.com  # ID 제공자 URL
        - --email-domain=*               # 모든 이메일 도메인 허용
        - --upstream=http://prometheus-operated:9090  # 백엔드 서비스 (Prometheus)
        - --http-address=0.0.0.0:4180    # 리스닝 주소
        - --cookie-secure=true           # 보안 쿠키만 사용
        - --cookie-samesite=lax          # SameSite 쿠키 정책
        - --session-cookie-minimal=true  # 최소한의 쿠키 정보만 포함
        # 다른 OAuth2 프록시 설정...
        resources:                       # 리소스 제한 (권한 상승 공격 제한)
          limits:
            cpu: 100m                    # CPU 제한
            memory: 128Mi                # 메모리 제한
          requests:
            cpu: 50m                     # CPU 요청
            memory: 64Mi                 # 메모리 요청
        envFrom:
        - secretRef:
            name: oauth2-proxy-secrets   # OAuth2 비밀값 참조
        ports:
        - name: http
          containerPort: 4180            # 컨테이너 포트

✅ 네트워크 보안 강화

모니터링 시스템의 네트워크 통신을 보호하는 방법입니다.

  1. 전송 계층 보안(TLS) 적용
    • 상호 TLS(mTLS) 구성
    • 인증서 관리 자동화
    • 최신 TLS 버전 및 암호화 적용
  2. 네트워크 정책 설정
    • 모니터링 네임스페이스 격리
    • 컴포넌트 간 통신 제한
    • 외부 경로 제한
  3. 프록시 및 API 게이트웨이 활용
    • 역방향 프록시 구현
    • 요청 필터링 및 제한
    • 속도 제한 및 버스트 제어
# 네트워크 보안 강화 설정 예시
# Prometheus와 관련 컴포넌트의 네트워크 통신을 보호하기 위한 설정입니다.

# 1. 네트워크 정책 - 모니터링 네임스페이스 격리
apiVersion: networking.k8s.io/v1          # 쿠버네티스 Networking API 버전
kind: NetworkPolicy                       # NetworkPolicy 리소스 타입
metadata:
  name: monitoring-namespace-isolation    # 정책 이름
  namespace: monitoring                   # 모니터링 네임스페이스에 적용
spec:
  podSelector: {}                         # 네임스페이스의 모든 파드에 적용 (빈 셀렉터)
  policyTypes:
  - Ingress                               # 인바운드 트래픽 규칙
  - Egress                                # 아웃바운드 트래픽 규칙
  ingress:
  # 같은 네임스페이스 내 통신 허용 - 컴포넌트 간 내부 통신용
  - from:
    - podSelector: {}                     # 모니터링 네임스페이스 내 모든 파드 간 통신 허용
  # kube-apiserver로부터의 접근 허용 - 서비스 디스커버리 등에 필요
  - from:
    - ipBlock:
        cidr: 10.0.0.0/16                 # API 서버 CIDR 범위 (환경에 맞게 조정 필요)
  # 인그레스 컨트롤러로부터의 접근 허용 - 외부 액세스 허용
  - from:
    - namespaceSelector:
        matchLabels:
          name: ingress-nginx             # 인그레스 컨트롤러 네임스페이스
  egress:
  # DNS 조회 허용 - 이름 확인에 필요
  - to:
    - namespaceSelector:
        matchLabels:
          name: kube-system               # DNS 서비스가 있는 네임스페이스
    ports:
    - protocol: UDP
      port: 53                            # DNS 포트
  # kube-apiserver 접근 허용 - 서비스 디스커버리 및 API 호출용
  - to:
    - ipBlock:
        cidr: 10.0.0.0/16                 # API 서버 CIDR 범위
  # 모니터링 대상에 대한 접근 허용 - 메트릭 스크래핑용
  - to:
    - namespaceSelector: {}               # 모든 네임스페이스 (스크래핑용)
      podSelector:
        matchLabels:
          prometheus.io/scrape: "true"    # 스크래핑 대상으로 표시된 파드만 접근 허용
---
# 2. Prometheus TLS 설정
apiVersion: monitoring.coreos.com/v1      # Prometheus Operator API 버전
kind: Prometheus                          # Prometheus 커스텀 리소스
metadata:
  name: prometheus                        # Prometheus 인스턴스 이름
  namespace: monitoring                   # 네임스페이스
spec:
  # 기본 설정...
  
  # TLS 설정 - 인증서 시크릿 지정
  secrets:
  - prometheus-tls                        # TLS 인증서 및 키를 포함하는 시크릿
  
  # 웹 TLS 설정 - HTTPS 활성화
  web:
    tlsConfig:
      cert: tls.crt                       # 인증서 파일 이름
      key: tls.key                        # 키 파일 이름
      minVersion: VersionTLS12            # 최소 TLS 버전 (1.2 이상 강제)
                                          # TLS 1.0 및 1.1은 취약하므로 사용하지 않음

✅ 데이터 보안 및 민감 정보 보호

모니터링 시스템에서 수집하고 저장하는 데이터의 보안을 강화하는 방법입니다.

  1. 메트릭 데이터 필터링
    • 개인 식별 정보(PII) 필터링
    • 민감한 레이블 마스킹
    • 재레이블링을 통한 정보 난독화
  2. 저장 데이터 암호화
    • 저장소 수준 암호화
    • 비밀 정보 별도 관리
    • 키 관리 자동화
  3. 알림 보안 강화
    • 알림 채널 암호화
    • 중요 알림 제한적 노출
    • 알림 전달 확인 메커니즘
# 데이터 보안 강화 설정 예시
# 메트릭에서 민감한 정보를 필터링하고 보호하는 설정입니다.

# 1. 메트릭 필터링 및 레이블 난독화
apiVersion: v1                             # 쿠버네티스 API 버전
kind: ConfigMap                            # ConfigMap 리소스 타입
metadata:
  name: prometheus-relabeling-rules        # ConfigMap 이름
  namespace: monitoring                    # 네임스페이스
data:
  relabel-config.yaml: |                   # 재레이블링 설정 파일
    # 글로벌 재레이블링 설정
    global:
      external_labels:
        cluster: 'production'              # 클러스터 식별자 추가 - 데이터 출처 표시
      
    # 메트릭 재레이블링 규칙
    metric_relabel_configs:
      # 패스워드나 토큰이 포함된 레이블 삭제 - 민감한 정보 제거
      - source_labels: [__name__]          # 메트릭 이름 확인
        regex: '.*(password|token|secret|key|credential).*'  # 민감한 키워드가 포함된 메트릭
        action: drop                       # 해당 메트릭 완전히 삭제
        
      # 이메일 주소, IP 등 PII 필터링 - 개인정보 보호
      - source_labels: [email]             # 이메일 주소 레이블
        regex: '(.+)'                      # 모든 값에 매칭
        target_label: email                # 같은 레이블에 적용
        replacement: 'redacted'            # 'redacted'로 값 대체 (실제 이메일 숨김)
        
      - source_labels: [client_ip]         # 클라이언트 IP 레이블
        regex: '(.+)'                      # 모든 값에 매칭
        target_label: client_ip            # 같은 레이블에 적용
        replacement: 'redacted'            # 'redacted'로 값 대체 (IP 주소 숨김)
        
      # 사용자 ID 해싱 (완전 제거 대신) - 추적은 가능하나 직접 식별은 방지
      - source_labels: [user_id]           # 사용자 ID 레이블
        regex: '(.+)'                      # 모든 값에 매칭
        target_label: user_id_hash         # 새 레이블에 해시값 저장
        replacement: '${1}'                # 원본 값을 해시로 대체 (실제로는 해시 함수 필요)
        action: hashmod                    # 해시 모듈로 연산 수행
        modulus: 1000                      # 모듈러 해싱 - 0-999 범위로 값 제한
        
      # 민감한 URL 경로 일반화 - 구체적인 ID나 값 숨김
      - source_labels: [path]              # URL 경로 레이블
        regex: '/api/users/[0-9]+'         # 사용자 ID를 포함하는 경로 (예: /api/users/12345)
        target_label: path                 # 같은 레이블에 적용
        replacement: '/api/users/:id'      # 패턴으로 대체하여 특정 ID 마스킹
---
# 2. AlertManager 웹훅 인증 및 암호화 설정
apiVersion: monitoring.coreos.com/v1       # Prometheus Operator API 버전
kind: AlertmanagerConfig                   # AlertmanagerConfig 커스텀 리소스
metadata:
  name: secure-webhooks                    # 구성 이름
  namespace: monitoring                    # 네임스페이스
spec:
  route:
    receiver: 'secure-webhook'             # 기본 수신자 지정
    group_by: ['alertname', 'severity']    # 알림 그룹화 기준
  receivers:
  - name: 'secure-webhook'                 # 수신자 이름
    webhook_configs:
    - url: 'https://alerts.example.com/webhook'  # 웹훅 엔드포인트 URL
      http_config:
        tls_config:                        # TLS 설정 - 암호화된 통신
          ca_file: '/etc/alertmanager/certs/ca.crt'     # CA 인증서
          cert_file: '/etc/alertmanager/certs/tls.crt'  # 클라이언트 인증서
          key_file: '/etc/alertmanager/certs/tls.key'   # 클라이언트 키
          insecure_skip_verify: false      # 서버 인증서 검증 필수
          server_name: 'alerts.example.com'  # SNI 검증용 서버 이름
        basic_auth:                        # 기본 인증 설정 - 추가 인증 레이어
          username:
            name: alertmanager-webhook-auth  # 사용자명이 들어있는 시크릿
            key: username                  # 시크릿 내 키
          password:
            name: alertmanager-webhook-auth  # 비밀번호가 들어있는 시크릿
            key: password                  # 시크릿 내 키

▶️ 데이터 보안 사례: 한 의료 기관은 환자 관련 메트릭을 수집하는 과정에서 실수로 일부 민감한 환자 식별 정보가 메트릭 레이블에 노출되는 문제를 발견했습니다. 이를 해결하기 위해 모든 수집 대상 애플리케이션에 메트릭 익스포터를 재구성하고, Prometheus의 메트릭 재레이블링 기능을 사용하여 환자 ID를 해시 처리하고, 잠재적으로 민감한 정보가 포함된 모든 레이블에 대해 정규식 기반 필터를 적용했습니다. 또한 데이터 접근 감사 로깅을 활성화하여 누가 어떤 메트릭에 접근했는지 추적하는 시스템을 구축했습니다.


📌 성능 최적화 기법

모니터링 시스템의 성능을 최적화하여 효율성을 높이는 방법을 알아보겠습니다.

 

메트릭 수집 및 저장 최적화 흐름도

✅ 효율적인 메트릭 수집 및 저장

메트릭 수집과 저장 단계에서의 성능 최적화 방법입니다.

 

  1. 스크래핑 최적화
    • 적절한 간격 설정
    • 필터링 및 집계 활용
    • 지능적인 타겟 선택
  2. 저장소 성능 튜닝
    • 블록 크기 최적화
    • 압축 설정 조정
    • 리텐션 정책 개선
  3. 메트릭 카디널리티 관리
    • 고카디널리티 레이블 제한
    • 동적 레이블 정규화
    • 불필요한 시리즈 제거
# 효율적인 메트릭 수집 및 저장 설정 예시
# 성능 최적화를 위한 스크래핑 및 저장소 설정입니다.

# 1. Prometheus 성능 최적화 설정
apiVersion: monitoring.coreos.com/v1      # Prometheus Operator API 버전
kind: Prometheus                          # Prometheus 커스텀 리소스
metadata:
  name: prometheus-optimized              # 최적화된 Prometheus 인스턴스 이름
  namespace: monitoring                   # 네임스페이스
spec:
  replicas: 2                             # 고가용성 및 부하 분산을 위한 복제본 수
                                          # 여러 인스턴스로 쿼리 부하 분산 가능
  
  # 리소스 할당 최적화 - 충분한 자원 확보가 성능의 기본
  resources:
    requests:
      memory: "8Gi"                       # 메모리 요청량 - 충분한 메모리가 성능에 중요
                                          # 시계열 인덱스와 WAL을 위한 공간
      cpu: "2"                            # CPU 요청량 - 동시 쿼리와 스크래핑을 위해 필요
    limits:
      memory: "16Gi"                      # 메모리 상한 - 갑작스런 부하 증가에 대비
      cpu: "4"                            # CPU 상한 - 피크 타임에 활용 가능한 자원
  
  # 스토리지 성능 최적화 - I/O 병목 해소가 중요
  storage:
    volumeClaimTemplate:
      spec:
        storageClassName: fast-ssd        # 고성능 SSD 스토리지 클래스 사용
                                          # HDD 대비 수배~수십배 I/O 성능 향상
        resources:
          requests:
            storage: 500Gi                # 충분한 스토리지 공간 확보
                                          # 공간 부족으로 인한 압축 작업 빈번화 방지
  
  # TSDB 설정 최적화 - 데이터베이스 엔진 튜닝
  tsdb:
    outOfOrderTimeWindow: "10m"           # 순서가 맞지 않는 샘플 허용 윈도우 확장
                                          # 일부 지연된 샘플 수용 가능
    minBlockDuration: "2h"                # 최소 블록 기간 설정 - 너무 작은 블록은 오버헤드 증가
    maxBlockDuration: "24h"               # 최대 블록 기간 설정 - 적절한 컴팩션 빈도 보장
    retention: "15d"                      # 데이터 보존 기간 - 필요한 만큼만 설정
  
  # 추가 최적화 매개변수
  additionalArgs:
    - "--storage.tsdb.wal-compression=true"  # WAL 압축 활성화 (I/O 감소)
                                           # 추가 CPU 사용량과 I/O 절약 사이의 균형
    - "--query.max-samples=50000000"      # 쿼리당 최대 샘플 수 설정
                                          # 리소스 고갈 방지 및 과도한 쿼리 제한
    - "--query.timeout=2m"                # 쿼리 타임아웃 설정
                                          # 실행 시간이 긴 쿼리로 인한 자원 고갈 방지
---
# 2. 스크래핑 최적화 설정
apiVersion: v1                            # 쿠버네티스 API 버전
kind: ConfigMap                           # ConfigMap 리소스 타입
metadata:
  name: prometheus-scrape-config          # ConfigMap 이름
  namespace: monitoring                   # 네임스페이스
data:
  prometheus.yaml: |                      # Prometheus 설정 파일
    global:
      scrape_interval: 30s                # 기본 스크래핑 간격 - 적절한 간격 설정
                                          # 너무 짧으면 부하 증가, 너무 길면 해상도 저하
      evaluation_interval: 30s            # 규칙 평가 간격
      scrape_timeout: 10s                 # 스크래핑 타임아웃 - 지연된 응답 제한
      
    scrape_configs:
      # 중요 시스템 메트릭 - 짧은 간격
      - job_name: 'kubernetes-critical'   # 중요 메트릭용 작업
        scrape_interval: 15s              # 짧은 간격으로 중요 메트릭 수집
                                          # 변화가 빠른 중요 메트릭에 적합
        kubernetes_sd_configs:
          - role: pod                     # 파드 기반 서비스 디스커버리
        relabel_configs:
          - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
            action: keep                  # 스크래핑 주석이 있는 파드만 유지
            regex: true
          - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_priority]
            action: keep                  # 우선순위가 high인 파드만 유지
            regex: high                   # 우선순위 필터링
            
      # 일반 메트릭 - 표준 간격
      - job_name: 'kubernetes-standard'   # 일반 메트릭용 작업
        scrape_interval: 30s              # 표준 간격
                                          # 대부분의 일반 메트릭에 적합한 간격
        kubernetes_sd_configs:
          - role: pod                     # 파드 기반 서비스 디스커버리
        relabel_configs:
          - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
            action: keep                  # 스크래핑 주석이 있는 파드만 유지
            regex: true
          - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_priority]
            action: keep                  # 우선순위가 standard인 파드만 유지
            regex: standard               # 우선순위 필터링
          
      # 저우선순위 메트릭 - 긴 간격
      - job_name: 'kubernetes-lowpriority'  # 저우선순위 메트릭용 작업
        scrape_interval: 120s            # 긴 간격으로 부하 감소
                                         # 천천히 변하는 메트릭이나 덜 중요한 메트릭에 적합
        kubernetes_sd_configs:
          - role: pod                    # 파드 기반 서비스 디스커버리
        relabel_configs:
          - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
            action: keep                 # 스크래핑 주석이 있는 파드만 유지
            regex: true
          - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_priority]
            action: keep                 # 우선순위가 low인 파드만 유지
            regex: low                   # 우선순위 필터링

✅ 효율적인 쿼리 및 알림 처리

쿼리 실행과 알림 처리의 성능을 최적화하는 방법입니다.

 

  1. 쿼리 최적화 기법
    • 효율적인 PromQL 작성
    • 사전 계산된 규칙 활용
    • 쿼리 캐싱 구현
  2. 알림 처리 최적화
    • 알림 그룹화 설정
    • 중복 알림 제거
    • 알림 대기열 관리
  3. 대시보드 성능 향상
    • 패널 수 제한
    • 변수 쿼리 최적화
    • 자동 새로고침 간격 조정
# 효율적인 쿼리 및 알림 처리 설정 예시
# PromQL 쿼리와 알림 처리 최적화를 위한 설정입니다.

# 1. 사전 계산 규칙을 활용한 쿼리 최적화
apiVersion: monitoring.coreos.com/v1      # Prometheus Operator API 버전
kind: PrometheusRule                      # PrometheusRule 커스텀 리소스
metadata:
  name: optimized-recording-rules         # 규칙 이름
  namespace: monitoring                   # 네임스페이스
spec:
  groups:
  # CPU 사용량 사전 집계 규칙 - 자주 사용되는 쿼리 미리 계산
  - name: cpu-aggregation                 # 규칙 그룹 이름
    interval: 1m                          # 1분마다 계산 - 적절한 주기 설정
    rules:
    # 노드별 CPU 사용률 - 기본 메트릭에서 계산
    - record: node:cpu_utilization:avg1m  # 사전 계산된 메트릭 이름
      expr: 1 - avg by (node) (rate(node_cpu_seconds_total{mode="idle"}[1m]))
             # 1분 평균 CPU 사용률 (1 - idle 비율)
             # by (node)로 노드별 집계 수행
    
    # 네임스페이스별 CPU 사용률 - 컨테이너 메트릭 집계
    - record: namespace:cpu_usage:avg1m   # 사전 계산된 메트릭 이름
      expr: sum by (namespace) (rate(container_cpu_usage_seconds_total{container!="POD",container!=""}[1m]))
             # 네임스페이스별 모든 컨테이너 CPU 사용량 합계
             # POD 컨테이너와 빈 컨테이너 제외
    
    # 클러스터 전체 CPU 사용률 - 최상위 집계
    - record: cluster:cpu_utilization:avg1m  # 사전 계산된 메트릭 이름
      expr: 1 - avg(rate(node_cpu_seconds_total{mode="idle"}[1m]))
             # 클러스터 전체 평균 CPU 사용률
             # 모든 노드의 평균값 계산
  
  # 메모리 사용량 사전 집계 규칙
  - name: memory-aggregation              # 규칙 그룹 이름
    interval: 1m                          # 1분마다 계산
    rules:
    # 노드별 메모리 사용률
    - record: node:memory_utilization:avg1m  # 사전 계산된 메트릭 이름
      expr: 1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes
             # 사용 가능한 메모리를 총 메모리로 나누어 사용률 계산
             # 간단한 공식이지만 자주 사용되므로 미리 계산
    
    # 네임스페이스별 메모리 사용량
    - record: namespace:memory_usage:avg1m  # 사전 계산된 메트릭 이름
      expr: sum by (namespace) (container_memory_working_set_bytes{container!="POD",container!=""})
             # 네임스페이스별 컨테이너 메모리 사용량 합계
             # working_set_bytes는 실제 메모리 사용량 측정에 적합
    
    # 컨테이너별 메모리 사용량 (상위 N개) - 대시보드 최적화용
    - record: container:memory_usage_top_n:avg1m  # 사전 계산된 메트릭 이름
      expr: topk(100, sum by (namespace, pod, container) (container_memory_working_set_bytes{container!="POD",container!=""}))
             # 메모리 사용량 상위 100개 컨테이너 선택
             # 과도한 메모리 사용 컨테이너 식별에 유용
             # topk()로 결과 제한하여 처리 부하 감소
---
# 2. 효율적인 알림 매니저 설정
apiVersion: monitoring.coreos.com/v1      # Prometheus Operator API 버전
kind: Alertmanager                        # Alertmanager 커스텀 리소스
metadata:
  name: alertmanager-optimized            # 최적화된 Alertmanager 이름
  namespace: monitoring                   # 네임스페이스
spec:
  replicas: 3                             # 고가용성 및 부하 분산을 위한 복제본 수
  
  # 리소스 최적화
  resources:
    requests:
      memory: "1Gi"                       # 메모리 요청량
      cpu: "500m"                         # CPU 요청량
    limits:
      memory: "2Gi"                       # 메모리 상한
      cpu: "1"                            # CPU 상한
  
  # 알림 라우팅 및 그룹화 설정
  config:
    global:
      resolve_timeout: 5m                 # 알림 해결 타임아웃
      
    # 알림 그룹화 및 라우팅 전략
    route:
      group_by: ['alertname', 'cluster', 'service']  # 그룹화 기준
                                                  # 유사한 알림을 묶어 알림 폭주 방지
      group_wait: 30s                     # 그룹 초기 대기 시간
                                          # 유사한 알림을 모으기 위한 대기 시간
      group_interval: 5m                  # 그룹 갱신 간격
                                          # 동일 그룹의 알림 재전송 간격
      repeat_interval: 4h                 # 반복 알림 간격
                                          # 해결되지 않은 알림의 재알림 간격
      receiver: 'default-receiver'        # 기본 수신자
      
      # 우선순위별 라우팅 - 알림 효율화
      routes:
      # 중요 알림은 즉시 전송
      - match:
          severity: critical              # 심각도가 critical인 알림
        receiver: 'critical-receiver'     # 중요 알림 수신자 (예: 페이징 서비스)
        group_wait: 0s                    # 대기 없이 즉시 알림
        group_interval: 1m                # 1분 간격으로 갱신
        repeat_interval: 30m              # 30분마다 반복 알림
        
      # 일반 알림은 표준 처리
      - match:
          severity: warning               # 심각도가 warning인 알림
        receiver: 'warning-receiver'      # 일반 알림 수신자
        
      # 정보성 알림은 묶음 처리 (노이즈 감소)
      - match:
          severity: info                  # 심각도가 info인 알림
        receiver: 'info-receiver'         # 정보성 알림 수신자
        group_wait: 5m                    # 5분간 알림 모음
        group_interval: 30m               # 30분 간격으로 갱신
        repeat_interval: 12h              # 12시간마다 반복 알림

✅ 확장성 있는 아키텍처 설계

모니터링 시스템의 확장성을 개선하기 위한 아키텍처 접근법입니다.

 

성능 최적화된 Prometheus 샤딩 아키텍쳐 예시

  1. 샤딩 및 연합
    • 기능적 샤딩 구현
    • 계층적 모니터링 구성
    • Prometheus 연합 설정
  2. 분산 저장 및 쿼리
    • 원격 스토리지 통합
    • 쿼리 레이어 분리
    • 장기 저장소 최적화
  3. 자동 확장 메커니즘
    • 수평적 확장 전략
    • 부하 기반 스케일링
    • 리소스 자동 조정
# 확장성 있는 모니터링 아키텍처 설정 예시
# 대규모 클러스터를 위한 분산형 모니터링 아키텍처입니다.

# 1. 기능적으로 샤딩된 Prometheus - 노드 메트릭 전용
apiVersion: monitoring.coreos.com/v1      # Prometheus Operator API 버전
kind: Prometheus                          # Prometheus 커스텀 리소스
metadata:
  name: prometheus-nodes                  # 노드 메트릭 전용 Prometheus
  namespace: monitoring                   # 네임스페이스
spec:
  replicas: 2                             # 복제본 수
  version: v2.35.0                        # Prometheus 버전
  
  # 노드 메트릭에 최적화된 리소스 설정
  resources:
    requests:
      memory: "8Gi"                       # 메모리 요청량
      cpu: "2"                            # CPU 요청량
    limits:
      memory: "12Gi"                      # 메모리 상한
      cpu: "4"                            # CPU 상한
  
  # 노드 메트릭 특화 보존 정책
  retention: "7d"                         # 7일 데이터 보존
  
  # 노드 관련 ServiceMonitor만 선택
  serviceMonitorSelector:
    matchLabels:
      component: node                     # 노드 컴포넌트 메트릭 선택
  
  # 외부 레이블 - 메트릭 출처 식별용
  externalLabels:
    cluster: "production"                 # 클러스터 식별자
    prometheus_type: "nodes"              # Prometheus 인스턴스 유형
    
  # 원격 저장소 통합 - 장기 저장
  remoteWrite:
    - url: "http://thanos-receive.monitoring.svc:9090/api/v1/receive"
      writeRelabelConfigs:                # 필터링 및 처리 규칙
        - sourceLabels: [__name__]
          regex: 'node_.*'                # 노드 접두사 메트릭만 전송
          action: keep                    # 조건에 맞는 메트릭만 유지
---
# 2. 애플리케이션 메트릭 전용 Prometheus
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  name: prometheus-apps                   # 애플리케이션 메트릭 전용 Prometheus
  namespace: monitoring
spec:
  replicas: 2
  version: v2.35.0
  
  # 앱 메트릭에 최적화된 설정
  resources:
    requests:
      memory: "12Gi"                      # 더 많은 메모리 (높은 카디널리티 대비)
      cpu: "4"                            # 더 많은 CPU (복잡한 쿼리 대응)
    limits:
      memory: "20Gi"                      # 메모리 상한
      cpu: "8"                            # CPU 상한
  
  # 앱 메트릭 특화 보존 정책
  retention: "3d"                         # 3일만 보존 (짧은 기간, 원격 저장소로 이전)
  
  # 앱 관련 ServiceMonitor만 선택
  serviceMonitorSelector:
    matchLabels:
      component: application              # 애플리케이션 컴포넌트 메트릭
      
  # 외부 레이블
  externalLabels:
    cluster: "production"                 # 클러스터 식별자
    prometheus_type: "applications"       # Prometheus 유형
    
  # 원격 저장소 통합
  remoteWrite:
    - url: "http://thanos-receive.monitoring.svc:9090/api/v1/receive"
      writeRelabelConfigs:
        - sourceLabels: [__name__]
          regex: '(container_.*|kube_pod_.*|kube_deployment_.*)'  # 앱 관련 메트릭
          action: keep
---
# 3. 상위 레벨 통합 쿼리 레이어 (Thanos Query)
apiVersion: apps/v1                       # 쿠버네티스 Apps API 버전
kind: Deployment                          # Deployment 리소스 타입
metadata:
  name: thanos-query                      # Thanos Query 이름
  namespace: monitoring                   # 네임스페이스
spec:
  replicas: 3                             # 고가용성 및 부하 분산을 위한 복제본 수
  selector:
    matchLabels:
      app: thanos-query                   # 파드 선택기
  template:
    metadata:
      labels:
        app: thanos-query                 # 파드 레이블
    spec:
      containers:
      - name: thanos-query                # 컨테이너 이름
        image: quay.io/thanos/thanos:v0.26.0  # Thanos 이미지
        args:
        - "query"                         # Query 컴포넌트로 실행
        - "--log.level=info"              # 로그 레벨
        - "--query.replica-label=replica"  # 복제본 레이블
        # 모든 Prometheus 인스턴스 및 저장소 연결
        - "--store=dnssrv+_grpc._tcp.thanos-store.monitoring.svc"  # 장기 저장소
        - "--store=prometheus-nodes-0.prometheus-nodes:10901"      # 노드 Prometheus
        - "--store=prometheus-nodes-1.prometheus-nodes:10901"
        - "--store=prometheus-apps-0.prometheus-apps:10901"        # 앱 Prometheus
        - "--store=prometheus-apps-1.prometheus-apps:10901"
        # 쿼리 최적화 설정
        - "--query.max-concurrent=20"     # 병렬 쿼리 수
        - "--query.timeout=2m"            # 쿼리 타임아웃
        - "--query.auto-downsampling"     # 자동 다운샘플링 (대시보드 최적화)
        # 로드 밸런싱 및 부하 분산
        - "--store.sd-dns-interval=1m"    # DNS 기반 서비스 디스커버리 갱신 주기
        - "--query.partial-response"      # 부분 응답 허용 (일부 저장소 실패 시에도 결과 반환)
        ports:
        - name: http                      # HTTP 포트 (UI 및 API)
          containerPort: 10902            # 포트 번호
        - name: grpc                      # gRPC 포트 (내부 통신)
          containerPort: 10901            # 포트 번호
        resources:
          limits:
            cpu: 2                        # CPU 상한
            memory: 8Gi                   # 메모리 상한
          requests:
            cpu: 1                        # CPU 요청량
            memory: 4Gi                   # 메모리 요청량

▶️ 성능 최적화 성공 사례: 한 대형 전자상거래 플랫폼은 블랙 프라이데이 기간에 트래픽이 평소의 10배 이상 증가하는 상황에서 모니터링 시스템 성능 병목을 겪었습니다. 이를 해결하기 위해 1) 메트릭 우선순위에 따른 차등화된 스크래핑 간격 적용, 2) 기능별로 샤딩된 Prometheus 인스턴스(인프라, 애플리케이션, 비즈니스 메트릭 각각 별도), 3) 중요 쿼리에 대한 recording rule 구현, 4) 카디널리티가 높은 레이블(session ID, 상세 URL 경로 등)의 필터링 및 정규화를 적용했습니다. 이러한 최적화 후 피크 시간대에도 모니터링 시스템이 안정적으로 동작했고, Grafana 대시보드 로딩 시간은 20초에서 2초로 단축되었으며, 알림 딜레이도 크게 감소했습니다.

 

 


📌 결론

이 글에서는 모니터링 시스템의 보안과 성능 최적화에 대해 다루었습니다. 다음과 같은 주요 내용을 살펴보았습니다:

  • 보안 위협과 취약점 이해: 모니터링 시스템이 직면할 수 있는 무단 접근, 권한 상승, 데이터 무결성 위협과 이에 대응하기 위한 기본적인 보안 조치를 알아보았습니다.
  • 보안 강화 전략: 강력한 인증 및 권한 제어, 네트워크 보안 강화, 데이터 보안 및 민감 정보 보호를 위한 구체적인 구현 방법과 YAML 설정 예제를 살펴보았습니다.
  • 성능 최적화 기법: 효율적인 메트릭 수집 및 저장, 쿼리 및 알림 처리 최적화, 확장성 있는 아키텍처 설계를 위한 다양한 접근법과 실제 구현 예시를 알아보았습니다.

모니터링 시스템은 클러스터의 건강 상태와 성능을 파악하는 데 필수적인 요소이지만, 그만큼 보안에 취약하고 리소스 집약적일 수 있습니다. 이 글에서 소개한 전략과 최적화 기법을 활용하여 안전하고 효율적인 모니터링 시스템을 구축하시길 바랍니다. 특히 환경의 규모와 특성에 맞게 적절한 보안 수준과 성능 최적화 전략을 선택하여 구현하는 것이 중요합니다. 모니터링 시스템 자체의 모니터링과 지속적인 개선 또한 잊지 말아야 하며, 이를 통해 보안과 성능 모두에서 최적의 상태를 유지할 수 있습니다.

모니터링 시스템의 보안과 성능은 서로 상충하는 요소처럼 보일 수 있지만, 적절한 설계와 최적화를 통해 두 가지 목표를 모두 달성할 수 있습니다. 예를 들어, 메트릭 필터링은 민감한 정보를 보호하는 동시에 카디널리티를 줄여 성능을 향상시킬 수 있습니다. 마찬가지로, 네트워크 정책은 보안을 강화하면서도 필요한 통신 경로만 열어 효율성을 높일 수 있습니다.

실제 운영 환경에서는 이 글에서 소개한 방법들을 기반으로 하되, 자신의 환경에 맞게 점진적으로 적용하고 효과를 측정하며 조정해 나가는 과정이 필요합니다. 보안과 성능 모두 한 번에 완벽하게 구현할 수 있는 것이 아니라, 지속적인 개선을 통해 발전시켜 나가야 하는 영역임을 기억하시기 바랍니다.

 

728x90