TLS를 사용한 단일 서버 배포
TLS를 사용한 단일 서버 배포 (Standalone with TLS)
쿠버네티스 CA로 키와 인증서를 만들고 Helm 차트에 TLS를 설정해 단일 서버 Vault 클러스터를 구성하는 예제입니다.
출처: 문서
본문
중요한 참고: 이 차트는 Helm 2와 호환되지 않아요. 이 차트에는 Helm 3.6 이상을 사용해 주세요.
이 예제는 TLS를 사용하는 단일 서버 Vault 클러스터를 구성하는 데 쓸 수 있어요.
- 쿠버네티스 CA를 사용해 키와 인증서 생성
- 키와 인증서를 쿠버네티스 시크릿 저장소에 저장
- 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
- 쿠버네티스가 서명할 키를 만듭니다.
$ openssl genrsa -out ${TMPDIR}/vault.key 2048
Generating RSA private key, 2048 bit long modulus
...................................................................................................+++
...............+++
e is 65537 (0x10001)
-
인증서 서명 요청(CSR)을 만듭니다.
-
다음 내용의 파일
$ {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
- 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
- 인증서를 만듭니다.
중요한 참고: EKS를 사용한다면 인증서 서명 요건이 바뀌었어요. AWS certificate signing 문서에 따르면 EKS 1.22 이상에서는
signerName이beta.eks.amazonaws.com/app-serving이어야 합니다. 그렇지 않으면 CSR은 승인되지만 인증서가 발급되지 않아요.
- 다음 내용의 파일
$ {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
- CSR을 쿠버네티스로 보냅니다.
$ kubectl create -f ${TMPDIR}/csr.yaml
certificatesigningrequest.certificates.k8s.io/vault-csr created
자동화된 프로세스라면 CSR이 수신·저장됐는지 확인할 때까지 기다려야 할 수 있어요: kubectl get csr ${CSR_NAME}
- 쿠버네티스에서 CSR을 승인합니다.
$ kubectl certificate approve ${CSR_NAME}
certificatesigningrequest.certificates.k8s.io/vault-csr approved
- 인증서가 승인·발급됐는지 확인합니다.
$ kubectl get csr ${CSR_NAME}
NAME AGE SIGNERNAME REQUESTOR CONDITION
vault-csr 1m13s kubernetes.io/kubelet-serving kubernetes-admin Approved,Issued
2. 키, 인증서, 쿠버네티스 CA를 쿠버네티스 시크릿 저장소에 저장
- 인증서를 가져옵니다.
$ serverCert=$(kubectl get csr ${CSR_NAME} -o jsonpath='{.status.certificate}')
자동화된 프로세스라면 인증서가 만들어질 때까지 기다려야 할 수 있어요. 아직 만들어지지 않았다면 빈 문자열을 반환합니다.
- 인증서를 파일로 씁니다.
$ echo "${serverCert}" | openssl base64 -d -A -out ${TMPDIR}/vault.crt
- 쿠버네티스 CA를 가져옵니다.
kubectl get cm kube-root-ca.crt -o jsonpath="{['data']['ca\.crt']}" > ${TMPDIR}/vault.ca
- 네임스페이스를 만듭니다.
$ kubectl create namespace ${NAMESPACE}
namespace/vault-namespace created
- 키, 인증서, 쿠버네티스 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"
}