Traefik & ACME 인증서 리졸버
Traefik & ACME 인증서 리졸버 (Traefik & ACME Certificates Resolver)
본문
ACME
구성 예시 (Configuration Example)
아래는 Traefik에서 ACME를 위한 기본 구성의 예시예요.
File (YAML)
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
certificatesResolvers:
myresolver:
acme:
email: [email protected]
storage: acme.json
httpChallenge:
# used during the challenge
entryPoint: web
File (TOML)
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.websecure]
address = ":443"
[certificatesResolvers.myresolver.acme]
email = "[email protected]"
storage = "acme.json"
[certificatesResolvers.myresolver.acme.httpChallenge]
# used during the challenge
entryPoint = "web"
CLI
--entryPoints.web.address=:80
--entryPoints.websecure.address=:443
# ...
--certificatesresolvers.myresolver.acme.email=your-email@example.com
--certificatesresolvers.myresolver.acme.storage=acme.json
# used during the challenge
--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
Helm Chart Values
# Traefik entryPoints configuration for HTTP and HTTPS.
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
certificatesResolvers:
myresolver:
acme:
email: "[email protected]"
storage: "/data/acme.json" # Path to store the certificate information.
httpChallenge:
# Entry point to use during the ACME HTTP-01 challenge.
entryPoint: "web"
구성 옵션 (Configuration Options)
ACME 인증서 리졸버는 다음과 같은 구성 옵션을 가져요.
| Field | Description | Default | Required |
| acme.email | 등록에 사용되는 이메일 주소. | "" | Yes |
| acme.caServer | 사용할 CA 서버. | https://acme-v02.api.letsencrypt.org/directory | No |
| acme.preferredChain | 사용할 선호 체인. CA가 여러 인증서 체인을 제공하면 이 주체 공통 이름(Subject Common Name)과 일치하는 발급자가 있는 체인을 선호해요. 일치하는 것이 없으면 기본 제공 체인이 사용됩니다. | "" | No |
| acme.keyType | 사용할 키 타입. | "RSA4096" | No |
| acme.disableCommonName | CSR에서 공통 이름을 비활성화해요. | false | No |
| acme.profile | 사용할 인증서 프로필. | "" | No |
| acme.caCertificates | 시스템 전역 신뢰 루트 목록의 CA가 아닌 HTTPS 인증서로 ACME 서버를 인증하는 데 사용할 수 있는 PEM 인코딩 CA 인증서의 경로를 지정해요. | [] | No |
| acme.caSystemCertPool | 인증서 풀이 시스템 인증서 풀의 복사본을 사용해야 하는지 여부를 정의해요. | false | No |
| acme.caServerName | 시스템 전역 신뢰 루트 목록의 CA가 아닌 HTTPS 인증서로 ACME 서버를 인증하는 데 사용할 수 있는 CA 서버 이름을 지정해요. | "" | No |
| acme.emailAddresses | 사용할 CSR 이메일 주소. | [] | No |
| acme.eab | 외부 계정 바인딩(External Account Binding)을 활성화해요. | | No |
| acme.eab.kid | 외부 CA의 키 식별자. | "" | No |
| acme.eab.hmacEncoded | 외부 CA의 HMAC 키. 패딩 없는 Base64 URL 인코딩 형식이어야 해요. | "" | No |
| acme.certificatesDuration | 인증서의 기간(시간). 갱신 날짜를 결정하는 데만 사용돼요. | 2160 | No |
| acme.clientTimeout | ACME 서버와 통신하는 데 사용되는 HTTP 클라이언트의 타임아웃. | 2m | No |
| acme.clientResponseHeaderTimeout | ACME 서버와 통신하는 데 사용되는 HTTP 클라이언트의 응답 헤더 타임아웃. | 30s | No |
| acme.certificateTimeout | finalization 요청 중 인증서 획득 타임아웃. ACME 서버가 인증서 발급에 느린 경우 설정하세요. | 30s | No |
| acme.dnsChallenge | DNS-01 챌린지를 활성화해요. 자세한 내용은 여기. | - | No |
| acme.dnsChallenge.provider | 사용할 DNS 프로바이더. | "" | No |
| acme.dnsChallenge.resolvers | FQDN 권위(authority)를 해석할 DNS 서버. | [] | No |
| acme.dnsChallenge.propagation.delayBeforeChecks | 기본적으로 프로바이더는 ACME가 검증하기 전에 TXT DNS 챌린지 레코드를 확인해요. delayBeforeCheck가 0보다 크면 이 확인이 구성된 기간(초)만큼 지연됩니다. 내부 네트워크가 외부 DNS 쿼리를 차단하는 경우 유용합니다. | 0s | No |
| acme.dnsChallenge.propagation.disableChecks | DNS 챌린지가 준비되었음을 ACME에 알리기 전에 챌린지 TXT 레코드 전파 확인을 비활성화해요. 확인 비활성화는 챌린지가 성공하지 못하게 할 수 있다는 점을 유의하세요. | false | No |
| acme.dnsChallenge.propagation.requireAllRNS | 챌린지 TXT 레코드를 모든 재귀 네임서버에 전파하도록 해요. 권위 네임서버 확인을 비활성화한 경우(propagation.disableANSChecks로), 대신 모든 재귀 네임서버를 확인하는 것이 권장됩니다. | false | No |
| acme.dnsChallenge.propagation.disableANSChecks | 권위 네임서버에 대한 챌린지 TXT 레코드 전파 확인을 비활성화해요. 이 옵션은 권위(SOA) 네임서버에 대한 전파 확인을 건너뜁니다. 권위 네임서버에 도달할 수 없는 경우에만 사용해야 해요. | false | No |
| acme.httpChallenge | HTTP-01 챌린지를 활성화해요. 자세한 내용은 여기. | | No |
| acme.httpChallenge.entryPoint | HTTP-01 챌린지에 사용할 엔트리포인트. Let's Encrypt가 포트 80으로 도달할 수 있어야 해요. | "" | Yes |
| acme.httpChallenge.delay | 챌린지 생성과 검증 사이의 지연. 0 이하 값은 지연 없음을 의미해요. | 0 | No |
| acme.tlsChallenge | TLS-ALPN-01 챌린지를 활성화해요. Traefik은 Let's Encrypt가 포트 443으로 도달할 수 있어야 해요. 자세한 내용은 여기. | - | No |
| acme.tlschallenge.delay | 챌린지 생성과 검증 사이의 지연. 0 이하 값은 지연 없음을 의미해요. | 0 | No |
| acme.storage | 인증서 저장에 사용되는 파일 경로. | "acme.json" | Yes |
자동 인증서 갱신 (Automatic Certificate Renewal)
Traefik은 생성하는 인증서의 만료일을 자동으로 추적해요. 더 이상 사용되지 않는 인증서도 갱신될 수 있는데, Traefik은 현재 갱신 전에 인증서가 사용 중인지 확인하지 않기 때문이에요.
기본적으로 Traefik은 90일 인증서를 관리하고 만료 30일 전에 갱신을 시작해요. 커스텀 기간의 인증서를 발급하는 인증서 리졸버를 사용할 때는 certificatesDuration 옵션으로 인증서 기간을 구성할 수 있어요.
참고 (Note)
더 이상 사용되지 않는 인증서도 갱신될 수 있는데, Traefik은 현재 갱신 전에 인증서가 사용 중인지 확인하지 않기 때문이에요.
다양한 ACME 챌린지 (The Different ACME Challenges)
dnsChallenge
DNS 레코드를 프로비저닝하여 ACME 인증서를 생성·갱신하는 DNS-01 챌린지예요.
Traefik은 내부적으로 ACME를 위해 Lego에 의존해요. 지원되는 모든 DNS 프로바이더의 목록은 그들의 문서에서 찾을 수 있고, 어떤 환경 변수를 설정해야 하는지에 대한 지침도 함께 제공돼요.
참고 (Note)
CNAME은 지원되며 권장되기까지 해요.
필요하다면 다음 환경 변수로 CNAME 지원을 끌 수 있어요.
LEGO_DISABLE_CNAME_SUPPORT=true
여러 DNS 챌린지
여러 DNS 챌린지 프로바이더는 Traefik에서 지원되지 않지만, CNAME으로 처리할 수 있어요. 예를 들어 example.org(계정 foo)와 example.com(계정 bar)이 있다면, challenge.example.com을 가리키는 _acme-challenge.example.org라는 CNAME을 example.org에 만들 수 있어요. 이렇게 하면 bar 계정으로 example.org의 인증서를 얻을 수 있습니다.
delayBeforeChecks
기본적으로 provider는 ACME가 검증하기 전에 TXT 레코드를 확인해요. delayBeforeChecks로 지연(초)을 지정해 이 작업을 늦출 수 있어요(값은 0보다 커야 함). 이 옵션은 내부 네트워크가 외부 DNS 쿼리를 차단할 때 유용합니다.
tlsChallenge
TLS 인증서를 프로비저닝하여 ACME 인증서를 생성·갱신하는 TLS-ALPN-01 챌린지를 사용해요.
Let's Encrypt 커뮤니티 포럼에서 설명한 대로, TLS-ALPN-01 챌린지를 사용할 때 Traefik은 Let's Encrypt가 포트 443으로 도달할 수 있어야 해요.
tlsChallenge 구성하기
File (YAML)
certificatesResolvers:
myresolver:
acme:
# ...
tlsChallenge: {}
File (TOML)
[certificatesResolvers.myresolver.acme]
# ...
[certificatesResolvers.myresolver.acme.tlsChallenge]
CLI
# ...
--certificatesresolvers.myresolver.acme.tlschallenge=true
httpChallenge
잘 알려진 URI 아래에 HTTP 리소스를 프로비저닝하여 ACME 인증서를 생성·갱신하는 HTTP-01 챌린지를 사용해요.
Let's Encrypt 커뮤니티 포럼에서 설명한 대로, HTTP-01 챌린지를 사용할 때 certificatesresolvers.myresolver.acme.httpchallenge.entrypoint는 Let's Encrypt가 포트 80으로 도달할 수 있어야 해요.
httpChallenge에 web이라는 엔트리포인트 사용하기
File (YAML)
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
certificatesResolvers:
myresolver:
acme:
# ...
httpChallenge:
entryPoint: web
File (TOML)
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.websecure]
address = ":443"
[certificatesResolvers.myresolver.acme]
# ...
[certificatesResolvers.myresolver.acme.httpChallenge]
entryPoint = "web"
CLI
--entryPoints.web.address=:80
--entryPoints.websecure.address=:443
# ...
--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
리다이렉션은 HTTP-01 챌린지와 완전히 호환돼요.
도메인 정의 (Domain Definition)
인증서 리졸버는 라우터에서 추론한 도메인 이름 집합에 대해 인증서를 요청하는데, 그 규칙은 다음과 같아요.
- IngressRoute에 tls.domains 옵션이 설정되어 있으면, 인증서 리졸버는 tls.domains의 main 옵션에서 이 라우터의 도메인 이름을 파생합니다.
- 그렇지 않으면 인증서 리졸버는 IngressRoute의 규칙에서 Host() 또는 HostSNI() 매처에서 도메인 이름을 파생합니다.
각 메인 도메인에 대해 SAN(대체 도메인)을 설정할 수 있어요. 모든 도메인은 Traefik을 가리키는 A/AAAA 레코드가 있어야 해요. 각 도메인과 SAN은 인증서 요청으로 이어집니다.
ACME v2는 와일드카드 인증서를 지원해요. Let's Encrypt의 게시물에서 설명한 대로 와일드카드 인증서는 DNS-01 챌린지를 통해서만 생성할 수 있어요. 도메인에 대해 이중 와일드카드 인증서(예: *.*.local.com)를 요청하는 것은 불가능해요.
대부분 루트 도메인도 인증서를 받아야 하므로 SAN으로 지정해야 하고, 그러면 2개의 DNS-01 챌린지가 호출됩니다. 이런 경우 두 도메인에 대해 생성되는 DNS TXT 레코드는 동일해요. 이 동작은 DNS RFC를 준수하지만, 모든 DNS 프로바이더가 일정 시간(TTL) 동안 DNS 레코드를 캐시하고 이 TTL이 챌린지 타임아웃보다 커서 DNS-01 챌린지가 실패할 수 있기 때문에 문제가 될 수 있어요.
Traefik ACME 클라이언트 라이브러리 lego는 이 문제를 해결하기 위해 일부 DNS 프로바이더를 지원해요. 지원되는 provider 표는 와일드카드 도메인과 그 루트 도메인에 대한 인증서 생성이 허용되는지 여부를 나타냅니다.
와일드카드 도메인 (Wildcard Domains)
ACME V2는 와일드카드 인증서를 지원해요. Let's Encrypt의 게시물에서 설명한 대로 와일드카드 인증서는 DNS-01 챌린지를 통해서만 생성할 수 있어요.
외부 계정 바인딩 (External Account Binding)
- kid: 외부 CA의 키 식별자
- hmacEncoded: 외부 CA의 HMAC 키, 패딩 없는 Base64 URL 인코딩 형식이어야 해요
File (YAML)
certificatesResolvers:
myresolver:
acme:
# ...
eab:
kid: abc-keyID-xyz
hmacEncoded: abc-hmac-xyz
File (TOML)
[certificatesResolvers.myresolver.acme]
# ...
[certificatesResolvers.myresolver.acme.eab]
kid = "abc-keyID-xyz"
hmacEncoded = "abc-hmac-xyz"
CLI
# ...
--certificatesresolvers.myresolver.acme.eab.kid=abc-keyID-xyz
--certificatesresolvers.myresolver.acme.eab.hmacencoded=abc-hmac-xyz
Kubernetes에서 LetsEncrypt 사용하기 (Using LetsEncrypt with Kubernetes)
Kubernetes에서 LetsEncrypt를 사용할 때 Ingress 및 CRD 프로바이더 모두에 알려진 몇 가지 주의 사항이 있어요.
참고 (Note)
LetsEncrypt와 함께 여러 Traefik 인스턴스를 실행하려는 경우, 해당 프로바이더 페이지의 섹션을 반드시 읽어 주세요.
Ingress 프로바이더의 LetsEncrypt 지원 (LetsEncrypt Support with the Ingress Provider)
설계상 Traefik은 상태가 없는(stateless) 애플리케이션이에요. 즉 자신이 실행되는 환경에서만 구성을 파생하며 추가 구성이 필요하지 않습니다. 이런 이유로 사용자들은 HA를 달성하기 위해 Traefik의 여러 인스턴스를 동시에 실행할 수 있는데, 이는 kubernetes 생태계에서 흔한 패턴이에요.
단일 Traefik Proxy 인스턴스를 Let's Encrypt와 함께 사용하면 문제가 없어야 해요. 그러나 이는 단일 실패 지점이 될 수 있어요. 안타깝게도 Let's Encrypt를 활성화한 채 Traefik 2.0의 여러 인스턴스를 실행하는 것은 불가능한데, 올바른 Traefik 인스턴스가 챌린지 요청과 후속 응답을 받도록 보장할 방법이 없기 때문이에요. 초기 버전(v1.x)의 Traefik은 KV store를 사용해 이를 달성하려 했지만, 최적이 아닌 성능 때문에 그 기능은 2.0에서 제거되었습니다.
Kubernetes 환경에서 고가용성을 갖춘 Let's Encrypt가 필요하다면, 분산형 Let's Encrypt를 지원 기능으로 포함하는 Traefik Enterprise 사용을 권장해요.
Traefik Proxy를 계속 사용하고 싶다면, Cert-Manager와 같은 인증서 컨트롤러를 사용해 LetsEncrypt HA를 달성할 수 있어요. Cert-Manager로 인증서를 관리하면 네임스페이스에 시크릿을 생성하며, 이를 ingress 객체에서 TLS 시크릿으로 참조할 수 있습니다.
폴백 (Fallback)
Let's Encrypt에 도달할 수 없다면 다음 인증서가 적용됩니다.
- 이전에 생성된 ACME 인증서(다운타임 이전)
- 만료된 ACME 인증서
- 제공된 인증서
중요 (Important)
Let's Encrypt 인증이 필요한 새 (서브)도메인의 경우, Traefik을 다시 시작할 때까지 기본 Traefik 인증서가 사용됩니다.
프로덕션에서 Traefik OSS를 사용하고 계신가요?
직장에서 Traefik을 사용하고 있다면 기업용 API 게이트웨이 기능이나 Traefik OSS에 대한 상용 지원을 고려해 보세요.
- API 게이트웨이 데모 영상 보기
- 24/7/365 OSS 지원 요청하기
Traefik OSS에 API 게이트웨이 기능을 추가하는 일은 빠르고 매끄러워요. 교체(rip and replace)가 필요 없고 모든 구성이 그대로 유지됩니다. 이 짧은 영상에서 실제 동작을 확인해 보세요.