diff --git a/incus-crowdsec-architecture.md b/incus-crowdsec-architecture.md index a1514be..25d167e 100644 --- a/incus-crowdsec-architecture.md +++ b/incus-crowdsec-architecture.md @@ -152,6 +152,40 @@ labels: type: nginx ``` +**Acquisition 디렉토리 구조화** (권장): +```bash +# /etc/crowdsec/acquis.d/ 디렉토리에 서비스별 파일 분리 +/etc/crowdsec/acquis.d/ +├── nginx.yaml # Nginx 로그 +├── apache.yaml # Apache 로그 (필요시) +├── sshd.yaml # SSH 로그 +└── traefik.yaml # Traefik 로그 (필요시) +``` + +**nginx.yaml 예시**: +```yaml +filenames: + - /var/log/nginx/access.log + - /var/log/nginx/error.log +labels: + type: nginx +--- +# JSON 형식 로그 (별도 처리) +filenames: + - /var/log/nginx/json_access.log +labels: + type: nginx + format: json +``` + +**sshd.yaml 예시**: +```yaml +filenames: + - /var/log/auth.log +labels: + type: syslog +``` + ### Layer 2: OpenAppSec ML WAF **Container**: `openappsec` @@ -206,12 +240,77 @@ nginx-logs: /var/log/nginx ### Security Configuration -#### CrowdSec Bouncer +#### CrowdSec Bouncer (수동 등록) ```yaml API_URL: http://10.90.135.49:8080 API_KEY: s0ENc/6Tw+6m6tr0Qkjt/WAYU1QlC5/MzH7SQOCJX50 ``` +#### Bouncer 자동 등록 (권장) + +> 컨테이너 시작 시 환경변수로 Bouncer 자동 등록. 수동 `cscli bouncers add` 불필요. + +**환경변수 방식**: +```bash +# CrowdSec 컨테이너 시작 시 Bouncer 자동 등록 +incus launch docker.io/crowdsecurity/crowdsec crowdsec \ + --config environment.BOUNCER_KEY_openresty=my-secure-bouncer-key-here \ + --config environment.BOUNCER_KEY_firewall=another-bouncer-key-here +``` + +**Docker Compose 예시**: +```yaml +services: + crowdsec: + image: crowdsecurity/crowdsec:latest + environment: + # Bouncer 자동 등록 (BOUNCER_KEY_=) + - BOUNCER_KEY_openresty=${OPENRESTY_BOUNCER_KEY} + - BOUNCER_KEY_firewall=${FIREWALL_BOUNCER_KEY} + # 컬렉션 자동 설치 + - COLLECTIONS=crowdsecurity/nginx crowdsecurity/http-cve + volumes: + - crowdsec-data:/var/lib/crowdsec/data + - crowdsec-config:/etc/crowdsec + - /var/log/nginx:/var/log/nginx:ro + restart: unless-stopped + + openresty: + image: openresty/openresty:latest + environment: + - CROWDSEC_API_URL=http://crowdsec:8080 + - CROWDSEC_API_KEY=${OPENRESTY_BOUNCER_KEY} + depends_on: + - crowdsec +``` + +**Docker Secret 방식 (더 안전)**: +```yaml +services: + crowdsec: + image: crowdsecurity/crowdsec:latest + secrets: + - bouncer_key_openresty + - bouncer_key_firewall + # Secret 파일은 /run/secrets/bouncer_key_ 으로 마운트됨 + +secrets: + bouncer_key_openresty: + file: ./secrets/openresty_bouncer_key + bouncer_key_firewall: + file: ./secrets/firewall_bouncer_key +``` + +```bash +# Secret 파일 생성 +mkdir -p secrets +openssl rand -base64 32 > secrets/openresty_bouncer_key +openssl rand -base64 32 > secrets/firewall_bouncer_key +chmod 600 secrets/* +``` + +> **주의**: 환경변수/Secret 방식은 초기 배포 시에만 동작. 기존 Bouncer 업데이트는 `cscli` 사용. + #### OpenResty Configuration ```nginx upstream openappsec_backend { diff --git a/incus-meilisearch-manual.md b/incus-meilisearch-manual.md index b64b366..9426010 100644 --- a/incus-meilisearch-manual.md +++ b/incus-meilisearch-manual.md @@ -295,13 +295,198 @@ echo "Access URL: http://localhost:7700" --- +## 8. 프로덕션 보안 설정 + +### Master Key 요구사항 + +> Master Key는 최소 16바이트(128비트) 이상 권장. 짧은 키는 보안 취약점. + +```bash +# 안전한 Master Key 생성 (32바이트) +openssl rand -base64 32 + +# 또는 hex 형식 (64자) +openssl rand -hex 32 +``` + +### 프로덕션 설정 파일 + +`/etc/meilisearch/config.toml` 또는 환경변수로 설정: + +```toml +# 프로덕션 모드 (필수) +env = "production" + +# 강력한 Master Key (필수, 최소 16자 이상) +master_key = "your-secure-master-key-here" + +# 데이터 경로 +db_path = "/var/lib/meilisearch/data" +dump_dir = "/var/lib/meilisearch/dumps" +snapshot_dir = "/var/lib/meilisearch/snapshots" + +# 스냅샷 자동 생성 (백업용) +schedule_snapshot = true +snapshot_interval_sec = 86400 # 24시간마다 + +# 로깅 +log_level = "INFO" + +# 성능 설정 +max_indexing_memory = "2 GiB" +max_indexing_threads = 4 +``` + +### Incus 환경변수로 프로덕션 설정 + +```bash +incus config set meilisearch-prod \ + environment.MEILI_ENV=production \ + environment.MEILI_MASTER_KEY="$(openssl rand -base64 32)" \ + environment.MEILI_DB_PATH=/data.ms \ + environment.MEILI_DUMP_DIR=/data.ms/dumps \ + environment.MEILI_SNAPSHOT_DIR=/data.ms/snapshots \ + environment.MEILI_SCHEDULE_SNAPSHOT=true \ + environment.MEILI_SNAPSHOT_INTERVAL_SEC=86400 \ + environment.MEILI_LOG_LEVEL=INFO \ + environment.MEILI_MAX_INDEXING_MEMORY="2 GiB" +``` + +--- + +## 9. API 키 관리 + +> Master Key는 절대 클라이언트에 노출하지 말 것. Admin/Search 키 분리 사용 필수. + +### 키 유형 + +| 키 유형 | 권한 | 용도 | +|---------|------|------| +| **Master Key** | 전체 권한 | 서버 관리자만 사용, 절대 노출 금지 | +| **Admin Key** | 인덱스 관리 | 백엔드 서버에서 데이터 인덱싱 | +| **Search Key** | 검색만 | 프론트엔드/클라이언트 검색 | + +### 기본 API 키 조회 + +```bash +# Master Key로 API 키 목록 조회 +curl -X GET 'http://localhost:7700/keys' \ + -H 'Authorization: Bearer YOUR_MASTER_KEY' +``` + +### 응답 예시 + +```json +{ + "results": [ + { + "name": "Default Search API Key", + "key": "d0552b...", + "actions": ["search"], + "indexes": ["*"], + "expiresAt": null + }, + { + "name": "Default Admin API Key", + "key": "380689...", + "actions": ["*"], + "indexes": ["*"], + "expiresAt": null + } + ] +} +``` + +### 커스텀 API 키 생성 + +```bash +# 특정 인덱스만 검색 가능한 키 생성 +curl -X POST 'http://localhost:7700/keys' \ + -H 'Authorization: Bearer YOUR_MASTER_KEY' \ + -H 'Content-Type: application/json' \ + --data-binary '{ + "name": "Products Search Key", + "description": "Search products index only", + "actions": ["search"], + "indexes": ["products"], + "expiresAt": "2026-12-31T23:59:59Z" + }' +``` + +### 클라이언트 사용 예시 + +```javascript +// 프론트엔드: Search Key만 사용 (노출 OK) +const client = new MeiliSearch({ + host: 'https://search.example.com', + apiKey: 'search-only-key-here' // Search Key +}); + +// 검색만 가능 +const results = await client.index('products').search('query'); +``` + +```python +# 백엔드: Admin Key 사용 (환경변수로 관리) +import os +from meilisearch import Client + +client = Client( + 'http://localhost:7700', + os.environ['MEILI_ADMIN_KEY'] # Admin Key +) + +# 인덱싱 가능 +client.index('products').add_documents(documents) +``` + +--- + +## 10. 백업 및 복구 + +### 스냅샷 (자동 백업) + +```bash +# 스냅샷 수동 생성 +curl -X POST 'http://localhost:7700/snapshots' \ + -H 'Authorization: Bearer YOUR_MASTER_KEY' + +# 스냅샷 파일 위치 +ls /var/lib/meilisearch/snapshots/ +``` + +### 덤프 (이식 가능한 백업) + +```bash +# 덤프 생성 (JSON 형식, 버전 간 호환) +curl -X POST 'http://localhost:7700/dumps' \ + -H 'Authorization: Bearer YOUR_MASTER_KEY' + +# 덤프 상태 확인 +curl -X GET 'http://localhost:7700/tasks?types=dumpCreation' \ + -H 'Authorization: Bearer YOUR_MASTER_KEY' +``` + +### 덤프에서 복구 + +```bash +# 새 인스턴스에서 덤프 복구 +incus launch docker.io/getmeili/meilisearch meilisearch-restore \ + --config environment.MEILI_MASTER_KEY=your-key \ + --config environment.MEILI_IMPORT_DUMP=/dumps/20260116-123456.dump +``` + +--- + ## 참고 사항 - Meilisearch 기본 포트: 7700 -- 프로덕션 환경에서는 반드시 `MEILI_MASTER_KEY` 설정 +- **프로덕션 모드**: `MEILI_ENV=production` 필수 (개발 모드는 Master Key 없이 실행됨) +- **Master Key**: 최소 16바이트 이상, 32바이트 권장 +- **API 키 분리**: Master Key 노출 금지, Admin/Search 키 분리 사용 - 데이터 영속성을 위해 볼륨 마운트 권장 - 리소스 제한 설정으로 시스템 안정성 확보 -- 정기적인 백업 필요 (데이터 디렉토리 백업) +- **백업 전략**: 스냅샷(빠른 복구) + 덤프(버전 간 호환) 병행 ---