Files
opensearch/README.md
2025-09-15 13:35:51 +09:00

515 lines
21 KiB
Markdown

# OpenSearch 3.1 클러스터 구축 가이드 (3-Node)
본 문서는 Ubuntu 24.04 환경에서 3대의 서버를 이용하여 OpenSearch 3.1 클러스터를 구축하고, 최종적으로 로드 밸런서(LB) 중심의 안정적인 프로덕션 아키텍처로 전환하는 전체 과정을 상세히 기술한다.
## 버전 히스토리
* **v1.0:** 개별 노드 직접 접속 방식의 초기 클러스터 구축
* **v2.0:** 로드 밸런서(LB)를 도입하여 고가용성 및 단일 접속점을 확보한 프로덕션 아키텍처로 전환
## 목차
1. [사전 정보](#1-사전-정보)
2. [**v1.0: 초기 클러스터 구축 (LB 미사용)**](#v10-초기-클러스터-구축-lb-미사용)
1. [1단계: 설치](#1단계-설치)
2. [2단계: 사전 준비](#2단계-사전-준비)
3. [3단계: OpenSearch 설정 (`opensearch.yml`)](#3단계-opensearch-설정-opensearchyml)
4. [4단계: JVM 및 시스템 설정](#4단계-jvm-및-시스템-설정)
5. [5단계: 보안 플러그인 설정](#5단계-보안-플러그인-설정)
6. [6단계: 클러스터 시작 및 적용](#6단계-클러스터-시작-및-적용)
7. [7단계: Dashboards 설정](#7단계-dashboards-설정)
8. [8단계: Dashboards 시작 및 확인](#8단계-dashboards-시작-및-확인)
9. [9단계: JWT 인증 테스트](#9단계-jwt-인증-테스트)
3. [**v2.0: LB 중심 아키텍처로 전환**](#v20-lb-중-심-아키텍처로-전환)
1. [10단계: 아키텍처 목표](#10단계-아키텍처-목표)
2. [11단계: LB 준비 및 Nginx 프록시 구축](#11단계-lb-준비-및-nginx-프록시-구축)
3. [12단계: OpenSearch 및 Dashboards 재구성](#12단계-opensearch-및-dashboards-재구성)
4. [13단계: 최종 전환 및 테스트](#13단계-최종-전환-및-테스트)
4. [**부록: 운영 및 관리**](#부록-운영-및-관리)
1. [주요 트러블슈팅 및 교훈](#주요-트러블슈팅-및-교훈)
2. [추가 권장 사항 및 팁](#추가-권장-사항-및-팁)
3. [사용자/역할 추가 (Dashboards UI)](#사용자역할-추가-dashboards-ui)
4. [인증서에서 정확한 DN 추출하기](#인증서에서-정확한-dn-추출하기)
5. [`-nameopt RFC2253` 옵션 상세 설명](#-nameopt-rfc2253-옵션-상세-설명)
---
## 1. 사전 정보
### 서버 사양 (3대 공통)
* **CPU:** 8 vCPU
* **Memory:** 65 GB
* **Disk:** 2 TB SSD
* **OS:** Ubuntu 24.04
* **SSH Port:** 42894
### 노드 정보
| 항목 | Node1 | Node2 | Node3 |
| :--- | :--- | :--- | :--- |
| **호스트네임** | ds-opensearch001 | ds-opensearch002 | ds-opensearch003 |
| **외부 DNS (v1.0)** | ds-osearch001.oneunivrs.com | ds-osearch002.oneunivrs.com | ds-osearch003.oneunivrs.com |
| **내부 DNS** | ds-osnode001.oneunivrs.com | ds-osnode002.oneunivrs.com | ds-osnode003.oneunivrs.com |
| **Private IP** | 10.0.10.8 | 10.0.10.9 | 10.0.10.10 |
### SSL 인증서
* **종류:** 와일드카드 `*.oneunivrs.com`
* **초기 위치:** Node1의 `/data/cert/`
* **파일:** `oneunivrs.pem`, `root.pem`, `oneunivrs_key.pem`
* **DN:** `C=KR, ST=Seoul, O="ONEUNIVERSE Co.,Ltd.", CN=*.oneunivrs.com`
### JWT 인증
* **방식:** 대칭키 (HS256)
* **서명키:** `UGdiOTdLVjFBTWtndTRNRiZmVjdwMDdCRW1lSSUxTnA=`
---
## v1.0: 초기 클러스터 구축 (LB 미사용)
이 버전은 로드 밸런서 없이 각 노드에 직접 접속하는 방식의 기본 클러스터를 구축한다.
### 1단계: 설치
모든 작업은 `root` 계정으로 진행.
**[모든 노드]**
APT 저장소 설정 후 OpenSearch 설치. 초기 admin 비밀번호 지정.
```bash
# APT 저장소 설정 (공식 문서 참조)
# OpenSearch 설치 (3.1.0)
env OPENSEARCH_INITIAL_ADMIN_PASSWORD='DHp5#r#GYQ9d' apt-get install opensearch=3.1.0
# Dashboards도 미리 설치
apt-get install opensearch-dashboards=3.1.0
```
### 2단계: 사전 준비
**[모든 노드]**
#### 2.1. 데이터/로그 디렉토리 생성
```bash
mkdir -p /data/opensearch/{data,logs}
chown -R opensearch:opensearch /data/opensearch
```
#### 2.2. 인증서 복사 및 권한 설정
**[Node1]**
```bash
mkdir -p /etc/opensearch/certs
cp /data/cert/*.pem /etc/opensearch/certs/
# 다른 노드로 전송
scp -P 42894 /etc/opensearch/certs/*.pem root@ds-osnode002.oneunivrs.com:/etc/opensearch/certs/
scp -P 42894 /etc/opensearch/certs/*.pem root@ds-osnode003.oneunivrs.com:/etc/opensearch/certs/
```
**[모든 노드]**
```bash
chown -R opensearch:opensearch /etc/opensearch/certs
chmod 600 /etc/opensearch/certs/oneunivrs_key.pem # 개인키 권한 축소
chmod 644 /etc/opensearch/certs/oneunivrs.pem /etc/opensearch/certs/root.pem
```
### 3단계: OpenSearch 설정 (`opensearch.yml`)
**[모든 노드]**
기존 파일 백업 후, 각 노드에 맞게 `/etc/opensearch/opensearch.yml` 작성.
```yaml
# 클러스터 이름
cluster.name: ds-cluster
# [중요] node.name은 내부 DNS와 일치시킬 것 (클러스터링 실패 방지)
# Node1: node.name: ds-osnode001.oneunivrs.com
# Node2: node.name: ds-osnode002.oneunivrs.com
# Node3: node.name: ds-osnode003.oneunivrs.com
node.name: ds-osnode001.oneunivrs.com # 각 노드에 맞게 수정
# 역할
node.roles: [ cluster_manager, data ]
# 경로
path.data: /data/opensearch/data
path.logs: /data/opensearch/logs
# 메모리 잠금
bootstrap.memory_lock: true
# 네트워크
network.host: 0.0.0.0
http.port: 9200
transport.port: 9300
# 클러스터링
discovery.seed_hosts:
- ds-osnode001.oneunivrs.com
- ds-osnode002.oneunivrs.com
- ds-osnode003.oneunivrs.com
# [중요] 최초 마스터 후보 목록. node.name과 일치해야 함.
cluster.initial_cluster_manager_nodes:
- ds-osnode001.oneunivrs.com
- ds-osnode002.oneunivrs.com
- ds-osnode003.oneunivrs.com
# 보안 플러그인
plugins.security.ssl.transport.enabled: true
plugins.security.ssl.transport.pemcert_filepath: certs/oneunivrs.pem
plugins.security.ssl.transport.pemkey_filepath: certs/oneunivrs_key.pem
plugins.security.ssl.transport.pemtrustedcas_filepath: certs/root.pem
plugins.security.ssl.transport.enforce_hostname_verification: false
plugins.security.ssl.http.enabled: true
plugins.security.ssl.http.pemcert_filepath: certs/oneunivrs.pem
plugins.security.ssl.http.pemkey_filepath: certs/oneunivrs_key.pem
plugins.security.ssl.http.pemtrustedcas_filepath: certs/root.pem
# [주의] DN의 쉼표(,)는 백슬래시 두 개(\\)로 이스케이프
plugins.security.nodes_dn:
- "CN=*.oneunivrs.com,O=ONEUNIVERSE Co.\\,Ltd.,ST=Seoul,C=KR"
plugins.security.authcz.admin_dn:
- "CN=*.oneunivrs.com,O=ONEUNIVERSE Co.\\,Ltd.,ST=Seoul,C=KR"
plugins.security.allow_default_init_securityindex: true
plugins.security.audit.type: internal_opensearch
plugins.security.restapi.roles_enabled: ["all_access", "security_rest_api_access"]
```
### 4단계: JVM 및 시스템 설정
**[모든 노드]**
#### 4.1. JVM 힙 메모리
`/etc/opensearch/jvm.options` 파일 수정. 31GB로 설정.
```bash
sed -i 's/^-Xms1g/#-Xms1g/' /etc/opensearch/jvm.options
sed -i 's/^-Xmx1g/#-Xmx1g/' /etc/opensearch/jvm.options
echo -e "\n-Xms31g\n-Xmx31g" >> /etc/opensearch/jvm.options
```
#### 4.2. Systemd 오버라이드
메모리 잠금과 경로 권한 부여.
```bash
mkdir -p /etc/systemd/system/opensearch.service.d
cat <<EOF > /etc/systemd/system/opensearch.service.d/override.conf
[Service]
LimitMEMLOCK=infinity
ReadWritePaths=/data/opensearch/
EOF
systemctl daemon-reload
systemctl enable opensearch.service
```
### 5단계: 보안 플러그인 설정
**[Node1에서 작업 후 다른 노드로 복사]**
#### 5.1. 인증 방식 설정 (`config.yml`)
`/etc/opensearch/opensearch-security/config.yml` 수정. JWT 우선, Basic 차선.
```yaml
---
_meta:
type: "config"
config_version: 2
config:
dynamic:
http:
anonymous_auth_enabled: false
authc:
# [중요] order: 0(JWT) -> order: 1(Basic)
jwt_auth_domain:
http_enabled: true
order: 0
http_authenticator:
type: jwt
challenge: false
config:
signing_key: "UGdiOTdLVjFBTWtndTRNRiZmVjdwMDdCRW1lSSUxTnA="
jwt_header: "Authorization" # "Bearer " 접두사는 자동 처리됨
subject_key: sub
roles_key: roles
authentication_backend:
type: noop
basic_internal_auth_domain:
http_enabled: true
order: 1
http_authenticator:
type: basic
challenge: true
authentication_backend:
type: internal
```
#### 5.2. 역할 매핑 (`roles_mapping.yml`)
`/etc/opensearch/opensearch-security/roles_mapping.yml` 수정.
```yaml
# ... (기존 내용 유지)
all_access:
reserved: false
users:
- "admin" # 내부 사용자
backend_roles:
- "admin" # JWT를 통해 온 사용자
# ... (기존 내용 유지)
```
#### 5.3. 파일 복사 및 권한 설정
**[Node1]**
```bash
scp -P 42894 /etc/opensearch/opensearch-security/config.yml root@ds-osnode002.oneunivrs.com:/etc/opensearch/opensearch-security/
scp -P 42894 /etc/opensearch/opensearch-security/roles_mapping.yml root@ds-osnode002.oneunivrs.com:/etc/opensearch/opensearch-security/
scp -P 42894 /etc/opensearch/opensearch-security/config.yml root@ds-osnode003.oneunivrs.com:/etc/opensearch/opensearch-security/
scp -P 42894 /etc/opensearch/opensearch-security/roles_mapping.yml root@ds-osnode003.oneunivrs.com:/etc/opensearch/opensearch-security/
```
**[모든 노드]**
```bash
chown -R opensearch:opensearch /etc/opensearch
find /etc/opensearch -type d -exec chmod 750 {} \;
find /etc/opensearch -type f -exec chmod 640 {} \;
chmod 600 /etc/opensearch/certs/oneunivrs_key.pem
chmod -R 600 /etc/opensearch/opensearch-security/*
```
### 6단계: 클러스터 시작 및 적용
#### 6.1. 클러스터 시작
마스터가 아닌 노드부터 순차적으로 시작.
```bash
systemctl start opensearch.service # Node3 -> Node2 -> Node1 순으로 실행
```
#### 6.2. 개인키 변환 (PKCS#8)
`securityadmin.sh`는 PKCS#8 형식을 요구함.
**[Node1]**
```bash
openssl pkcs8 -topk8 -inform PEM -outform PEM -in /etc/opensearch/certs/oneunivrs_key.pem -out /etc/opensearch/certs/oneunivrs_key.p8.pem -nocrypt
chown opensearch:opensearch /etc/opensearch/certs/oneunivrs_key.p8.pem
chmod 600 /etc/opensearch/certs/oneunivrs_key.p8.pem
```
#### 6.3. 보안 설정 적용
**[Node1]**
```bash
# [중요] 3.1 버전은 REST 포트(9200)와 변환된 키(.p8.pem) 사용
/usr/share/opensearch/plugins/opensearch-security/tools/securityadmin.sh \
-cd /etc/opensearch/opensearch-security/ \
-cacert /etc/opensearch/certs/root.pem \
-cert /etc/opensearch/certs/oneunivrs.pem \
-key /etc/opensearch/certs/oneunivrs_key.p8.pem \
-h ds-osnode001.oneunivrs.com \
-p 9200 \
-icl \
-nhnv
```
### 7단계: Dashboards 설정
**[Node1]**
#### 7.1. 대시보드용 인증서 복사
```bash
mkdir -p /etc/opensearch-dashboards/certs
cp /etc/opensearch/certs/*.pem /etc/opensearch-dashboards/certs/
chown -R opensearch-dashboards:opensearch-dashboards /etc/opensearch-dashboards/certs
```
#### 7.2. `opensearch_dashboards.yml` 설정
```yaml
server.port: 5601
server.host: "0.0.0.0"
server.name: "oneunivrs-opensearch-dashboards"
# 고가용성을 위해 클러스터 노드 모두 기재
opensearch.hosts:
- https://ds-osearch001.oneunivrs.com:9200
- https://ds-osearch002.oneunivrs.com:9200
- https://ds-osearch003.oneunivrs.com:9200
# [중요] 2.x 이후 버전의 설정 키 이름
opensearch.requestHeadersWhitelist: [ "securitytenant", "authorization" ]
# 대시보드 HTTPS
server.ssl.enabled: true
server.ssl.certificate: /etc/opensearch-dashboards/certs/oneunivrs.pem
server.ssl.key: /etc/opensearch-dashboards/certs/oneunivrs_key.pem
# [중요] 2.x 이후 버전의 설정 키 이름 (배열)
opensearch.ssl:
verificationMode: full
certificateAuthorities: [ "/etc/opensearch-dashboards/certs/root.pem" ]
# 서비스 계정
opensearch.username: "kibanaserver"
opensearch.password: "kibanaserver"
# 보안 연동
opensearch_security:
multitenancy.enabled: true
auth.anonymous_auth_enabled: false
cookie.password: "강력하고_랜덤한_문자열_사용"
```
### 8단계: Dashboards 시작 및 확인
**[Node1]**
```bash
systemctl start opensearch-dashboards.service
systemctl enable opensearch-dashboards.service
```
브라우저에서 `https://ds-osearch001.oneunivrs.com:5601` 접속. `admin` / `DHp5#r#GYQ9d` 로그인 확인.
### 9단계: JWT 인증 테스트
#### 9.1. 서버에서 직접 토큰 생성
외부 도구의 키 처리 방식 문제로 서버에서 직접 생성하는 것이 가장 확실.
**[Node1]**
```bash
pip install pyjwt
vi create_token.py
```
```python
# create_token.py
import jwt, time, base64
base64_secret = "UGdiOTdLVjFBTWtndTRNRiZmVjdwMDdCRW1lSSUxTnA="
# [핵심] Base64 디코딩
decoded_secret = base64.b64decode(base64_secret)
payload = { "sub": "admin", "roles": ["admin"], "exp": int(time.time()) + 3600 }
token = jwt.encode(payload, decoded_secret, algorithm="HS256")
print(token)
```
```bash
python3 create_token.py # 토큰 생성 후 복사
```
#### 9.2. `curl`로 API 호출
```bash
curl -k -H "Authorization: Bearer <방금_생성한_토큰>" "https://ds-osearch001.oneunivrs.com:9200"
```
성공 응답 확인.
---
## v2.0: LB 중심 아키텍처로 전환
초기 구축된 클러스터를 프로덕션 환경에 적합하도록 로드 밸런서(LB) 중심의 고가용성 아키텍처로 전환한다.
### 10단계: 아키텍처 목표
* **AS-IS:** 클라이언트가 개별 노드(`ds-osearch001` 등)에 직접 접속.
* **TO-BE:** 클라이언트는 LB의 단일 대표 주소(`ds-opensearch.oneunivrs.com`)에만 접속. 노드들은 내부망에 격리되어 보안 강화.
### 11단계: LB 준비 및 Nginx 프록시 구축
LB의 헬스 체크 제약(200 OK만 허용)을 우회하기 위해, 모든 OpenSearch 노드에 헬스 체크 전용 Nginx 프록시를 설치한다.
**[모든 노드 (Node1, Node2, Node3)에서 실행]**
```bash
# Nginx 설치
apt-get update && apt-get install nginx -y
# Nginx용 SSL 디렉토리 생성 및 인증서 복사
mkdir -p /etc/nginx/ssl
cp /etc/opensearch/certs/*.pem /etc/nginx/ssl/
# 기본 설정 비활성화
rm /etc/nginx/sites-enabled/default
# 헬스 체크용 설정 파일 생성
vi /etc/nginx/sites-available/opensearch-healthcheck
```
`opensearch-healthcheck` 파일에 아래 내용을 작성한다.
```nginx
server {
listen 9201 ssl;
# [주의] IPv6 비활성화 환경에서는 아래 라인 주석 처리
# listen [::]:9201 ssl;
# 각 노드의 내부 DNS 또는 IP로 설정
server_name ds-osnode001.oneunivrs.com; # Node2에서는 ds-osnode002...
ssl_certificate /etc/nginx/ssl/oneunivrs.pem;
ssl_certificate_key /etc/nginx/ssl/oneunivrs_key.pem;
location / {
# 헬스 체크 요청에 무조건 200 OK 응답
return 200 'Healthy';
add_header Content-Type text/plain;
add_header Content-Length 7;
}
}
```
```bash
# 설정 활성화 및 재시작
ln -s /etc/nginx/sites-available/opensearch-healthcheck /etc/nginx/sites-enabled/
nginx -t
systemctl restart nginx
systemctl enable nginx
```
### 12단계: OpenSearch 및 Dashboards 재구성
**[로드 밸런서 설정]**
* **대표 DNS:** `ds-opensearch.oneunivrs.com`을 생성하여 LB의 Public IP에 연결.
* **리스너:** `HTTPS:9200` (API용), `HTTPS:5601` (Dashboards용) 생성.
* **SSL 인증서:** `oneunivrs.com` 인증서를 LB에 설치.
* **`opensearch-api` 타겟 그룹:**
* **대상:** `10.0.10.8:9200`, `10.0.10.9:9200`, `10.0.10.10:9200`
* **헬스 체크:** `HTTPS`, Port `9201`, Path `/`, Method `GET`
* **`opensearch-dashboard` 타겟 그룹:**
* **대상:** `10.0.10.8:5601`
* **헬스 체크:** `HTTPS`, Port `9201`, Path `/`, Method `GET` (API와 동일한 프록시 사용)
**[Node1의 Dashboards 설정 변경]**
`/etc/opensearch-dashboards/opensearch_dashboards.yml`을 수정하여 LB를 바라보게 한다.
```yaml
# opensearch.hosts를 새로운 LB 대표 DNS로 변경
opensearch.hosts: ["https://ds-opensearch.oneunivrs.com:9200"]
# [중요] LB <-> Dashboards 간 SNI 문제 해결을 위한 옵션 추가
opensearch.ssl:
alwaysPresentCertificate: true
verificationMode: full
certificateAuthorities: [ "/etc/opensearch-dashboards/certs/root.pem" ]
```
```bash
# Dashboards 서비스 재시작
systemctl restart opensearch-dashboards.service
```
### 13단계: 최종 전환 및 테스트
1. LB 콘솔에서 `opensearch-api``opensearch-dashboard` 타겟 그룹의 상태가 모두 `healthy`로 바뀌는지 확인한다.
2. 모든 클라이언트의 접속 주소를 `https://ds-opensearch.oneunivrs.com`으로 변경한다.
3. API와 Dashboards 접속이 모두 정상적으로 이루어지는지 최종 확인한다.
```bash
curl -k -H "Authorization: Bearer <최종_토큰>" "https://ds-opensearch.oneunivrs.com:9200"
```
4. (선택 사항) 전환이 안정화되면, 개별 노드의 외부 IP를 제거하고 방화벽을 강화하여 보안 수준을 높인다.
---
## 부록: 운영 및 관리
### 주요 트러블슈팅 및 교훈
1. **클러스터 형성 실패 (`cluster-manager not discovered`):** `opensearch.yml`의 `node.name`과 `cluster.initial_cluster_manager_nodes` 목록의 이름이 불일치. 클러스터링 관련 설정의 이름은 정확히 일치해야 함.
2. **`securityadmin.sh` 실행 실패:**
* **원인 1 (`InvalidKeySpecException`):** `securityadmin.sh`는 PKCS#8 형식의 개인키를 필요로 함. `openssl pkcs8` 명령으로 변환하여 해결.
* **원인 2 (포트 오류):** OpenSearch 2.12 이후 `securityadmin.sh`는 REST 포트(9200)를 사용.
3. **Dashboards 시작 실패:** 2.x 버전 이후 변경된 설정 키 이름 문제 (`requestHeadersWhitelist`, `ssl.ca`). 버전업 시 공식 문서의 Breaking Changes를 반드시 확인해야 함.
4. **JWT 인증 실패 (`Unauthorized`):**
* **근본 원인:** `signing_key`를 Base64 문자열 그대로 사용.
* **해결:** `signing_key`를 **Base64 디코딩**한 바이너리 값을 실제 비밀키로 사용하여 토큰을 생성해야 함.
5. **LB 헬스 체크 실패 (`503`, `401`, `405` 등):**
* **원인:** 사용하는 LB가 헬스 체크 성공 기준으로 `200 OK`만 허용하는데, 보안이 활성화된 OpenSearch/Dashboards는 인증되지 않은 요청에 `200 OK`를 반환하지 않음.
* **해결:** 모든 노드에 Nginx를 헬스 체크 전용 프록시로 설치. LB는 Nginx의 `9201` 포트로 헬스 체크를 요청하고, Nginx는 무조건 `200 OK`를 응답하여 문제를 우회함.
### 추가 권장 사항 및 팁
1. **롤링 리스타트 시 샤드 재배치 중단:** `/_cluster/settings` API를 통해 `cluster.routing.rebalance.enable`을 `none`으로 설정하면 재시작 속도를 높일 수 있음.
2. **인덱스 템플릿 및 ILM:** 데이터가 많아지기 전에 Dashboards의 `Index Management` 메뉴에서 인덱스 템플릿과 ILM(수명 주기 관리) 정책을 설정하여 운영을 자동화할 것.
3. **스냅샷 및 복구:** 데이터 유실 방지를 위해 Dashboards의 `Snapshots` 메뉴에서 외부 저장소(S3 등)로의 주기적인 백업을 반드시 설정할 것.
4. **방화벽 설정:** LB 전환 후 노드들의 외부 IP를 제거하고, OS 방화벽(UFW 등)을 사용해 신뢰할 수 있는 내부 IP 대역에서의 접속만 허용하여 보안을 강화할 것.
### 사용자/역할 추가 (Dashboards UI)
`admin` 계정으로 Dashboards에 로그인 후, `Security` 메뉴에서 YAML 파일 수정 없이 직관적으로 사용자, 역할, 역할 매핑을 관리할 수 있다. 일회성 작업은 UI를 사용하는 것이 편리하다.
* **역할 생성:** `Security > Roles > Create role`
* **사용자 생성:** `Security > Internal Users > Create internal user`
* **역할 매핑:** `Security > Roles > (역할 선택) > Mapped users > Manage mapping`
### 인증서에서 정확한 DN 추출하기
`opensearch.yml`의 `nodes_dn`, `admin_dn` 설정 시, `openssl` 명령어로 정확한 DN을 추출하여 사용하면 실수를 방지할 수 있다.
```bash
# [권장] RFC2253 형식으로 출력
openssl x509 -in /data/cert/oneunivrs.pem -noout -subject -nameopt RFC2253
```
**출력 예시:** `CN=*.oneunivrs.com,O=ONEUNIVERSE Co.\,Ltd.,ST=Seoul,C=KR`
**`opensearch.yml` 적용 시:** YAML 문자열 내에서 백슬래시(`\`)는 이스케이프해야 하므로 `\\`로 변경해야 한다.
`"CN=*.oneunivrs.com,O=ONEUNIVERSE Co.\\,Ltd.,ST=Seoul,C=KR"`
### `-nameopt RFC2253` 옵션 상세 설명
이 옵션은 기계가 파싱하기 좋은 표준 형식으로 DN을 출력한다.
* `subject=` 같은 불필요한 접두사가 없다.
* 쉼표(`,`)로만 구분되며 불필요한 공백이 없다.
* **가장 중요:** DN 값 자체에 포함된 특수 문자(예: `Co.,Ltd.`의 쉼표)를 백슬래시(`\`)로 자동으로 이스케이프 처리해준다.
* OpenSearch 보안 플러그인은 이 형식을 가장 안정적으로 인식하므로, DN 설정 시 반드시 사용하는 것이 좋다.