본문 바로가기
WIKI 기술 지식 베이스

인증서(Certificates)

원문 보기 위키 갱신

CloudNativePG는 TLS 인증서를 네이티브로 지원하도록 설계됐어요. 오퍼레이터가 자동으로 인증서를 관리하는 방식과, cert-manager 같은 별도 컴포넌트로 인증서를 직접 제공하는 방식을 나눠서 설명할게요.

출처: 문서

본문

CloudNativePG는 TLS 인증서를 네이티브로 지원하도록 설계됐어요. 클러스터를 설정하려면 오퍼레이터가 필요로 하는 것:

  • 서버 인증 기관(CA) 인증서
  • 서버 CA가 서명한 서버 TLS 인증서
  • 클라이언트 CA 인증서
  • 클라이언트 CA가 생성한 스트리밍 복제(streaming replication) 클라이언트 인증서

:::note 클러스터에서 사용하는 모든 시크릿과 그 만료 날짜는 클러스터의 status에서 찾을 수 있어요. :::

CloudNativePG는 TLS 인증서에 관해 매우 유연해요. 주로 두 가지 모드로 동작해요:

  1. 오퍼레이터 관리(Operator managed) – 인증서가 완전 자동화된 방식으로 오퍼레이터 내부에서 관리되고, CloudNativePG가 만든 CA로 서명돼요.
  2. 사용자 제공(User provided) – 인증서가 오퍼레이터 외부에서 생성되고 시크릿으로 클러스터 정의에 가져와져요. CloudNativePG는 cert-manager와 통합돼요. (Cert-manager 예시 참고)

인증서의 일부만 CNPG 외부에서 생성하는 하이브리드 접근 방식도 선택할 수 있어요.

:::note 오퍼레이터와 인스턴스는 DNS 이름을 무시하고 CA에 대해서만 서버 인증서를 검증해요. 이는 클러스터 내 통신에 사용되는 <cluster>-rw 서비스에 대해 사용자 제공 인증서에 DNS 이름이 포함되지 않는 것이 일반적이기 때문이에요. :::

:::note 위에 나열된 CA 관리 인증서 외에도 오퍼레이터는 인스턴스 매니저의 상태 포트에 인증하기 위해 메모리에서 생성한 자체 서명 클라이언트 인증서도 사용해요. 이 인증서는 클라이언트 CA가 서명한 것이 아니에요. 인스턴스 매니저는 공개 키 지문을 고정(pinning)해 이를 신뢰해요. Operator-to-instance authentication을 참고하세요. :::

오퍼레이터 관리 모드(Operator-Managed Mode)

기본적으로 오퍼레이터는 클라이언트와 서버 인증서를 모두 발급하는 단일 인증 기관(CA)을 자동으로 생성해요. 이 인증서들은 오퍼레이터가 지속적으로 관리하며, 만료 7일 전에 자동 갱신돼요(90일 유효 기간 내).

:::info CERTIFICATE_DURATION과 EXPIRING_CHECK_THRESHOLD 환경 변수를 구성해 이 기본 동작을 조정할 수 있어요. 자세한 지침은 Operator Configuration을 참고하세요. :::

:::info[Important] 인증서 갱신은 단순한 리로드 연산으로 충분하므로 PostgreSQL 서버에 다운타임을 초래하지 않아요. 하지만 CloudNativePG가 제어하지 않는 사용자 관리 인증서는 갱신 프로세스에 따라 다시 발급되어야 해요. :::

인증서를 생성할 때 오퍼레이터는 Kubernetes 클러스터의 DNS 영역이 기본적으로 cluster.local로 설정되어 있다고 가정해요. 이 동작은 KUBERNETES_CLUSTER_DOMAIN 환경 변수를 설정해 커스터마이즈할 수 있어요. 편리한 대안은 오퍼레이터의 구성 기능을 사용하는 거예요.

서버 인증서

서버 CA 시크릿

오퍼레이터는 자체 서명 CA를 생성해 다음 키를 포함하는 generic 시크릿에 저장해요:

  • ca.crt – 서버 인증서를 검증하는 데 사용되는 CA 인증서로, 클라이언트의 연결 문자열에서 sslrootcert로 사용돼요.
  • ca.key – 서버 SSL 인증서를 자동으로 서명하는 데 사용되는 키.

서버 TLS 시크릿

오퍼레이터는 생성된 자체 서명 CA를 사용해 서버 TLS 인증서를 서명해요. 이 인증서는 kubernetes.io/tls 타입의 시크릿에 저장되고 인스턴스가 ssl_cert_file과 ssl_key_file로 사용하도록 구성돼요. 이 접근 방식은 클라이언트가 자신의 신원을 검증하고 안전하게 연결할 수 있게 해줘요.

서버 대체 DNS 이름

기본 이름 외에도 생성된 서버 TLS 시크릿의 일부로 DNS 서버 대체 이름을 지정할 수 있어요.

클라이언트 인증서

클라이언트 CA 시크릿

기본적으로 서버 CA와 같은 자체 서명 CA가 사용돼요. 공개 부분은 모든 인스턴스에 ssl_ca_file로 전달되어 그 CA가 서명한 클라이언트 인증서를 검증할 수 있어요. 개인 키는 같은 시크릿에 저장되고 kubectl cnpg 플러그인이 생성한 클라이언트 인증서를 서명하는 데 사용돼요.

클라이언트 streaming_replica 인증서

오퍼레이터는 생성된 자체 서명 CA를 사용해 streaming_replica 사용자용 클라이언트 인증서를 서명하고 kubernetes.io/tls 타입의 시크릿에 저장해요. 프라이머리 인스턴스에 안전하게 연결할 수 있도록 이 인증서는 복제본의 연결 문자열에서 sslcert와 sslkey로 전달돼요.

사용자 제공 인증서 모드

서버 인증서

필요하다면 cert-manager 같은 별도 컴포넌트로 생성한 두 서버 인증서를 제공할 수도 있어요. 클러스터에 커스텀 서버 TLS 인증서를 사용하려면 다음 파라미터를 지정해야 해요:

  • serverTLSSecret – 서버 TLS 인증서를 포함하는 kubernetes.io/tls 타입 시크릿의 이름. 표준 tls.crt와 tls.key 키를 모두 포함해야 해요.
  • serverCASecret – ca.crt 키를 포함하는 시크릿의 이름.

:::note 오퍼레이터는 여전히 클라이언트 인증서와 관련된 두 시크릿을 생성하고 관리해요. :::

:::note 오퍼레이터와 인스턴스는 DNS 이름을 무시하고 CA에 대해서만 서버 인증서를 검증해요. 이는 클러스터 내 통신에 사용되는 <cluster>-rw 서비스에 대해 사용자 제공 인증서에 DNS 이름이 포함되지 않는 것이 일반적이기 때문이에요. :::

:::note 인스턴스가 ConfigMap과 시크릿을 리로드하게 하려면 여기에 cnpg.io/reload 키의 레이블을 추가할 수 있어요. 그렇지 않으면 kubectl cnpg reload 하위 명령으로 인스턴스를 리로드해야 해요. :::

예시

다음 파일이 있다고 가정해 볼게요:

  • server-ca.crt – 서버 TLS 인증서를 서명한 CA의 인증서.
  • server.crt– 서버 TLS 인증서의 인증서.
  • server.key – 서버 TLS 인증서의 개인 키.

CA 인증서를 포함하는 시크릿 만들기:

kubectl create secret generic my-postgresql-server-ca \
  --from-file=ca.crt=./server-ca.crt

TLS 인증서로 시크릿 만들기:

kubectl create secret tls my-postgresql-server \
  --cert=./server.crt --key=./server.key

그 시크릿들을 참조하는 PostgreSQL 클러스터 만들기:

kubectl apply -f - <<EOF
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example
spec:
  instances: 3
  certificates:
    serverCASecret: my-postgresql-server-ca
    serverTLSSecret: my-postgresql-server
  storage:
    storageClass: standard
    size: 1Gi
EOF

새 클러스터는 TLS 연결에 제공한 서버 인증서를 사용해요.

Cert-manager 예시

이 간단한 예시는 cert-manager를 사용해 자체 서명 CA를 설정하고 필요한 TLS 서버 인증서를 생성하는 방법을 보여줘요:

---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}
---
apiVersion: v1
kind: Secret
metadata:
  name: my-postgres-server-cert
  labels:
    cnpg.io/reload: ""
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-postgres-server-cert
spec:
  secretName: my-postgres-server-cert
  usages:
    - server auth
  dnsNames:
    - cluster-example-lb.internal.mydomain.net
    - cluster-example-rw
    - cluster-example-rw.default
    - cluster-example-rw.default.svc
    - cluster-example-r
    - cluster-example-r.default
    - cluster-example-r.default.svc
    - cluster-example-ro
    - cluster-example-ro.default
    - cluster-example-ro.default.svc
  issuerRef:
    name: selfsigned-issuer
    kind: Issuer
    group: cert-manager.io

Cert-manager는 my-postgres-server-cert라는 시크릿을 만들어요. 여기에는 필요한 모든 파일이 포함되며 다음과 같이 클러스터에서 참조할 수 있어요:

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example
spec:
  instances: 3
  certificates:
    serverTLSSecret: my-postgres-server-cert
    serverCASecret: my-postgres-server-cert
  storage:
    size: 1Gi

cert-manager를 사용해 서버와 클라이언트 CA 및 인증서를 모두 관리하는 완전한 예시는 cluster-example-cert-manager.yaml 배포 매니페스트에서 찾을 수 있어요.

클라이언트 인증서

필요하다면 cert-manager나 HashiCorp vault 같은 별도 컴포넌트로 생성한 두 클라이언트 인증서를 제공할 수도 있어요. 클러스터의 클라이언트 인증서를 검증하는 데 커스텀 CA를 사용하려면 다음 파라미터를 지정해야 해요:

  • replicationTLSSecret – streaming_replica 사용자용 클라이언트 인증서를 포함하는 kubernetes.io/tls 타입 시크릿의 이름. 표준 tls.crt와 tls.key 키를 모두 포함해야 해요.
  • clientCASecret– 클라이언트 인증서를 검증하는 데 사용할 CA의 ca.crt 키를 포함하는 시크릿의 이름.

:::note 오퍼레이터는 여전히 서버 인증서와 관련된 두 시크릿을 생성하고 관리해요. :::

:::note 클러스터가 클라이언트 CA 시크릿 키를 제어하지 않으므로, 더 이상 kubectl cnpg certificate로 클라이언트 인증서를 생성할 수 없어요. :::

:::note 인스턴스가 ConfigMap과 시크릿을 자동으로 리로드하게 하려면 여기에 cnpg.io/reload 키의 레이블을 추가할 수 있어요. 그렇지 않으면 kubectl cnpg reload 하위 명령으로 인스턴스를 리로드해야 해요. :::

streaming_replica 클라이언트 인증서 커스터마이즈하기

일부 환경에서는 회사 정책이나 다른 보안 우려(예: 여러 클러스터가 공유하는 CA) 때문에 common name이 streaming_replica인 인증서를 생성하지 못할 수 있어요. 이런 경우 사용자 매핑 기능을 사용해 다른 common name을 가진 인증서로 streaming_replica 사용자로 인증할 수 있게 할 수 있어요.

이 설정을 구성하려면 cnpg_streaming_replica라는 사전 정의된 맵에 pg_ident.conf 항목을 추가해요.

예를 들어 common name이 streaming-replica.cnpg.svc.cluster.local인 인증서로 streaming_replica 인증을 활성화하려면 클러스터 정의에 다음을 추가하세요:

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example
spec:
  postgresql:
    pg_ident:
    - cnpg_streaming_replica streaming-replica.cnpg.svc.cluster.local streaming_replica

오퍼레이터가 pg_ident.conf를 관리하는 방법에 대한 자세한 내용은 문서의 "PostgreSQL Configuration" 페이지를 참고해 주세요.

Cert-manager 예시

이 간단한 예시는 cert-manager를 사용해 자체 서명 CA를 설정하고 필요한 TLS 서버 인증서를 생성하는 방법을 보여줘요:

---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}
---
apiVersion: v1
kind: Secret
metadata:
  name: my-postgres-client-cert
  labels:
    cnpg.io/reload: ""
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-postgres-client-cert
spec:
  secretName: my-postgres-client-cert
  usages:
    - client auth
  commonName: streaming_replica
  issuerRef:
    name: selfsigned-issuer
    kind: Issuer
    group: cert-manager.io

Cert-manager는 필요한 모든 파일을 포함하는 my-postgres-client-cert라는 시크릿을 만들어요. 다음과 같이 클러스터에서 참조할 수 있어요:

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example
spec:
  instances: 3
  certificates:
    clientCASecret: my-postgres-client-cert
    replicationTLSSecret: my-postgres-client-cert
  storage:
    size: 1Gi

cert-manager를 사용해 서버와 클라이언트 CA 및 인증서를 모두 관리하는 완전한 예시는 cluster-example-cert-manager.yaml 배포 매니페스트에서 찾을 수 있어요.

더 알아보기 (Learn more)