[NAS 구축] 7. WebDAV에 Let’s Encrypt SSL 인증서 적용

이 글은 Let’s Encrypt 인증서와 AWS Route 53 DNS 서비스를 바탕으로 한다.
AWS에 등록된 도메인을 활용하여 iptime의 DDNS에 연결된 NAS에 SSL 인증을 해보았다.

필자의 집에는 iptime에 연결되어있는 NAS가 있어서 iptime에서 자체적으로 제공해주는 DDNS(iptime.org)로 SSL 인증을 하려고 했었다.
그런데 알고보니 나같이 iptime.org를 통해 SSL 인증서를 발급하려는 사람들이 부지기수였다.
이에 Let’s Encrypt에서는 iptime.org를 통한 인증을 일시적으로 금지하였다. (동일 도메인에서의 잦은 신청으로 인한 것 같다)
한마디로 못써먹는다는 이야기다.

이에 AWS Route 53에서 별도로 도메인과 DNS를 설정하였다.
비용은 한달에 $1정도 했던 것으로 기억한다.
문제는 내가 도메인을 사든 말든 내 NAS는 유동 ip가 부여된 iptime에 연결되어있다는 점이다.
이에 Route 53의 DNS에 iptime DDNS를 연결하여 Route 53 (DNS) -> iptime.org (DDNS) -> NAS의 구조로 네트워크를 연결하기로 했다.

SSL 인증을 위해서는 Webroot, Standalone, DNS 중 한 가지 방법으로 SSL Challenge를 수행해야 한다.
문제는 SSL Challenge는 반드시 80(HTTP)과 443(HTTPS) 포트로 수행되어야 한다는 점인데,
Webroot나 Standalone의 경우 인증하는 경우 외부에서 80과 443을 경유해 NAS로 접속할 수 없기 때문에 인증이 불가능하다.
결국 남은 선택지는 DNS 인증밖에 없다.
DNS 인증은 SSL Challenge를 NAS에서가 아니라 DNS 서버에서 수행하는 방법이다.
하지만 DNS 인증은 인증서 갱신을 수동으로 해주어야 한다는 단점이 있다.
다행히 Let’s Encrypt는 필자가 사용하는 Route 53에 대해 플러그인을 제공하기때문에 이를 사용하기로 하였다.

참고로 Certbot은 Route 53뿐만 아니라 다른 DNS들에 대해서도 플러그인을 지원한다. (물론 직접 설치해야 한다)
아래는 공식 홈페이지에서 제공하는 플러그인 명단이다.

순서는 다음과 같다.

  • DNS에 DDNS를 CNAME으로 등록
  • Certbot 설치
  • DNS를 통한 SSL Challenge 수행
  • Route 53 플러그인을 통한 인증서 자동갱신 설정
  • 웹서버에 SSL 인증서 등록
  • HTTPS Redirection
  • WebDAV에 SSL 적용

1. DDNS를 CNAME으로 등록

iptime에서 DDNS를 등록하고, 아래의 그림과 같이 DDNS를 원하는 도메인 네임에 CNAME으로 등록한다.
DDNS 등록법은 구글에서 찾아보시라. 어렵지 않다.

2. Certbot 설치

공식 홈페이지에서 안내하는 방법을 그대로 따른다.
공식 홈페이지에서는 스냅크래프트(snapcraft)를 통한 패키지 관리를 추천하기 때문에 필자도 snapd를 먼저 설치한 후, certbot을 설치하였다.

$ sudo yum install snapd
$ sudo systemctl enable --now snapd.socket
$ sudo ln -s /var/lib/snapd/snap /snap

$ sudo snap install core
$ sudo snap refresh core
$ sudo snap install --classic certbot

3. SSL Challenge 수행

Webroot나 Standalone 모드에서의 Challenge는 certbot에서 자동으로 수행되지만
SSL Challenge는 사용자가 직접 DNS에 Challenge용 Record(TXT)를 등록한 후에야 수행된다.
아래는 certbot을 이용해 SSL Challenge를 수행하는 커맨드이다.

참고로 DNS Challenge 방식의 경우 와일드카드 인증서 또한 발급받을 수 있다. [Announcement]
필자 또한 와일드카드 인증서를 발급받아 사용하였다.
단, 이 경우 인증서의 유효기간은 3달이다.

$ certbot certonly --manual \
--preferred-challenges dns \
--server https://acme-v02.api.letsencrypt.org/directory \
--agree-tos -m <E-mail@add.ress> \
-d <Doname.Name>

위 과정에서 다음과 같은 결과가 나오는데

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for hooni-playground.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.hooni-playground.com with the following value:

XkssY0v8Oma1WjR4j7-CWK3T8ceDP9ew_gqqs-h2QSs

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

다음과 같이 _acme-challenge.<Domain.name>.com의 내용을 DNS의 TXT 레코드로 넣어주면 된다.

이 이미지는 대체 속성이 비어있습니다. 그 파일 이름은 image-8-1024x437.png입니다.

그 이후 계속 인증을 진행하면 된다.
방화벽 등에 문제가 없다면 다음과 같이 인증이 잘 되어있을 것이다.

Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/hooni-playground.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/hooni-playground.com/privkey.pem
   Your cert will expire on 2022-05-08. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

이후의 내용은 크게 어렵지 않으나 글 작성할 시간이 부족해 우선은 최하단의 링크들로 대체한다.
링크들을 보며 따라하면 쉽게 SSL 인증서를 웹서버에 등록하여 WebDAV를 https로 서비스할 수 있다.

4. 인증서 자동갱신 설정

앞서 말했듯 DNS 인증은 자동으로 갱신할 수 없다.

$ Could not choose appropriate plugin: The manual plugin is not working; there may be problems with your existing configuration.
$ The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.',)

하지만 Let’s Encrypt는 AWS Route 53 플러그인을 통해 인증서를 자동으로 갱신할 수 있도록 해준다.
이 방법은 필자도 블로그에서 알게 되었는데 본인의 환경에 따라 플러그인 설치 방법이 다르니 주의할 것.
위 블로그에서는 virtualenv를 사용하지만, 필자의 경우는 python3.6을 사용해야 했다.
(참고로, 이전 버전의 certbot은 악랄하게 python2.7을 쓰고있어서 패키지(pyOpenSSL) 버전 레거시때문에 더 이상 진행이 불가능했다. 혹시 비슷한 경험을 하게된다면 certbot 버전을 업그레이드하자)

$ vim /var/log/letsencrypt/letsencrypt.log
Traceback (most recent call last):
  File "/usr/local/bin/certbot", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.6/site-packages/certbot/main.py", line 15, in main
    return internal_main.main(cli_args)
  File "/usr/local/lib/python3.6/site-packages/certbot/_internal/main.py", line 1362, in main
    return config.func(config, plugins)
  File "/usr/local/lib/python3.6/site-packages/certbot/_internal/main.py", line 1267, in renew
    renewal.handle_renewal_request(config)
  File "/usr/local/lib/python3.6/site-packages/certbot/_internal/renewal.py", line 497, in handle_renewal_request
    len(renew_failures), len(parse_failures)))
certbot.errors.Error: 1 renew failure(s), 0 parse failure(s)
2020-10-18 05:30:37,652:ERROR:certbot._internal.log:1 renew failure(s), 0 parse failure(s)

이제 아래와 같이 python3.6을 통해 Route 53 플러그인을 설치하고 SSL 인증을 수행해보자
그러면 에러를… 목격하게 될 것이다…

$ pip3 install certbot-dns-route53
$ certbot renew --dns-route53

이는 이 블로그에서 설명되었듯 AWS의 IAM(Identify and Access Management) 때문이다.
AWS로 가서 계정의 보안 자격 증명 서비스에서 IAM 액세스 키를 발급받자.

그 후, NAS에서 awscli를 통해 IAM 액세스 키 ID보안 엑세스 키를 등록하면 된다.

$ sudo yum install awscli
$ sudo aws configure

위의 설정들이 잘 적용되었는지 dry-run을 통해 확인해보자.
Congratulations, all renewals succeeded. 가 나오면 성공한 것이다.

$ certbot renew --dns-route53 --dry-run

이제 crontab을 통해 인증서를 자동갱신하도록 설정해보자.
예를 들어 다음과 같은 방법으로 짝수달의 15일 새벽 4시마다 인증서를 갱신하고 웹서버를 재시작할 수 있다.
본인의 인증 프로그램이나 경로, OS, 웹서버에 맞추어 수정해 사용하면 된다.

$ sudo crontab -e
> 0 4 15 */2 * certbot renew --dns-route53 --renew-hook="sudo service httpd restart"

필자는 와일드카드 인증서를 사용하기에 매주 일요일 새벽 4시에 인증서를 갱신하도록 하였다.

$ sudo crontab -e
> 0 4 * * 0 certbot renew --dns-route53 --renew-hook="sudo service httpd restart"

5. WebDAV에 SSL 적용

WebDAV 설정파일에 SSL 인증서를 등록해야 한다.
SSL 인증서의 위치는 3장의 certbot 결과화면에서 확인할 수 있다.
conf 파일에 다음과 같이 https를 listen하는 내용을 넣어준다.
필자는 /etc/httpd/conf.d/webdav.conf를 만들어 사용중이다.

<VirtualHost *:443>
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/<Domain>/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/<Domain>/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/<Domain>/fullchain.pem
</VirtualHost>

6. 윈도우에서의 WebDAV 접근 이슈

윈도우는 WebDAV 접근 시 https 트래픽만을 허용한다.
레지스트리를 수정하여 http를 사용하도록 할 수도 있으나 NAS에 I/O하는 기능인 이상 https를 사용하는 것이 여러모로 안전하다.

다만 그 밖에도 윈도우에서는 WebDAV 사용 시 최대 약 50MB정도의 단일 파일에만 접근할 수 있다.
이런 터무니없는 크기는 반드시 조정해주어야 한다.
레지스트리 편집기에서 다음 경로에 있는 FileAttributesLimitInBytes를 0xffffffff(약 4.2GB)로 수정한다.
(WebDAV 특성상 약 4GB보다 큰 파일을 다룰 수 없다.)

HKEY_LOCAL_MACHINE > SYSTEM > CurrentControlSet > services > WebClient > Parameters

이제 WebDAV를 즐기면 된다.

Series Navigation<< [NAS 구축] 6. WebDAV 설치[NAS 구축] 8. HAProxy를 이용한 포트 도메인네임 매핑 >>

댓글 남기기