SSL/TLS 인증서 재시작 없이 교체하기

이 포스트에서는 njs shared dictionary 기능과 이점을 살펴보고 SSL/TLS 인증서 교체를 진행할 때 재시작할 필요 없이 NGINX 오픈 소스를 설정하는 방법을 보여줍니다.

고성능 웹 서버의 세계에서는 가볍고 효율적인 아키텍처로 대량의 트래픽을 처리할 수 있는 NGINX가 인기 있는 선택입니다. NGINX JavaScript 모듈(njs)의 일부로 shared dictionary 기능이 도입되면서 NGINX의 성능은 한 차원 더 높아졌습니다.

목차

1. Shared Dictionary 기본 사항 및 이점
2. Shared Dictionary를 사용한 SSL/TLS 인증서 교체
3. 지금 시작하세요.

1. Shared Dictionary 기본 사항 및 이점

새로운 js_shared_dict_zone 지시문을 사용하면 NGINX 오픈 소스 사용자가 worker process 간의 효율적인 데이터 교환을 위해 공유 메모리 영역을 활성화할 수 있습니다. 이러한 공유 메모리 영역은 실시간으로 액세스하고 수정할 수 있는 동적 구성 설정을 저장하는 key-value dictionary 역할을 합니다.

Shared dictionary의 주요 이점은 다음과 같습니다:

  • 최소한의 오버헤드 및 간편한 사용 – njs에 직접 구축되어 직관적인 API와 간단한 구현으로 프로비저닝 및 활용이 용이합니다. 또한 worker process 간에 데이터를 관리하고 공유하는 프로세스를 간소화하는 데 도움이 됩니다.
  • 가볍고 효율적 – 이벤트 중심의 non-blocking I/O 모델을 활용하여 NGINX와 원활하게 통합됩니다. 이 접근 방식은 메모리 사용량을 줄이고 동시성을 개선하여 NGINX가 많은 동시 연결을 효율적으로 처리할 수 있도록 합니다.
  • 확장성 – 여러 worker process에 걸쳐 수평적으로 확장할 수 있는 NGINX의 기능을 활용하여 복잡한 프로세스 간 통신 메커니즘 없이도 해당 프로세스 간에 데이터를 공유하고 동기화할 수 있습니다. TTL(Time-to-Live) 설정을 사용하면 shared dictionary 항목의 레코드를 비활성화로 인해 영역에서 제거하여 관리할 수 있습니다. evict 매개변수는 가장 오래된 key-value 쌍을 제거하여 새 항목을 위한 공간을 확보합니다.

2. Shared Dictionary를 사용한 SSL/TLS 인증서 교체

Shared dictionary의 가장 영향력 있는 사용 사례 중 하나는 SSL/TLS 인증서 교체입니다. js_shared_dict_zone을 사용하면 SSL/TLS 인증서 또는 키가 업데이트되는 경우 NGINX를 재시작할 필요가 없습니다. 또한 NGINX에서 인증서를 관리할 수 있는 REST와 유사한 API를 제공합니다.

다음은 js_setssl_certificate 지시문을 사용하여 HTTPS 서버를 설정하는 NGINX 구성 파일의 예입니다. JavaScript 핸들러는 js_set을 사용하여 파일에서 SSL/TLS 인증서 또는 키를 읽습니다.

이 구성 스니펫은 shared dictionary를 사용하여 인증서 및 키를 공유 메모리에 캐시로 저장합니다. 키가 없는 경우 디스크에서 인증서 또는 키를 읽고 캐시에 넣습니다.

캐시를 지우는 위치를 노출할 수도 있습니다. 디스크의 파일이 없데이트되면(예: 인증서 및 키가 갱신됨) shared dictionary는 디스크에서 읽기를 적용합니다. 이 조정을 통해 NGINX 프로세스를 다시 시작할 필요 없이 인증서/키를 순환할 수 있습니다.

http {
     ...
    js_shared_dict_zone zone=kv:1m;
   

    server {
    …
     # Sets an njs function for the variable. Returns a value of cert/key
      js_set $dynamic_ssl_cert main.js_cert;
      js_set $dynamic_ssl_key main.js_key;
   

      # use variable's data
      ssl_certificate data:$dynamic_ssl_cert;
      ssl_certificate_key data:$dynamic_ssl_key;
     

     # a location to clear cache 
   location = /clear {
      js_content main.clear_cache;
      # allow 127.0.0.1;
      # deny all;
    }

  ...
  }

다음은 js_shared_dict_zone을 사용하여 SSL/TLS 인증서 및 키를 교체하는 JavaScript 구현입니다:

function js_cert(r) {
  if (r.variables['ssl_server_name']) {
    return read_cert_or_key(r, '.cert.pem');
  } else {
    return '';
  }
}

function js_key(r) {
  if (r.variables['ssl_server_name']) {
    return read_cert_or_key(r, '.key.pem');
  } else {
    return '';
  }
}
/** 
   * Retrieves the key/cert value from Shared memory or fallback to disk
   */
  function read_cert_or_key(r, fileExtension) {
    let data = '';
    let path = '';
    const zone = 'kv';
    let certName = r.variables.ssl_server_name;
    let prefix =  '/etc/nginx/certs/';
    path = prefix + certName + fileExtension;
    r.log('Resolving ${path}');
    const key = ['certs', path].join(':');
    const cache = zone && ngx.shared && ngx.shared[zone];
   

    if (cache) {
    data = cache.get(key) || '';
    if (data) {
      r.log(`Read ${key} from cache`);
      return data;
    }
  }
  try {
    data = fs.readFileSync(path, 'utf8');
    r.log('Read from cache');
  } catch (e) {
    data = '';
    r.log(`Error reading from file:${path}. Error=${e}`);
  }
  if (cache && data) {
    try {
      cache.set(key, data);
      r.log('Persisted in cache');
    } catch (e) {
      const errMsg = `Error writing to shared dict zone: ${zone}. Error=${e}`;
      r.log(errMsg);
    }
  }
  return data
}

/clear 요청을 보내면 캐시가 무효화되고 NGINX는 다음 SSL/TLS 핸드셰이크에서 디스크에서 SSL/TLS 인증서 또는 키를 로드합니다. 또한 캐시를 유지 및 업데이트하는 동안 요청에서 SSL/TLS 인증서 또는 키를 가져오는 js_content를 구현할 수도 있습니다.

이 예제의 전체 코드는 njs GitHub 리포지토리에서 확인할 수 있습니다.

3. 지금 SSL/TLS 인증서 교체를 시작해보세요.

Shared dictionary 기능은 애플리케이션의 프로그래밍 기능을 위한 강력한 도구로, 간소화 및 확장성 측면에서 상당한 이점을 제공합니다. js_shared_dict_zone의 기능을 활용하면 새로운 성장 기회를 포착하고 증가하는 트래픽 수요를 효율적으로 처리할 수 있습니다.

js_shared_dict_zone으로 NGINX 배포를 강화할 준비가 되셨나요? js_shared_dict_zone으로 NGINX 배포를 업그레이드하여 새로운 사용 사례를 활용하고 이 기능에 대해 자세히 알아보려면 가이드에서 확인하세요. 또한 최근에 소개된 njs-acme 프로젝트에서 shared dictionary 기능의 전체 예제를 확인할 수 있으며, 이를 통해 njs 모듈 런타임이 ACME 공급자와 함께 작동할 수 있습니다.

NGINX 오픈 소스 또는 NGINX Plus를 시작하는 데 관심이 있고, NGINX Plus를 직접 사용해 보시려면 30일 무료 평가판을 신청하거나 NGINX STORE에 연락하여 문의하십시오.

NGINX에 대한 최신 정보들을 빠르게 전달받고 싶으시다면, 아래의 뉴스레터를 구독하세요.