[AWS] AWS 맛보기 #6(SSL 설정)
서론
처음에 AWS 맛보기 프로젝트를 시작했을 때는 적절히 모든 코드와 데이터가 배포 된 상태로 구동된다 정도를 보려고 했습니다. 미리 어떠한 기술들이 필요한지 조사하고 들어갔음에도 생각보다 깊은 내용들이 있어서 내용이 많이 길어졌습니다. 이번엔 보안 설정 중 하나인 HTTPS를 설정하는 SSL에 대해서 알아보겠습니다.
지금 현재 보고있는 웹 페이지의 좌측 상단 URL 쪽 자물쇠를 클릭하시면(크롬 기준)
위 처럼 HTTPS 보안 연결이 사용되었다고 합니다. 하지만 저희가 만든 어플리케이션은 아마
이렇게 나올 것입니다. 우리가 만든 어플리케이션은 HTTP를 사용하고 이 미디움 블로그는 HTTPS를 사용하는 것입니다. HTTPS에서 S는 Secure의 의미입니다. HTTP 자체가 통신 프로토콜을 의미하는데 보안된 통신 프로토콜이라는 의미이죠.
원래 HTTP 통신을 하면 데이터들이 그대로 전송되는데 HTTPS를 쓰면 암호화된 데이터로 통신을 하게 됩니다. 만약 HTTPS를 사용하지 않는다면 해커들이 중간에 데이터를 가로챘을 때 그 데이터에 즉시 접근을 할 수 있게 되지만 HTTPS를 사용하면 데이터가 암호화 되어 있기 때문에 바로 해석이 불가능하게 되죠.
이러한 SSL의 암호화 방식은 공개 키, 비공개 키를 이용하는데 공개 키는 데이터를 암호화하는데 사용되고 비공개 키는 데이터를 복호화 하는데만 사용이 됩니다.
그리고 브라우저는 공개 키만을 가지게 되고 서버는 비공개 키를 가지게 되어서 안전한 방식이 됩니다.
그렇다면 이제 SSL을 설치하고 우리가 만든 NginX에 적용해보도록 하겠습니다.
도메인 등록
먼저 도메인이 필요합니다. 개인적으로 도메인이 있으시면 상관 없지만 없으시다면
https://my.freenom.com/clientarea.php
여기서 만들수 있습니다. 가입을 하시고 service 탭에 register new domain을 해서 무료 도메인을 생성하고 My Domain에 가서 설정버튼을 누른 후
타겟부분에 EC2의 퍼블릭 IP를 넣어주면 됩니다.
Let’s Encrypt
이제 ec2 서버에 certbot을 설치하도록 하겠습니다. 먼저
sudo apt-get update
업데이트를 해주시고
sudo apt install certbot python3-certbot-nginx
이렇게 필요한 패키지를 설치해줍니다. 참고로 제 ec2 운영체제는 우분투 20.04버전입니다. certbot을 wget을 통해 설치하는 방법도 있는데 우분투 20.04부터는 python2가 디폴트로 설치가 안되어있기 때문에 제대로 실행이 안되는 경우가 생깁니다. 따라서 위 방법대로 하시는게 가장 좋습니다.
그리고 설치가 완료되면
sudo certbot --nginx -d <YOUR_DOMAIN> -d <YOUR_DOMAIN>
을 통해 SSL 설정을 해줍니다. 위 커맨드를 실행합니다. 이 커맨드는 certbot을 통해 nginx로 배포된 웹 서버 중 <YOUR_DOMAIN> 이라는 도메인 이름에 ssl을 입혀준다는 뜻입니다.
sudo vi /etc/nginx/nginx.conf
그리고 이제 nginx 설정을 위해 vi를 통해 설정 파일에 들어와줍니다. 저같은 경우는 certbot이 자동으로 ssl에 대한 설정을 해주었는데 만약 안되어 있다면
server {
...listen 443 ssl; # managed by Certbotssl_certificate /etc/letsencrypt/live/<YOUR_DOMAIN>/fullchain.pem; Certbotssl_certificate_key /etc/letsencrypt/live/<YOUR_DOMAIN>/privkey.pem;include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
...
// nginx.conf
위 내용을 추가해주세요. 위 내용은 ssl 방식으로 443 포트를 이용하겠다는 뜻이고 방금
sudo certbot --nginx -d <YOUR_DOMAIN> -d <YOUR_DOMAIN>
이 커맨드를 통해 생성한 pem 키를 이용하여 암호화, 복호화를 하겠다는 의미입니다. 굉장히 복잡한데 천천히 따라오시고 마지막에 다시 전체적인 과정을 정리하도록 하겠습니다.
nginx 설정을 마치셨다면
sudo service nginx restart
커맨드를 통해 nginx를 재시작 해줍니다.
EC2에 인바운드 규칙 추가
nginx 설정에 보시면 저희가 443번 포트를 사용하겠다고 한 부분이 있습니다. 그리고 https 서버는 또 다른 포트를 사용할 것입니다. 따라서 우리는 ec2 인스턴스에 새로운 포트 번호를 열어줄 필요가 있습니다.
EC2 대시보드 왼쪽탭 아래쪽을 보시면 네트워크 및 보안탭에 보안 그룹이 있습니다. 들어가셔서 우리가 사용하고 있는 EC2 인스턴스에 맞는 보안그룹에 들어간 후
인바운드 규칙편집을 누르시고 위 사진처럼 443번 포트와 8443번 포트를 추가해줍니다.
443번에은 nginx를 8443번에는 nodejs 서버를 올릴 것입니다.
이제 포트 번호가 바뀌고 도메인도 추가 되었으니 어플리케이션의 환경 변수들을 바꿔주도록 하겠습니다.
.env 파일 수정
먼저 client 폴더의 .env 파일을 수정해주겠습니다.
ENDPOINT=https://<YOUR_DOMAIN>:8443/api/
이런식으로 이제 새로 생성한 도메인의 8443번 포트를 이용하도록 바꿔줍니다. 그리고 이제 다시 server.js 파일로 들어가서
import https from "https"
import fs from "fs"const privateKey = fs.readFileSync('/etc/letsencrypt/live/<YOUR_DOMAIN>/privkey.pem', 'utf8');
const certificate = fs.readFileSync('/etc/letsencrypt/live/<YOUR_DOMAIN>/cert.pem', 'utf8');
const ca = fs.readFileSync('/etc/letsencrypt/live/<YOUR_DOMAIN>/chain.pem', 'utf8');const credentials = {
key: privateKey,
cert: certificate,
ca: ca
};const https_server = https.createServer(credentials, app);https_server.listen(8443, () => {
console.log(`server running on PORT 8443`)
})
// server.js
위 코드를 추가해줍니다. 그리고 app.listen 코드는 지워주세요.
const privateKey = fs.readFileSync('/etc/letsencrypt/live/<YOUR_DOMAIN>/privkey.pem', 'utf8');
const certificate = fs.readFileSync('/etc/letsencrypt/live/<YOUR_DOMAIN>/cert.pem', 'utf8');
const ca = fs.readFileSync('/etc/letsencrypt/live/<YOUR_DOMAIN>/chain.pem', 'utf8');const credentials = {
key: privateKey,
cert: certificate,
ca: ca
};
이 부분을 통해 서버에서 비공개 키를 가지게 하고 원래는 express로 직접 서버를 열었지만
const https_server = https.createServer(credentials, app);https_server.listen(8443, () => {
console.log(`server running on PORT 8443`)
})
이렇게 https 모듈을 통해서 https 서버를 열도록 해줍니다. 그리고 포트번호도 8443으로 바꿔주고 .env 파일에서 CORS 세팅들도
https://<YOUR_DOMAIN>
으로 바꿔주면 모든 HTTPS 설정 과정이 끝나게 됩니다.
정리
만약 이 모든 과정이 어떻게 돌아가는지 어떤 기술이 어떤 원리를 가지고 왜 쓰이는지 모른다면 이 과정들은 이해하기가 굉장히 어렵습니다. 따라서 전체적인 흐름을 다시 한번 정리해 드리겠습니다.
일단 간단하게 그림을 그리면 위와 같은 과정으로 돌아가고 저희의 목표는 아래에 있는 그림
즉 브라우저에서 공개키를 통해 암호화한 데이터를 server에 보내고 서버에서 비공개 키를 통해 복호화를 해서 데이터를 받아들이는 HTTPS 방식으로 통신을 하고 싶은 것입니다.
따라서 저희는 먼저 도메인을 등록을 했고 그 후에 그 도메인에 certbot과 letsencrypt를 통하여 SSL을 입혔습니다. SSL을 입히니 서로 데이터의 암호화 복호화를 위한 키를
/etc/letsencrypt/live/<YOUR_DOMAIN>
폴더에 제공을 해주었고 이 키를 nginx 설정에 등록해주었습니다.
그리고 nginx에서 HTTPS 통신에는 443, 8443번 포트를 사용하니 인바운드 규칙을 수정해주고
이에 맞게 어플리케이션 코드도 수정해준 것입니다. 그리고 백엔드 코드에는 추가적으로 express에서 바로 app을 여는 것이 아닌 https 모듈을 거쳐서 서버를 열게 된 것입니다.
다음에는 AWS S3와 RDS 그리고 EC2를 보안 그룹으로 묶어서 더 안전한 통신을 하는 과정을 알아보도록 하겠습니다.