Boundary의 TLS

Boundary의 TLS

Boundary는 세 가지 연결 유형(클라이언트-컨트롤러, 클라이언트-워커, 워커-업스트림)을 모두 TLS 또는 상호 인증된 TLS(mTLS)로 보호해요. 클라이언트-워커 연결은 인증서를 동적으로 생성하므로 워커에 수동 TLS 구성이 필요하지 않아요.

출처: HashiCorp Boundary docs

본문

클라이언트-워커 연결 같은 일부 TLS 사용 방식은 다른 대부분의 제품과 달라요. 워커의 리슨 포트에 TLS를 사용자 구성하는 것이 필요하지 않을 뿐 아니라 더 안전하다는 점이 쉽게 보이지 않을 수도 있어요. 하지만 TLS에 관해서 Boundary는 운영의 단순함과 함께 기본적으로 높은 보안을 제공하려고 해요.

클라이언트-컨트롤러 TLS

Boundary의 API 접근(즉, 기본적으로 포트 9200을 사용하는 컨트롤러 서버)은 표준 PKI를 사용해요. 유효한 인증서(선택적으로 CA 인증서 또는 체인)를 제공해서 TLS를 구성하고, 클라이언트는 그 CA 체인을 신뢰해야 해요. 이는 다양한 클라이언트와의 광범위한 호환성을 제공해요.

클라이언트 인증서를 요구하도록 하는 것도 가능해요. 사용 가능한 TLS 파라미터는 listener 블록 구성에서 확인할 수 있어요.

클라이언트-워커 TLS

워커는 클라이언트 대면 리스너가 높은 수준의 보안을 지원하기 위해 어떤 구성도 요구하지 않아요. 대신 사용할 TLS 구성은 SNI(서버 이름 표시)를 통해 동적으로 결정되고, 세션은 그다음 상호 인증돼요.

TLS 수립은 다음과 같이 진행돼요.

  • 세션이 인가되면 컨트롤러가 자체 포함 체인 역할을 하는 TLS 인증서를 생성해요. 이는 위의 워커-컨트롤러 흐름과 비슷하지만, 이 경우 키는 대상이 포함된 스코프의 "root" KMS로 저장 시 보호되는, 컨트롤러 내부의 기본 키에서 파생된 Ed25519 키예요. 파생은 사용자 ID와 세션 ID를 입력으로 HKDF-SHA256을 사용해요. 인증서의 수명은 세션의 수명과 연결돼요.
  • 인증서와 개인 키(다른 세션 인가 데이터, 특히 세션 ID와 함께)는 대상에 대한 authorize-session 액션의 출력 일부로 마샬링된 객체 형태로 클라이언트에 반환돼요. 컨트롤러는 인증서는 데이터베이스에 저장하지만 개인 키는 저장하지 않아요.
  • 클라이언트(즉, boundary connect 명령)는 이 세션 인가 데이터를 파싱하고 인증서와 개인 키를 사용해 TLS 스택을 구성해요. 그런 다음 세션 ID를 SNI 값으로 전달하면서 워커에 TLS 1.3 연결을 만들어요.
  • 워커는 SNI 값을 보고 컨트롤러에 호출해서 세션 ID를 키로 하는 세션 인가 정보를 가져와요.
  • 컨트롤러는 주어진 ID를 가진 세션을 찾아 정보를 가져와요. 세즘과 연결된 세션 ID와 사용자 ID를 사용해 개인 키를 다시 파생하고 모든 정보를 워커에 전달해요. 특히 TOFU(신뢰 기반 최초 사용) 토큰이 포함될 수 있어요.
  • 워커는 주어진 데이터로 동일한 인증서와 키로 TLS 스택을 구성해요.
  • 연결은 상호 인증돼요. 각 끝에서 안전하게 전송된 단일 자체 서명 CA 인증서만 검증용 유효 루트 CA로 구성돼요.
  • 성공하면 클라이언트와 워커가 핸드셰이크를 수행하는데, 클라이언트가 워커에 TOFU(신뢰 기반 최초 사용) 값을 전달해요. 이 값은 클라이언트가 생성될 때(즉, boundary connect가 실행될 때) 파생돼요. 이를 통해 단일 클라이언트가 세션 안에서 여러 연결을 만들 수 있고, 자격 증명이 다른 클라이언트를 통해 사용될 수 없어요.
    • 워커가 5단계에서 TOFU 토큰을 받지 못했다면 워커는 그 값을 컨트롤러에 제출해요. 컨트롤러는 (데이터베이스 트랜잭션을 통해) 세션이 이전에 다른 TOFU 토큰을 제출받지 않았는지 검증하고 저장해요. 그렇지 않으면 재생 공격 가능성으로 거부하고 연결도 거부돼요.
    • 워커가 5단계에서 TOFU 토큰을 받았다면 값이 일치하는지 확인해요. 일치하지 않으면 재생 공격 가능성으로 연결이 거부돼요.

미래에는 다른 클라이언트 패러다임을 지원하기 위해 워커의 클라이언트 대면 TLS에 대한 사용자 구성을 지원할 수도 있어요. 이 모델에서는 공유 인증서/개인 키가 사용자 이름/비밀번호처럼 세션의 자격 증명 역할을 해요.

워커-업스트림 TLS

워커는 TLS 연결로 업스트림(컨트롤러 또는 다른 워커)에 연결해요. 이 연결을 만들려면 워커가 클러스터에 인증되어야 해요. 이 인증과 세션 수립이 어떻게 일어나는지는 두 가지 방식 중 하나가 될 수 있어요. 내장 X.509 기반 PKI(공개 키 기반) 시스템을 사용하거나, KMS 시스템을 활용해 인증 정보의 안전한 전송을 제공할 수 있어요.

KMS 기반 메커니즘은 워커의 클러스터에 대한 제로 터치 등록을 제공하고, PKI 메커니즘은 등록 시점에 긍정적인 접근 제어를 제공해요. 현재 HCP Boundary 배포는 자체 관리 워커에 대해 PKI 인증만 지원해요.

PKI 기반 워커 인증

PKI 기반 인증 메커니즘에서 워커는 워커의 공개 서명 및 암호화 키를 클러스터에 알려서 등록돼요. 그러면 클러스터는 서명된 인증서 세트와 컨트롤러 공개 암호화 키를 워커에 반환해요. 이 과정은 초기 공개 키 자료의 전송 보안을 제공하기 위해 운영자(또는 프로비저닝 시스템)가 중재해요.

PKI 메커니즘은 워커에서 클러스터 컨트롤러로의 단일 값 전송으로 설정돼요. 일단 수립되면 인증서와 암호화 키가 주기적으로(현재 2주 주기로) 자동 회전돼요.

이 메커니즘에는 worker-led(워커가 초기 키 자료를 생성)와 controller-led(컨트롤러가 초기 키 자료를 생성)의 두 가지 변형이 있어요.

참고로 이 섹션에서 설명하는 메커니즘은 명확성을 위해 세부 사항을 생략했어요.

Worker-led PKI 등록

등록은 다음과 같이 진행돼요.

  • 워커가 서명용 공개/개인 Ed25519 키쌍과 암호화용 공개/개인 X25519 키쌍, 등록 nonce를 생성하고 이 값들을 번들로 운영자 또는 오케스트레이션 시스템에 제공해요. 번들은 워커의 개인 Ed25519 키로 서명돼요(서명은 트래픽을 엿볼 수 있는 중간자(MITM)가 워커의 개인 서명 키가 없어서 컨트롤러에 보내는 요청에서 워커로 가장할 수 없도록 보장해요. 그 결과 제대로 등록되거나 프록시할 세션을 받을 수 없어요).
  • 운영자 또는 오케스트레이션 시스템이 이 번들을 인증되고 인가된 API 호출로 클러스터의 컨트롤러에 제출해서, 주어진 키 정보에 연결된 워커 리소스를 만들어 달라고 요청해요.
  • 컨트롤러가 워커 리소스를 만들고 주어진 키 자료에 연결해요. 컨트롤러는 또한 워커의 서명 키를 인증하는 클라이언트 전용 인증서에 서명하고, 그 워커 특유의 자체 암호화 공개/개인 키쌍을 생성해요.
  • 워커가 구성된 업스트림에 요청해서 발급된 자격 증명을 가져와요. 요청에 공개 키와 원래 등록 nonce를 제공하고, 워커의 개인 Ed25519 키로 서명돼요(여기서도 MITM이 서명 키가 없어 워커로 가장할 수 없음을 의미해요). 구성된 업스트림이 컨트롤러면 직접 응답할 수 있고, 그렇지 않으면 요청이 클러스터 컨트롤러로 중계돼요.
  • 요청을 받은 컨트롤러는 2단계에서 운영자/오케스트레이션 시스템이 제공한 번들의 nonce와 키가 일치하는지 검증해요. 일치하면 컨트롤러는 워커별 암호화 개인 키와 워커의 암호화 공개 키를 사용해 공유 대칭 암호화 키를 파생하고, 그것으로 워커 인증서, CA 인증서, nonce를 암호화해서 암호화 공개 키와 함께 워커에 반환해요.
  • 워커는 주어진 컨트롤러 암호화 공개 키와 자신의 개인 키로 공유 대칭 키를 파생하고, 반환된 번들을 복호화할 수 있는지 확인하며 nonce를 검증한 다음 발급된 인증서와 CA 인증서를 저장해요.

Controller-led PKI 등록

등록은 다음과 같이 진행돼요.

  • 운영자가 워커 활성화 토큰을 요청해요. 컨트롤러가 워커 리소스를 만들고 일회용 활성화 토큰과 nonce를 생성해 그 값을 운영자에게 반환해요.
  • 운영자가 이 토큰을 워커 구성 파일의 controller_generated_activation_token 필드에 넣어요.
  • 워커가 서명용 공개/개인 Ed25519 키쌍과 암호화용 공개/개인 X25519 키쌍을 생성하고 이 번들에 서명해요.
  • 워커가 구성된 업스트림에 요청해서 발급된 자격 증명을 가져와요. 요청에 공개 키와 활성화 토큰을 제공하고, 워커의 개인 Ed25519 키로 서명돼요(중간자가 서명 키가 없어 워커로 가장할 수 없어요). 구성된 업스트림이 컨트롤러면 직접 응답할 수 있고, 그렇지 않으면 요청이 클러스터 컨트롤러로 중계돼요.
  • 요청을 받은 컨트롤러가 1단계에서 생성된 활성화 토큰을 검증해요. 토큰이 검증되면 컨트롤러는 주어진 키 자료를 미리 만든 워커 리소스에 연결해요. 컨트롤러는 또한 워커의 서명 키를 인증하는 클라이언트 전용 인증서에 서명하고, 그 워커 특유의 자체 암호화 공개/개인 키쌍을 생성해요. 키쌍은 공유 대칭 암호화 키를 파생하고 워커 인증서와 CA 인증서를 암호화하는 데 사용돼요. 컨트롤러는 공개 암호화 키와 함께 워커에 반환해요.
  • 워커는 주어진 컨트롤러 암호화 공개 키와 자신의 개인 키로 공유 대칭 키를 파생하고, 반환된 번들을 복호화할 수 있는지 확인한 다음 발급된 인증서와 CA 인증서를 저장해요.

PKI 기반 세션 수립

저장된 자격 증명을 사용해 PKI 기반 워커는 다음과 같이 세션을 수립해요.

  • 워커가 업스트림에 TLS 연결을 시작하고, TLS 인증서와 nonce가 들어 있는 서명된 번들을 제시해요.
  • 업스트림이 적시(just-in-time) 서버 인증서를 요청해요(등록 중 발급된 인증서는 클라이언트 전용임을 기억하세요). 컨트롤러면 직접, 다른 워커면 컨트롤러에 대한 프록시 요청을 통해요. 요청은 워커의 nonce와 클라이언트 인증서의 키 ID를 전달해요.
  • 클러스터 컨트롤러가 키 ID를 검증해 등록된 워커인지 확인한 다음, 워커의 nonce를 포함하고 클러스터 CA 인증서로 서명된 짧은 검증 기간의 인증서를 생성해요. 이 인증서를 발급한 컨트롤러는 클라이언트 인증서에 연결된 워커의 유효성을 보증했으므로, 들어오는 워커를 업스트림에 인증한 셈이에요. (기술적으로 클라이언트 인증서 검증은 TLS 핸드셰이크에서 더 나중에 일어나지만, 개념적으로는 이 시점에 들어오는 워커가 업스트림에 인증돼요.)
  • 업스트림이 이 서버 인증서를 워커에 제시해요. 워커는 자신의 nonce가 인증서에 포함되어 있고 인증서 체인이 저장된 CA 중 하나로 검증될 수 있는지 확인해요. 이는 신뢰된 루트가 예상 nonce를 포함한 새 인증서를 발급해 업스트림에 제공했으므로, 업스트림을 들어오는 워커에게 인증해요.
  • TLS 연결이 수립되고 업스트림이 워커 프로토콜을 처리할 수 있어요.

PKI 기반 자격 증명 회전

주기적으로 PKI 기반 워커는 자격 증명 회전을 트리거해요. 메커니즘은 다음과 같아요.

  • 워커가 새 서명용 공개/개인 Ed25519 키쌍과 새 암호화 X25519 공개/개인 키쌍을 생성해요.
  • 워커가 컨트롤러에 새 자격 증명을 가져오는 요청을 만들고, 요청에 새 공개 키와 작업 nonce를 제공하며 현재 X25519 파라미터를 통해 현재 공유 대칭 암호화 키로 암호화해요. 컨트롤러와 워커만 이 공유 대칭 키를 파생할 수 있으므로, 워커는 요청이 충족되려면 이미 신뢰된 컨트롤러가 처리해야 함을 알 수 있어요.
  • 컨트롤러가 번들을 복호화하고 새 키 정보를 워커 리소스에 등록해요. 새 인증서와 암호화 공개/개인 키쌍을 생성하고 인증서, 현재 CA, 작업 nonce, 암호화 공개 키를 워커에 반환해요. 암호화 공개 키를 제외한 모든 것은 새 컨트롤러 암호화 개인 키/새 워커 암호화 공개 키에서 파생된 대칭 키로 암호화돼요.
  • 이 정보 자체는 기존 대칭 암호화 키로 암호화되고 이 값이 워커에 반환돼요.
  • 워커는 현재 정보로 바깥 번들을 복호화하고, 그것으로 컨트롤러에서 인증된 새 암호화 공개 키를 검색한 다음, 새 암호화 개인 키와 함께 사용해 새 공유 대칭 암호화 키를 파생해요. 그 새 키로 나머지 파라미터를 복호화하고, nonce가 1단계에서 워커가 시작한 현재 작업에 대한 응답인지 확인해요.
  • 워커는 신뢰된 컨트롤러가 새 인증서 정보와 암호화 파라미터를 제공했고, 그 파라미터로 공유 대칭 암호화 키를 성공적으로 파생할 수 있음을 검증했어요. 워커는 새 자격 증명을 저장하고 앞으로 그것들을 사용해요.

KMS 기반 워커 인증

워커는 Boundary 구성 파일에서 worker-auth로 지정된 KMS 키를 활용할 수 있는데, 이 키는 컨트롤러와 워커 모두가 KMS에서 동일한 키를 가리켜야 해요. 연결의 보안은 단일 허용 TLS 파라미터 집합의 안전한 전송에 의존하며, 이것이 연결의 전체 허용 CA 체인을 형성해요.

TLS 수립은 다음과 같이 진행돼요.

  • 워커가 자체 포함 체인 역할을 하는 TLS 인증서와 nonce를 생성해요. 생성된 키 유형은 현재 Ed25519예요. 인증서는 총 2.5분간 유효해요. 현재 시간보다 30초 전(약간의 시계 드리프트 허용)과 2분 후(연결 수립 시간 허용)까지예요.
  • 워커가 TLS 체인과 nonce를 마샬링하고 결과 바이트를 공유 KMS로 암호화해요. 이 값은 마샬링되어 청크로 나뉘어요.
  • 워커가 컨트롤러에 TLS 1.3 연결을 만들어요. 암호화된 값은 TLS ALPN(애플리케이션 계층 프로토콜 협상) 필드를 통해 번호가 매겨진 청크로 컨트롤러에 전송돼요.
  • 컨트롤러가 청크를 읽고 원래의 암호화된 값으로 다시 조립해요.
  • 컨트롤러가 공유 KMS로 이 값을 복호화해요. 성공하면 컨트롤러는 재생이 아닌지 확인하기 위해 nonce가 알려지지 않은 값인지 검증해요. nonce 값은 데이터베이스에서 확인되고 저장되어, nonce 재생이 컨트롤러 간에 일어날 수 없도록 보장해요.
  • 컨트롤러가 복호화된 파라미터로 TLS 스택을 동일한 인증서와 키로 구성해요.
  • 연결은 상호 인증돼요. 각 끝에서 안전하게 전송된 단일 자체 서명 CA 인증서만 검증용 유효 루트 CA로 구성돼요.

더 알아보기 (Learn more)