TLS를 사용한 단일 서버 배포

TLS를 사용한 단일 서버 배포 (Standalone with TLS)

쿠버네티스 CA로 키와 인증서를 만들고 Helm 차트에 TLS를 설정해 단일 서버 Vault 클러스터를 구성하는 예제입니다.

출처: 문서

본문

중요한 참고: 이 차트는 Helm 2와 호환되지 않아요. 이 차트에는 Helm 3.6 이상을 사용해 주세요.

이 예제는 TLS를 사용하는 단일 서버 Vault 클러스터를 구성하는 데 쓸 수 있어요.

  1. 쿠버네티스 CA를 사용해 키와 인증서 생성
  2. 키와 인증서를 쿠버네티스 시크릿 저장소에 저장
  3. 2단계의 쿠버네티스 시크릿을 사용하도록 Helm 차트 구성

1. 쿠버네티스 CA로 키와 인증서 만들기

이 예제에서 사용할 변수는 네 가지예요.

# SERVICE는 쿠버네티스에서 Vault 서비스의 이름이에요.
# 실제 실행 중인 서비스와 일치할 필요는 없지만, 일관성을 위해 맞추면 도움이 돼요.
export SERVICE=vault-server-tls

# NAMESPACE는 Vault 서비스가 실행 중인 네임스페이스예요.
export NAMESPACE=vault-namespace

# SECRET_NAME은 쿠버네티스 시크릿 저장소에 만들 이름이에요.
export SECRET_NAME=vault-server-tls

# TMPDIR은 임시 작업 디렉터리예요.
export TMPDIR=/tmp

# CSR_NAME은 쿠버네티스가 보는 인증서 서명 요청의 이름이에요.
export CSR_NAME=vault-csr
  1. 쿠버네티스가 서명할 키를 만듭니다.
$ openssl genrsa -out ${TMPDIR}/vault.key 2048
Generating RSA private key, 2048 bit long modulus
...................................................................................................+++
...............+++
e is 65537 (0x10001)
  1. 인증서 서명 요청(CSR)을 만듭니다.

  2. 다음 내용의 파일 $ {TMPDIR}/csr.conf를 만듭니다.

cat <<EOF > ${TMPDIR}/csr.conf
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = *.${SERVICE}
DNS.2 = *.${SERVICE}.${NAMESPACE}
DNS.3 = *.${SERVICE}.${NAMESPACE}.svc
DNS.4 = *.${SERVICE}.${NAMESPACE}.svc.cluster.local
IP.1 = 127.0.0.1
EOF
  1. CSR을 만듭니다.
openssl req -new \
            -key ${TMPDIR}/vault.key \
            -subj "/CN=system:node:${SERVICE}.${NAMESPACE}.svc;/O=system:nodes" \
            -out ${TMPDIR}/server.csr \
            -config ${TMPDIR}/csr.conf
  1. 인증서를 만듭니다.

중요한 참고: EKS를 사용한다면 인증서 서명 요건이 바뀌었어요. AWS certificate signing 문서에 따르면 EKS 1.22 이상에서는 signerNamebeta.eks.amazonaws.com/app-serving이어야 합니다. 그렇지 않으면 CSR은 승인되지만 인증서가 발급되지 않아요.

  1. 다음 내용의 파일 $ {TMPDIR}/csr.yaml을 만듭니다.
cat <<EOF > ${TMPDIR}/csr.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: ${CSR_NAME}
spec:
  signerName: kubernetes.io/kubelet-serving
  groups:
  - system:authenticated
  request: $(base64 ${TMPDIR}/server.csr | tr -d '\n')
  signerName: kubernetes.io/kubelet-serving
  usages:
  - digital signature
  - key encipherment
  - server auth
EOF
  1. CSR을 쿠버네티스로 보냅니다.
$ kubectl create -f ${TMPDIR}/csr.yaml
certificatesigningrequest.certificates.k8s.io/vault-csr created

자동화된 프로세스라면 CSR이 수신·저장됐는지 확인할 때까지 기다려야 할 수 있어요: kubectl get csr ${CSR_NAME}

  1. 쿠버네티스에서 CSR을 승인합니다.
$ kubectl certificate approve ${CSR_NAME}
certificatesigningrequest.certificates.k8s.io/vault-csr approved
  1. 인증서가 승인·발급됐는지 확인합니다.
$ kubectl get csr ${CSR_NAME}
NAME        AGE     SIGNERNAME                                    REQUESTOR                        CONDITION
vault-csr   1m13s   kubernetes.io/kubelet-serving                 kubernetes-admin                 Approved,Issued

2. 키, 인증서, 쿠버네티스 CA를 쿠버네티스 시크릿 저장소에 저장

  1. 인증서를 가져옵니다.
$ serverCert=$(kubectl get csr ${CSR_NAME} -o jsonpath='{.status.certificate}')

자동화된 프로세스라면 인증서가 만들어질 때까지 기다려야 할 수 있어요. 아직 만들어지지 않았다면 빈 문자열을 반환합니다.

  1. 인증서를 파일로 씁니다.
$ echo "${serverCert}" | openssl base64 -d -A -out ${TMPDIR}/vault.crt
  1. 쿠버네티스 CA를 가져옵니다.
kubectl get cm kube-root-ca.crt -o jsonpath="{['data']['ca\.crt']}" > ${TMPDIR}/vault.ca
  1. 네임스페이스를 만듭니다.
$ kubectl create namespace ${NAMESPACE}
namespace/vault-namespace created
  1. 키, 인증서, 쿠버네티스 CA를 쿠버네티스 시크릿에 저장합니다.
$ kubectl create secret generic ${SECRET_NAME} \
    --namespace ${NAMESPACE} \
    --from-file=vault.key=${TMPDIR}/vault.key \
    --from-file=vault.crt=${TMPDIR}/vault.crt \
    --from-file=vault.ca=${TMPDIR}/vault.ca

# secret/vault-server-tls created

3. Helm 구성

아래 custom-values.yaml은 TLS를 사용하는 단일 서버 Vault 클러스터를 구성하는 데 쓸 수 있어요. 서버 인증서, 키, 인증 기관이 들어 있는 쿠버네티스 시크릿이 이미 존재한다고 가정합니다.

global:
  enabled: true
  tlsDisable: false

server:
  extraEnvironmentVars:
    VAULT_CACERT: /vault/userconfig/vault-server-tls/vault.ca

  volumes:
    - name: userconfig-vault-server-tls
      secret:
        defaultMode: 420
        secretName: vault-server-tls # 위의 ${SECRET_NAME}과 일치

  volumeMounts:
    - mountPath: /vault/userconfig/vault-server-tls
      name: userconfig-vault-server-tls
      readOnly: true

  standalone:
    enabled: true
    config: |
      listener "tcp" {
        address = "[::]:8200"
        cluster_address = "[::]:8201"
        tls_cert_file = "/vault/userconfig/vault-server-tls/vault.crt"
        tls_key_file  = "/vault/userconfig/vault-server-tls/vault.key"
        tls_client_ca_file = "/vault/userconfig/vault-server-tls/vault.ca"
      }

      storage "file" {
        path = "/vault/data"
      }

더 알아보기 (Learn more)