본문으로 건너뛰기
8.4 REST API 보안

8.4 REST API 보안

REST API는 클러스터 상태를 바꾸는 통로다. 8.3에서 본 대로 HTTP 요청 하나로 switchover를 트리거하고 dynamic configuration을 덮어쓸 수 있으므로, 이 인터페이스를 보호하지 않은 클러스터는 네트워크에 닿는 누구에게나 조작 권한을 내준 것과 같다. Patroni는 Basic auth, TLS, 클라이언트 인증서 검증, 호스트 allowlist 네 겹의 방어 수단을 제공하며, 전부 patroni.ymlrestapi 섹션에서 설정한다.

safe와 unsafe

보안 설정을 이해하려면 먼저 공식 문서의 엔드포인트 분류를 알아야 한다. security 문서는 unsafe 엔드포인트를 “PUT, POST, PATCH, DELETE 요청, 노드의 상태를 바꾸는” 것으로 정의한다. 반대로 GET 계열, 즉 health check와 조회 엔드포인트는 safe다.

이 구분이 중요한 이유는 보호 수단마다 적용 범위가 다르기 때문이다. Basic auth와 allowlist는 unsafe만 보호하고, safe 엔드포인트는 기본 구성에서 항상 익명으로 열려 있다.

Basic auth

restapi.authentication에 자격증명을 지정하면 unsafe 엔드포인트 호출에 Basic-auth 인증이 요구된다.

restapi:
  authentication:
    username: patroni
    password: strong-password
curl -s -XPOST -u patroni:strong-password http://127.0.0.1:8008/reload
Basic auth는 자격증명을 평문에 가까운 인코딩으로 전송한다. TLS 없이 Basic auth만 켜면 네트워크 구간에서 비밀번호가 그대로 노출되므로, 인증을 쓴다면 아래 TLS와 함께 구성한다.

TLS

restapi.certfile에 PEM 형식 서버 인증서를 지정하면 REST API가 HTTPS로 동작한다. certfile을 지정하지 않거나 빈 값으로 두면 SSL 없이, 즉 평문 HTTP로 동작한다.

역할
certfilePEM 서버 인증서. 미지정이면 SSL 없이 동작
keyfilePEM 비밀키 파일
keyfile_passwordkeyfile 복호화 비밀번호
cafile클라이언트 인증서 검증에 쓸 신뢰 CA 번들

cafile은 서버가 자신을 증명하는 용도가 아니라, 바로 아래에서 다루는 verify_client 클라이언트 인증서 검증에 쓰인다.

클라이언트 인증서 검증: verify_client

restapi.verify_client는 서버가 클라이언트에게 인증서를 요구할지 정한다. 세 값의 차이는 요구 범위다.

동작
none (기본)클라이언트 인증서를 검사하지 않음
optionalunsafe 엔드포인트 호출에만 클라이언트 인증서 요구
required모든 REST API 호출에 클라이언트 인증서 요구

optional은 이름과 달리 느슨한 선택 사항이 아니다. 상태를 바꾸는 요청에는 인증서를 강제하되, 로드밸런서의 health check 같은 GET 요청은 인증서 없이 통과시키는 절충점이다. required로 올리면 safe 엔드포인트까지 보호되는 대신, health check를 보내는 로드밸런서와 모니터링 수집기까지 전부 클라이언트 인증서를 갖추어야 한다.

allowlist: 호스트 기반 제한

restapi.allowlist는 unsafe 엔드포인트 호출을 허용할 호스트 집합이다. 원소는 호스트명, IP 주소, CIDR 표기 네트워크 주소로 쓴다. 지정하지 않으면 기본은 전체 허용이다.

restapi:
  allowlist:
    - 10.0.0.0/24
    - admin-host.internal
  allowlist_include_members: true

allowlist_include_members: true는 DCS에 등록된 다른 클러스터 멤버로부터의 unsafe 호출을 허용한다. 이때 허용 주소는 각 멤버의 api_url에서 가져온다.

공식 문서는 allowlist_include_members를 쓸 때 OS가 outgoing 연결에 다른 IP를 쓸 가능성을 경고한다. 멤버의 api_url은 수신 주소 기준이므로, NIC가 여러 개인 노드에서 나가는 연결이 다른 인터페이스 IP를 쓰면 allowlist 검사에 걸린다. 이런 환경에서는 멤버들의 실제 출발지 대역을 allowlist에 명시적으로 추가한다.

safe 엔드포인트는 무엇으로 보호하는가

Basic auth도 allowlist도 unsafe 전용이다. 그러면 /cluster/config 같은 조회 엔드포인트가 노출하는 토폴로지, 설정 정보는 무엇으로 가리는가. security 문서의 답은 단호하다. “There is no way to protect the safe endpoints without enabling TLS.” TLS를 켜고 verify_client: required로 모든 호출에 클라이언트 인증서를 요구하는 조합이 유일한 수단이다.

    flowchart TD
  Q1{"보호 대상이<br/>unsafe 뿐인가?"}
  Q1 -->|예| A1["Basic auth + allowlist<br/>또는 verify_client: optional"]
  Q1 -->|"아니오<br/>(safe 포함)"| A2["TLS +<br/>verify_client: required"]
  A1 --> N1["health check 는<br/>익명 허용 유지"]
  A2 --> N2["로드밸런서에도<br/>클라이언트 인증서 필요"]
  

required를 선택하면 health check 소비자 전원이 mTLS 클라이언트가 되어야 하므로, 실제 선택은 조회 정보의 민감도와 운영 부담 사이의 판단이 된다.

server_tokens

restapi.server_tokens는 응답의 Server HTTP 헤더에 얼마나 상세한 버전 정보를 실을지 정한다. Original(기본), Minimal, ProductOnly 세 값이 있으며, 외부에 버전 정보를 덜 드러내고 싶으면 Minimal이나 ProductOnly로 줄인다.

클라이언트 쪽: ctl 섹션

서버를 잠갔으면 patronictl도 그에 맞는 클라이언트 설정이 필요하다. patroni.ymlctl 섹션이 그 자리다.

역할
authentication.username / password보호된 REST API 접근용 Basic-auth. 미지정 시 restapi.authentication 값을 fallback으로 사용
insecure서버 SSL 인증서 검증 생략
cacert서버 인증서 검증용 CA 번들 파일 또는 디렉토리
certfile / keyfile / keyfile_password클라이언트 인증서(mTLS)용

insecure: truepatronictl -k와 같은 효과로, 자체 서명 인증서 환경에서 검증을 건너뛰게 한다. 검증을 끄는 대신 내부 CA 인증서를 cacert로 배포하는 편이 낫다.

권장 조합 예시

Basic auth, TLS, 멤버 간 allowlist를 함께 켠 구성이다. unsafe는 인증과 출발지 제한으로 이중 보호되고, health check는 익명 HTTPS로 열려 있다.

restapi:
  listen: 0.0.0.0:8008
  connect_address: 10.0.0.11:8008
  authentication:
    username: patroni
    password: strong-password
  certfile: /etc/patroni/tls/server.crt
  keyfile: /etc/patroni/tls/server.key
  allowlist:
    - 10.0.0.0/24
  allowlist_include_members: true
  server_tokens: Minimal

ctl:
  cacert: /etc/patroni/tls/ca.crt

조회 정보까지 가려야 하는 환경이라면 여기에 cafileverify_client: required, 그리고 ctl.certfile/ctl.keyfile을 더해 mTLS로 올린다.

정리

  • 엔드포인트는 safe(GET)와 unsafe(PUT/POST/PATCH/DELETE)로 나뉘고, Basic auth와 allowlist는 unsafe만 보호한다.
  • TLS는 certfile 지정으로 켜진다. 미지정이면 평문 HTTP이므로 Basic auth 자격증명이 노출된다.
  • verify_clientoptional이 unsafe만, required가 모든 호출에 클라이언트 인증서를 요구한다. safe 엔드포인트 보호는 TLS와 required의 조합뿐이다.
  • patronictl 쪽은 ctl 섹션에서 cacert, certfile, authentication을 맞춰 준다.