본문으로 건너뛰기

OpenSearch 인증

OpenSearch coordinator 가 Security 플러그인으로 인증을 강제. 사용자는 Keycloak OIDC 로, Fluent Bit / 자동화 도구는 internal user (basic) 로 접근.

개요

활성화 구성

1. Security 플러그인

infra/opensearch/deployment.yaml 의 env:

- name: DISABLE_SECURITY_PLUGIN
value: "false"
- name: OPENSEARCH_INITIAL_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: opensearch-admin
key: password
# 외 plugins.security.* 환경변수 (TLS 경로, admin DN 등) 다수

2. TLS

인증서발급자용도
opensearch-transport-tlsgend-ca-issuer (cert-manager Issuer)transport 9300 mTLS, single-node 노드 cert
opensearch-rest-tlsgend-ca-issuerREST 9200 server cert (Pod 내부)
opensearch-public-tlsletsencrypt-prod (cert-manager)Ingress 외부 노출 cert (opensearch.gend.genon.ai)

3. Security config (8 파일)

infra/opensearch/security-config.yaml ConfigMap:

파일역할
config.yml인증 백엔드 (basic + OIDC) 정의
internal_users.ymladmin / gend_fluent_bit (password hash)
roles.ymlgend_admin / gend_analyst / gend_auditor / gend_log_writer
roles_mapping.ymlKeycloak realm role → OpenSearch role
audit.ymlOpenSearch 자체 감사 (writer IP, action)
nodes_dn.ymltransport mTLS 허용 DN
action_groups.yml, tenants.yml, whitelist.yml기본값

4. role 매트릭스

Keycloak realm roleOpenSearch role인덱스권한DLS
admingend_admingend-audit*, .opendistro_security, .kibana*full없음
analystgend_analystgend-audit*read, searchevent.user.security_level != "TOP_SECRET"
viewergend_auditorgend-audit*read, searchTOP_SECRET 제외
(svc account)gend_log_writergend-audit*write only없음

Keycloak 설정

OpenSearch 는 기존 gend-ui client 의 ID token 을 그대로 사용 (별도 client 신설 불필요).

OIDC discovery URL: https://gend.genon.ai/auth/realms/gend/.well-known/openid-configuration

토큰 수동 발급 + 검증:

TOKEN=$(curl -s -X POST 'https://gend.genon.ai/auth/realms/gend/protocol/openid-connect/token' \
-d 'grant_type=password&client_id=gend-ui&username=analyst&password=<pw>&scope=openid' \
| jq -r .access_token)

curl -k -H "Authorization: Bearer $TOKEN" https://opensearch.gend.genon.ai/_cat/indices
# → gend-audit-* 만 표시 (analyst 권한)

admin 비밀번호 회전

# 1) 새 비밀번호 생성 + SealedSecret 재봉인
NEW_PW=$(openssl rand -base64 24 | tr -d '=' | head -c 32)
kubectl create secret generic opensearch-admin \
--from-literal=password="$NEW_PW" \
-n gend --dry-run=client -o yaml \
| kubeseal -o yaml > infra/sealed-secrets/sealed-secrets/opensearch-admin.yaml

# 2) PR → ArgoCD 가 SealedSecret 갱신
# 3) ConfigMap의 internal_users 의 password hash 도 갱신해야 OIDC 검증 통과
# → securityadmin Job 이 자동 처리 (env 의 새 password 로 hash 재생성 + sed 치환)
# 4) Job 재실행 (ConfigMap annotation 변경 또는 수동 trigger)
kubectl --context aks-genos-prod delete job opensearch-securityadmin -n gend
argocd app sync gend-opensearch

Fluent Bit 인증

Fluent Bit DaemonSet 의 4 OUTPUT 블록이 ${OPENSEARCH_FB_USER} / ${OPENSEARCH_FB_PASSWORD} 환경변수를 SealedSecret opensearch-fluent-bit-cred 에서 받는다. 패스워드 회전은 admin 회전 절차와 동일 (SealedSecret 재봉인 → securityadmin Job 재실행).

트러블슈팅

증상원인처치
401 Unauthorized 외부 opensearch.gend.genon.aiBearer 미첨부 또는 만료Keycloak 로그인 후 새 토큰 획득
Fluent Bit 로그 [error] [output:opensearch] HTTP status=401opensearch-fluent-bit-cred Secret 미적용 또는 password hash 불일치SealedSecret 재배포 + securityadmin Job 재실행
OpenSearch Pod 부팅 실패 OPENSEARCH_INITIAL_ADMIN_PASSWORD must be setopensearch-admin SealedSecret 미적용kubectl get secret opensearch-admin -n gend → 없으면 SealedSecret 적용 후 재기동
securityadmin Job 실패transport cert 만료 또는 gend-ca-issuer 문제kubectl describe certificate opensearch-transport -n gend 확인
securityadmin Job 실패 "..." is not an admin user (#899)admin_dn / nodes_dn DN 순서 불일치 — cert subject 와 정규화 순서가 다름아래 boxed warning 참조
OIDC 토큰 검증 실패 unable to fetch JWKissuer URL 접근 불가OpenSearch Pod 의 NetworkPolicy + DNS 점검
Grafana datasource connection refusedNodePort 30560 으로 설정된 채 NodePort 제거됨https://opensearch.gend.genon.ai 또는 https://opensearch.gend.svc.cluster.local:9200 으로 datasource 변경
admin_dn / nodes_dn 은 RFC 2253 정규화 순서 (#899)

OpenSearch security plugin 은 transport cert subject 를 RFC 2253 정규화 순서 (O=...,OU=...,CN=...) 로 추출하여 plugins.security.authcz.admin_dnnodes_dn 과 비교합니다. openssl x509 -subject 가 출력하는 슬래시 표기 (/CN=.../OU=.../O=...) 는 역순 이므로 cert subject 를 그대로 옮겨 적으면 securityadmin.sh 가 admin 으로 인식하지 못하고 다음 에러로 실패합니다:

Connected as "O=gend,OU=opensearch,CN=opensearch-node-1"
ERR: "O=gend,OU=opensearch,CN=opensearch-node-1" is not an admin user

internal_users.yml 의 admin password hash 가 placeholder 상태로 남아 admin basic auth 401 → /admin/audit 502.

infra/opensearch/deployment.yamlplugins.security.authcz.admin_dn.0infra/opensearch/security-config.yamlnodes_dn 둘 다 RFC 2253 순서로 작성합니다:

- name: plugins.security.authcz.admin_dn.0
value: "O=gend,OU=opensearch,CN=opensearch-node-1" # ✅ RFC 2253
# value: "CN=opensearch-node-1,OU=opensearch,O=gend" # ❌ cert /CN/OU/O slash 표기 직역 — 실패

진단: securityadmin.sh 가 출력하는 Make sure opensearch.yml ... admin_dn: - "..." 메시지를 그대로 admin_dn 값으로 사용하면 됩니다. cert 재발급 불필요.

verify 시에는 _cat/indices 사용 금지 — admin backend_role 의 기본 권한 부족으로 403 false-positive 가 발생. _cluster/health (200 기대) 또는 gend-api 가 실제 호출하는 gend-audit-*/_search 로 검증합니다.

로그 조회

다중 레플리카 환경에서는 레이블 셀렉터 사용. 컨텍스트/네임스페이스 플레이스홀더는 환경별로 치환.

# OpenSearch 측
kubectl --context <CONTEXT> logs -n <NAMESPACE> -l app=opensearch --tail=200 \
| grep -iE "Authentication|Unauthorized|ssl|jwt|oidc"

# Fluent Bit 측
kubectl --context <CONTEXT> logs -n <NAMESPACE> -l app.kubernetes.io/name=fluent-bit --tail=200 \
| grep -iE "401|auth|opensearch"

변경 이력

  • 도입: #514
  • 운영 가이드 문서 추가: 본 PR