본문 바로가기
Infra

[Nginx] Nginx에 SSL를 적용해보자(SSL 개념)

by 진꿈청 2024. 3. 17.

이번 포스팅에서는 Nginx에 SSL 인증서를 적용해보는 법을 알아보려 한다.

 

우선 시작하기에 앞서 SSL/TLS는 뭘까?

 

SSL/TLS

SSL(Secure Socket Layer) 또는 TLS(Transport Layer Security)은 전송계층 상에서

클라이언트, 서버에 관한 인증 및 데이터 암호화를 수행한다.

 

즉, 클라이언트와 서버 양단 간 응용계층 및 TCP 전송계층 사이에서 안전한 보안 채널을 형성해주는 역할을 하는 보안용 프로토콜이다.


이 둘은 보통 버전의 차이이며, 보통 SSL이라 통칭한다.(엄밀히 말하면 SSL을 좀 더 정교한게 만든 것이 TLS 라고 한다.)

 

기본적으로 HTTP/2 프로토콜을 통해 동작한다.

 

  • 응용계층 및 전송계층 사이에 위치하나 전송계층 보다 응용계층에 밀접하게 동작한다.
  • 운반용 프로토콜: TCP 또는 UDP
  • 사용 포트: HTTPS의 경우, HTTP를 위한 SSL/TLS 보안 터널 형성을 위해, 443 포트 사용
  • 주요 기능: 상호 인증, 메시지 인증 (메시지 무결성), 메시지 압축(디폴트 Null), 암호화용 세션 키 생성을 위한 키 교환 등

HTTPS(HyperText Transfer Protocol Over SSL)은 SSL을 적용한 HTTP로 보안을 강화한 전송 기능이다.

그래서 SSL 인증서가 적용이 된 도메인만이 https:// 주소를 가질 수 있다.

 

그렇다면 SSL 기반의 보안 연결에서 인증서는 정확히 어떻게 사용이 되는 것일까?

 

인증서의 사용 이유

우선, 인증서를 쓰는 이유는 무엇일까?

 

만약 네트워크 데이터가 암호화된다면, 중간에 공격자가 패킷을 열람하더라도 데이터가 유출되는 것을 막을 수 있다.

이때, 오늘날 가장 널리 쓰이고 있는 암호화 방식인 SSL/TLS1가 사용이 된다.

이 방식은 언급했듯 '인증서' 라고 하는 일종의 서명을 사용한다.

인증서라는 것은 결국 '당신이 신뢰할 수 있는 사람이냐' 라는 것을 확인하기 위한 용도이며
이것이 패킷 데이터를 암호화하기 위한 첫 단계라고 생각하면 된다. 

 

인증서가 신뢰할 수 있다는 검증 작업을 거치면 비로소 데이터 암호화 작업이 수행된다.

그 과정이 SSL 보안 통신이라고 불리는 것이며, 이론상 이를 해독하는 것이 거의 불가능하다.
우리가 흔히 사용하고 있는 (그렇지만 잘 인지하지 못하고 있는) 보안 연결은 다름아닌 웹 브라우저 <-> 웹 사이트 간 연결이다.

 

이때, 이 인증서에 관한 검증을 도와주는 CA(공인된 제 3자, 관공서라고 생각하면 됨)의 도움을 받는다.

(서버와 클라이언트가 직접 소통을 했을 때 중간자가 그냥 발신쪽의 공개키로 열어버리고 메시지를 수정하면 원하는 전송이 안된다)

 

CA

CA는 공인된 제 3자로 CA의 공개키는 우리가 사용하는 웹 브라우저(크롬, 파이어폭스), 키 체인에 이미 등록되어 있다.

따라서, 서버는 자신의 공개키를 CA의 비밀키로 암호화하는 방식으로 CA를 활용한다.

 

그렇다면 최종적인 SSL의 통신 방식은?

  1. 클라이언트가 서버를 건드린다.(Handshaking)
    이때 클라이언트는 아무 값(nonce)이나 써서 보내면서 자기가 암호화 할 수 있는 방법들을 나열하여 보낸다.

  2. 서버는 응답을 해준다.(Handshaking)
    이때 서버도 아무 값(nonce)이나 써서 보내면서 클라이언트가 보낸 방법중에 서버도 가능한 방법중 하나를 선택해서 써서 보낸다.
    그리고 CA가 준 인증서(서버의 공개키를 CA의 비밀키로 암호화)도 같이 보내준다.

  3. 클라이언트는 서버가 준 인증서를 CA의 공개키를 이용해서 뜯어본다.
    모든 웹브라우저는 CA의 공개키를 이미 갖고있기때문에 제대로 열리는지 확인한다.
    만약에 서버가 준 인증서가 CA가 만든 인증서가 아니면 브라우저는 이거 CA것이 아니라면서 시뻘겋게 경고를 보여준다.
    만약에 CA의 공개키로 인증서가 제대로 열렸다면, 일단 서버가 믿을만한 곳이라는것을 알 수 있다.

  4. 클라이언트가 클라이언트에서 만들었던 아무값이랑 서버에서 만들어준 아무값을 조합해서
    대칭키 방식으로 PMS(Pre Master Secret) 값을 만든다.

  5. 클라이언트는 만들어놓은 PMS(Pre Master Secret)값을 서버가 준 공개키를 이용해서 암호화해서 보낸다.
    그럼 서버는 이것을 비밀키로 열어볼 수 있다.

  6. 서버는 클라이언트가 준 PMS(Pre Master Secret)값을 열어본다.

  7. 클라이언트와 서버는 PMS(Pre Master Secret)값을 Master Secret값으로 바꾼다.

  8. Master Secret값으로 한번 더 session key를 만든다.

  9. session key를 이용해서 대칭키 방식으로 암호화하고 주고 이제 클라이언트와 서버는 실제로 값을 주고 받는다.

 

서버와 클라이언트는 대칭키 방식으로 암호화해서 통신하는게 가장 편하다.
근데, 특정 대칭키로 고정해버리면 언젠가는 대칭키가 유출 될 수 있다.

그래서, 클라이언트가 일단 서버를 믿도록 하기 위해 CA를 이용한다.

그 후, 클라이언트와 서버 둘이서만 대칭키를 그때 그때 만들어 안전하게 전해주는 것이다.

 

여기까지 SSL 및 인증서 사용에 대해 알아보았다. 

본격적으로 nginx를 통해 SSL를 적용해보자.

 

필자는 AWS EC2 및 Duck DNS를 활용하였다.

Duck DNS에 관하여 참조 블로그를 확인 바란다.

Let's Encrypt

Let’s Encrypt는 무료로 TLS 인증서를 발급해주는 비영리기관이다. 
무료인 대신 만료기한이 90일로 주기적으로 재발급해야 한다.

 

위 Let's Encrypt를 사용하기 위해서 CertBot을 설치해보자.

 

CertBot

CertBot은 Let’s Encrypt 인증서를 사용하여 HTTPS를 적용할 수 있게 하는 오픈 소스툴이다.

 

sudo apt-get update
sudo apt-get install python3-certbot-nginx # certbot 설치
certbot certonly --nginx -d example.com
  • certonly: certbot 명령어로 인증서를 다운받고, 설치할 수 있다.
  • --nginx: 해당 도메인에 대한 소유주가 자신임을 인증하기 위해 이용할 플러그인이다.
    • nginx에 대한 인증서 취득 및 설치가 자동으로 이루어진다.

Nginx 설정

설정 방법은 여러개다.

  • sites-available
  • sites-enable
  • conf.d(해당 디렉토리를 이용하여 conf 파일 작성)

우선 메인 설정 파일을 확인해보자

cd /etc/nginx
vim nginx.conf

 

 

확인해보면,

/etc/nginx/conf.d 아래에 있는 모든 .conf 파일과 /etc/nginx/sites-enabled의 모든 파일들을 include한다.

 

여기서 중요한 점은

  1. conf.d 디렉토리에 conf 파일은 작성만 하면 된다.
  2. sites-available 디렉토리에 작성하면, 아래 명령어를 통해 심볼릭 링크를 만들어준다.
sudo nginx -t    # 문법 확인
sudo ln -s /etc/nginx/sites-available/test.conf /etc/nginx/sites-enabled

 

필자는 그냥 conf 파일만 작성하는 방식을 택했다.

 

 

conf 파일

# 1)
server {
  listen 80; # 80포트로 받을 때
  server_name example.com; # 도메인주소
  return 301 https://example.com$request_uri;

}

# 2)
server {
  listen 443 ssl http2;
  server_name example.com;

  # ssl 인증서 적용하기
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  
  root /usr/share/nginx/html;

  location / { # location 이후 특정 url을 처리하는 방법을 정의(여기서는 / -> 즉, 모든 request)
    try_files $uri $uri/ =404;
  }
}

# 3)
server {
    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

  listen 80;
  server_name example.com;
    return 404; # managed by Certbot
}
  • example.com에는 자신의 도메인 주소를 입력한다.
  • location에는 원래 백엔드 서버를 두면 좋겠지만 필자는 https 연동 테스트만을 위해 그냥 nginx 기본 html을 출력하도록 했다.

위의 conf 파일을 간략히 설명하자면

1) 80포트로 들어오는 요청 즉, http로 들어오는 모든 요청을 https로 리다이렉션을 한다.

  • $request_uri: 요청 주소

2) location 블록에서 자주 사용 되는 설정들

  • proxy_pass : 프록시 주소, 백엔드 운영 서버 ip를 넣어준다.
  • proxy_set_header Host $http_host : HTTP Request의 Host 헤더 값, 클라이언트가 요청한 원래 호스트 주소
  • X-Real-IP $remote_addr: 실제 방문자의 원격 ip 주소
  • X-Forwarded-For $proxy_add_x_forwared_for : 클라이언트가 프록시 처리한 모든 서버의 IP 주소를 포함하는 목록
  • X-forwarded-Proto $scheme : HTTP의 구조로 http or https를 의미한다.
    HTTPS 서버 블록 내에서 사용할 경우 프록시 서버의 HTTP 응답이 HTTPS로 변환된다.

3) 요청 주소가 다르면 404 에러 처리를 한다.

 

 

설정을 성공적으로 마쳤다면 Nginx를 재시작해주자.

sudo service nginx restart

 

AWS를 사용한다면 관련 포트도 열어주어야 한다.

EC2 -> 보안 -> 인바운드 규칙

 

결과

 

 

AWS Route53과 CertBot 활용의 차이점(참고)

HTTPS를 적용하기 위해 검색을 해보면 심심치 않게 AWS Route53에 관한 내용을 확인할 수 있다.

 

예를 들어 가비아에서 도메인을 구입하고 Route53을 사용한다면 ACM(AWS Certificate Manager)를 활용하여 인증서를 만든 뒤

Route53에서 DNS 레코드를 설정 및 관리하는 작업을 해야 한다.

둘의 차이점을 내가 알아보고 정리한건 다음과 같다. 참고로만 알아보자.

 

AWS 사용 시

  • 인증서 발급과 관리
    • AWS Certificate Manager(ACM)을 사용하여 SSL/TLS 인증서를 발급받고 관리할 수 있다.
    • 이 인증서는 AWS에서 제공하는 서비스(예: Elastic Load Balancer, Amazon CloudFront 등)와 직접 통합되어 사용이 가능하다.
  • DNS 관리
    • Amazon Route 53을 사용하여 DNS를 관리할 수 있다.
      Route 53을 사용하면 AWS의 다른 서비스와의 연동이 용이하며, DNS 설정을 통해 트래픽을 AWS 인프라로 유도할 수 있다.
  • 일관된 환경
    • AWS 내에서 인증서 발급부터 DNS 관리, 그리고 다른 AWS 서비스와의 통합까지 모든 것을 일관된 환경에서 할 수 있다.


Certbot 사용 시

  • 인증서 설치
    • 인증서를 서버에 직접 설치하므로, 서버 설정에 좀 더 유연하게 대응할 수 있다.
  • DNS 확인
    • Certbot을 사용하는 경우, 도메인의 소유권 검증을 위해 DNS 레코드를 확인한다.
    • 이 과정에서 가비아와 같은 도메인 등록 기관에서 관리하는 네임서버 설정이 올바르게 되어 있어야 한다.
    • 도메인이 가리키는 IP 주소가 실제 서버의 IP와 일치하면, 도메인 소유권 검증이 이루어지고 인증서 발급이 진행된다.
  • 독립적 관리
    • 인증서 발급과 DNS 관리가 별도로 이루어진다.
    • 따라서 AWS와 같은 일관된 환경에서의 통합 관리보다는 각각을 독립적으로 관리해야 한다.

즉, AWS를 사용하는 경우는 AWS 서비스 간의 일관된 사용과 통합 관리의 이점이 있으며,
Certbot을 사용하는 경우는 서버에 직접 인증서를 설치하고 관리하는 유연성이 있다. 

 

비슷하게

 

AWS에서 인증서 발급을 한 후 네임서버를 가비아에 등록하게 되면,
AWS의 다른 서비스와의 일관된 사용이 가능해서 좋다.

Certbot을 사용한 방법은 서버에 직접 인증서를 설치하고 가비아의 네임 서버를 확인하며
나아가다가 IP가 등록한 서버와 같다면 인증이 된다.

 



참고 블로그

https://velog.io/@lgj9172/HTTPS-SSL-CA-%EC%9D%B8%EC%A6%9D%EC%84%9C-%EC%A7%81%EA%B4%80%EC%A0%81%EC%9D%B8-%EA%B0%9C%EB%85%90

 

HTTPS, SSL, CA, 인증서 직관적인 개념

웹 사이트를 배포할 일이 생겼는데, HTTPS로 배포해야 했다.기존에 HTTPS와 SSL 개념에 대해 잘 몰랐기 때문에 한번 정리가 필요했다.어떤 내용을 암호화하고 다시 복구하는 복호화를 하려면 크게

velog.io

https://m.blog.naver.com/alice_k106/221468341565

 

154. [Security] SSL과 인증서 구조 이해하기 : CA (Certificate Authority) 를 중심으로

이번 포스트에서는 인증서의 구조와 동작 원리에 대해 알아보고, 이것이 실제 SSL 기반의 보안 연결에서...

blog.naver.com

https://velog.io/@yedamhy/AWS-%EC%99%B8%EB%B6%80%EB%8F%84%EB%A9%94%EC%9D%B8-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0

 

AWS 구매한 도메인 연결하기 with 프리티어

시작하기 전) 도메인 구매 배포하기 위해 가비아에서 도메인을 구매했다. 이걸 AWS를 이용해 배포하려고 한다. 또 우리에겐 돈이 없기 때문에.... 최대한 금액이 적게 나오게,, 이왕이면 금액이 들

velog.io

https://velog.io/@coastby/Nginx-SSL-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0

 

[Nginx] SSL 적용하기

SSL(Secure Socket Layer) 또는 TLS(Transport Layer Security)은 전송계층 상에서 클라이언트, 서버에 대한 인증 및 데이터 암호화를 수행한다. 클라이언트와 서버 양단 간 응용계층 및 TCP 전송계층 사이에서

velog.io

https://m.blog.naver.com/seek316/222446489794

 

[IT정보] 무료 도메인(Domain) 발급받기

무료 도메인(Domain) 발급받기 일반 사용자들도 DNS(Domain Name Server)를 이용해서 자신이 가지고...

blog.naver.com