APISIX에서 Vault를 사용하여 인증서를 관리하는 방법

Junduo Dong

Junduo Dong

June 9, 2023

Technology

API 게이트웨이는 API 생명주기 관리에서 핵심적인 기본 구성 요소입니다. 이는 모든 트래픽의 입구 역할을 하며, 다운스트림 클라이언트로부터의 API 요청을 올바른 업스트림 서비스로 라우팅하여 처리하는 역할을 담당합니다. 따라서 API 게이트웨이는 업스트림 서비스와 다운스트림 클라이언트 간의 네트워크 통신을 위해 작동합니다.

새로운 클라우드 네이티브 API 게이트웨이인 Apache APISIX는 다운스트림 클라이언트와 APISIX 간, 그리고 APISIX와 업스트림 서비스 간의 TLS/mTLS 통신 메커니즘을 제공하여 이들 간의 네트워크 보안을 보장합니다. APISIX는 SSL 인증서를 SSL 인증서 객체로 저장하며, TLS 프로토콜을 지원하는 확장 기능인 SNI(Server Name Indication)를 통해 SSL 인증서의 동적 로딩을 실현합니다.

APISIX에서 SSL 인증서를 안전하게 저장하기 위해, APISIX는 HashiCorp Vault와의 통합을 달성하여 Vault의 비밀 보안 저장 기능을 활용하여 SSL 인증서의 통합 관리를 실현했습니다. 이 글은 다운스트림 클라이언트와 APISIX 간의 HTTPS 통신 설정을 예로 들어, APISIX가 Vault를 통합하여 SSL 인증서 관리를 구현하는 방법을 소개합니다.

APISIX와 Vault 통합

SSL 인증서란 무엇인가

SSL/TLS는 두 통신 당사자 간에 암호화된 네트워크 연결을 설정하여 네트워크 통신의 보안을 보호하는 암호화 프로토콜입니다. SSL/TLS 프로토콜은 사용자와 서버를 인증하여 데이터가 올바른 클라이언트와 서버로 전송되도록 보장합니다. 또한, SSL/TLS 프로토콜은 통신 데이터를 암호화하여 전송 중에 데이터가 도난, 변조 또는 위조되지 않도록 보장합니다.

SSL 인증서는 웹사이트의 신원을 인증하고 SSL/TLS 프로토콜을 사용하여 암호화된 연결을 가능하게 하는 디지털 인증서입니다. SSL 인증서는 일반적으로 신뢰할 수 있는 디지털 인증 기관(CA)에 의해 발급되며, 주로 다음 정보를 포함합니다:

  • 도메인 이름
  • 인증 기관
  • 인증 기관이 서명한 디지털 서명
  • 관련 하위 도메인
  • 인증서 발급일
  • 인증서 만료일
  • 공개 키 (개인 키는 비밀 키입니다)

HashiCorp Vault란 무엇인가

HashiCorp Vault(이하 Vault)는 토큰, 비밀번호, 인증서와 같은 민감한 데이터를 저장하고 관리할 수 있는 기업급 비밀 관리 도구입니다. Vault는 전체 IT 시스템의 기술과 통합될 수 있으며, ID 기반의 보안 자동화 및 암호화 서비스를 제공하고, 민감한 데이터와 시스템에 대한 접근을 중앙에서 제어하여 조직이 데이터 유출 및 노출 위험을 줄이고 클라우드 및 애플리케이션 보안을 향상시킬 수 있도록 도와줍니다.

HashiCorp Vault

APISIX SSL 인증서를 Vault에 저장하는 방법

환경 준비

Vault 서비스 배포 및 구성

이 섹션에서는 Docker를 사용하여 Vault 컨테이너 서비스를 배포합니다. 이미 환경에 Vault 서비스 인스턴스가 있는 경우 이 섹션을 건너뛸 수 있습니다.

Dev 모드에서 apisix-quickstart-vault라는 이름의 Vault 컨테이너를 생성하고 배포합니다. Vault Token을 apisix-quickstart-vault-token으로 지정하고 포트 8200을 호스트에 매핑합니다:

docker run -d --cap-add=IPC_LOCK \
  -e 'VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200' \
  -e 'VAULT_ADDR=http://0.0.0.0:8200' \
  -e 'VAULT_DEV_ROOT_TOKEN_ID=apisix-quickstart-vault-token' \
  -e 'VAULT_TOKEN=apisix-quickstart-vault-token' \
  --network=apisix-quickstart-net \
  --name apisix-quickstart-vault \
  -p 8200:8200 vault:1.13.0

APISIX SSL 인증서 저장 경로로 kv를 선택합니다:

docker exec apisix-quickstart-vault vault secrets enable -path=kv -version=1 kv

APISIX 구성

APISIX는 Vault에서 SSL 인증서를 읽어야 하므로, Vault는 지정된 경로에 대한 읽기 권한을 APISIX에 부여해야 합니다.

apisix-policy.hcl이라는 이름의 Vault 정책을 생성하여 APISIX에 kv/apisix/ 경로에 대한 읽기 접근 권한을 부여합니다:

docker exec apisix-quickstart-vault /bin/sh -c "echo '
path \"kv/apisix/*\" {
    capabilities = [\"read\"]
}
' > /etc/apisix-policy.hcl"

생성된 정책 파일 apisix-policy.hcl을 Vault에 적용합니다:

docker exec apisix-quickstart-vault vault policy write apisix-policy /etc/apisix-policy.hcl

Vault 연결 정보와 인증서 저장 경로를 저장하기 위해 quickstart-secret-id라는 ID를 가진 APISIX 비밀 객체를 생성합니다:

curl -i "http://127.0.0.1:9180/apisix/admin/secrets/vault/quickstart-secret-id" -X PUT -d '
{
    "uri": "http://apisix-quickstart-vault:8200",
    "prefix": "kv/apisix",
    "token" : "apisix-quickstart-vault-token"
}'

Vault에 SSL 인증서 저장

자체 서명된 CA 인증서 ca.crt와 키 ca.key를 생성합니다:

openssl genrsa -out ca.key 2048 && \
  openssl req -new -sha256 -key ca.key -out ca.csr -subj "/CN=ROOTCA" && \
  openssl x509 -req -days 36500 -sha256 -extensions v3_ca -signkey ca.key -in ca.csr -out ca.crt

CA에 의해 발급된 SSL 인증서 server.crt와 키 server.key를 생성하며, 그 공통 이름(CN)은 test.com입니다:

openssl genrsa -out server.key 2048 && \
  openssl req -new -sha256 -key server.key -out server.csr -subj "/CN=test.com" && \
  openssl x509 -req -days 36500 -sha256 -extensions v3_req \
  -CA ca.crt -CAkey ca.key -CAserial ca.srl -CAcreateserial \
  -in server.csr -out server.crt

발급된 SSL 인증서와 키를 Vault 컨테이너로 복사합니다:

docker cp server.key apisix-quickstart-vault:/root/
docker cp server.crt apisix-quickstart-vault:/root/

vault kv put 명령을 사용하여 SSL 인증서와 키를 비밀로 저장하며, 키는 ssl이고 저장 경로는 kv/apisix입니다:

docker exec apisix-quickstart-vault vault kv put kv/apisix/ssl test.com.crt=@/root/server.crt test.com.key=@/root/server.key

위 명령을 통해 Vault에 ssl이라는 이름의 비밀을 저장했으며, 이 비밀에는 인증서와 개인 키라는 2개의 키-값 쌍이 포함되어 있습니다.

Vault에 저장된 APISIX SSL 인증서 사용 방법

APISIX는 다운스트림 클라이언트와 APISIX 간, 그리고 APISIX와 업스트림 서비스 간의 TLS/mTLS 네트워크 암호화를 지원하며, 여기서 Vault에 저장된 SSL 인증서를 사용할 수 있습니다. 클라이언트와 APISIX 간의 HTTPS 통신 설정을 예로 들어, APISIX에서 Vault에 저장된 SSL 인증서를 사용하는 방법을 보여드리겠습니다.

클라이언트와 APISIX 간 HTTPS 통신 구성

SSL 인증서 객체를 생성하여 SSL 인증서를 저장합니다:

curl -i "http://127.0.0.1:9180/apisix/admin/ssls" -X PUT -d '
{
  "id": "quickstart-tls-client-ssl",
  "sni": "test.com",
  "cert": "$secret://vault/quickstart-secret-id/ssl/test.com.crt",
  "key": "$secret://vault/quickstart-secret-id/ssl/test.com.key"
}'

이 객체의 snitest.com이며, 이는 인증서 발급 시의 CN과 일치합니다. certkey는 발급된 인증서와 개인 키에 해당하며, 이는 설정된 비밀 리소스 로케이터를 통해 Vault에서 자동으로 가져옵니다. 리소스 로케이터 규칙은 다음과 같습니다:

$secret://$manager/$id/$secret_name/$key
  • manager: 키 관리 서비스 Vault
  • id: APISIX 비밀 리소스 ID
  • secret_name: Vault의 비밀 이름
  • key: secret_name이라는 비밀 내의 키-값 쌍의 키

클라이언트와 APISIX 간 HTTPS 통신 검증

/ip로 전송된 모든 요청을 업스트림 httpbin.org로 전달하는 라우트를 생성합니다:

curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
  "id": "quickstart-client-ip",
  "uri": "/ip",
  "upstream": {
    "nodes": {
      "httpbin.org:80":1
    },
    "type": "roundrobin"
  }
}'

cURL을 사용하여 https://test.com:9443/ip로 요청을 보내며, test.com127.0.0.1로 해석됩니다:

curl -ikv --resolve "test.com:9443:127.0.0.1" "https://test.com:9443/ip"

설정이 성공적으로 완료되면, cURL이 반환하는 클라이언트와 APISIX 간의 TLS 핸드셰이크 과정은 다음과 같은 결과와 동일할 것입니다:

* Added test.com:9443:127.0.0.1 to DNS cache
* Hostname test.com was found in DNS cache
*   Trying 127.0.0.1:9443...
* Connected to test.com (127.0.0.1) port 9443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=test.com
*  start date: Apr 21 07:47:54 2023 GMT
*  expire date: Mar 28 07:47:54 2123 GMT
*  issuer: CN=ROOTCA
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x556274d632e0)
> GET /ip HTTP/2
> Host: test.com:9443
> user-agent: curl/7.74.0
> accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200
HTTP/2 200
...

요약

APISIX가 Vault를 통합하여 SSL 인증서 관리를 구현하는 방법을 소개하고, 다운스트림 클라이언트와 APISIX 간의 HTTPS 통신 설정을 예로 들어 구성 및 통합 단계를 상세히 설명했습니다.

APISIX에서 SSL 인증서의 관련 개념 및 사용 시나리오에 대해서는 다음 글들을 참조하세요:

Tags: