https를 위한 SSL 인증서 발급
자체 서명된 인증서 → CA 인증서 발급 받아보기
HTTP와 HTTPS
HTTP
웹에서 데이터를 전송하기 위한 기본 프로토콜입니다. 암호화되지 않은 평문으로 데이터를 전송 하기 때문에 보안에 취약합니다.
HTTPS (HTTP Secure)
HTTP의 보안 버전입니다. HTTP 프로토콜에 SSL/TLS 프로토콜을 결합하여 만들어졌습니다. 웹사이트의 신뢰성을 보장하기 위해 SSL/TLS 인증서를 사용합니다. 데이터를 암호화하여 전송하므로 보안성이 높습니다. 중간자 공격, 도청 등으로부터 데이터를 보호할 수 있습니다.
SSL(Secure Sockets Layer)과 인증서
https 통신을 위해서 필요한 SSL 인증서에 대해서 알아보겠습니다.
SSL(Secure Sockets Layer)
SSL은 웹 통신을 암호화하고 보안을 유지하는 프로토콜입니다. 네스케이프에 의해서 처음 만들어지고 그 이후 표준화 관리 명칭은 TLS(Transport Layer Security)로 부릅니다. 하지만 일반적으로 SSL이라는 용어를 더 많이 사용하고 있습니다.
인증서
인증서는 SSL/TLS 통신의 핵심 요소로, 신뢰할 수 있는 인증 기관(CA, Certificate Authority)에서 검증 받고 인증서를 발급 받습니다. 발급 받은 인증서는 다음과 같은 중요한 정보를 포함합니다.
- 서비스 정보
- 도메인 이름
- 조직 이름
- 위치 정보 등
- 서버 측 공개키
- 공개키 자체
- 사용된 암호화 알고리즘 (예: RSA, ECC 등)
인증서 종류
인증서의 종류는 심사 수준에 따라, 각 유형은 다른 수준의 신뢰와 검증 과정을 거칩니다.
유형 | 의미 | 검증 수준 | 발급 시간 | 신뢰도 | 주요 용도 |
---|---|---|---|---|---|
DV (Domain Validation) | 도메인 소유권 확인 | 낮음 | 빠름 (몇 분 ~ 몇 시간) | 낮음 | 개인 블로그, 소규모 웹사이트 |
OV (Organization Validation) | 조직 확인 | 중간 | 보통 (1-3일) | 중간 | 기업 웹사이트, 온라인 서비스 |
EV (Extended Validation) | 확장 검증 | 높음 | 느림 (1-2주) | 높음 | 금융기관, 대기업, 정부기관 |
인증서 발급 및 검증 과정
아래의 그림은 브라우저와 서버간의 https 통신을 위한 과정을 시퀀스 다이어그램으로 표현했습니다. 크게 두 부분으로 볼 수 있습니다.
- CA에서 SSL 인증서를 발급 받고 서버에 세팅하는 과정
- 브라우저에서 https 통신을 위해 인증서를 검증하고 사용하는 과정
여기서 우리는 CA에서 인증서를 발급받아 서버에 세팅 해보겠습니다. 한번 해보고 다시 아래의 다이어그램을 보면 좀 더 쉽게 이해하실 수 있습니다.
%%{ init: { 'theme': 'base', 'themeVariables': { 'primaryColor': '#2a3844', 'tertiaryColor': '#fff' } } }%% sequenceDiagram participant WS as 웹 서버 participant CA as CA (인증기관) participant WB as 웹 브라우저 WS ->>+ CA: 1. 인증 요청 : 공개 키 + 서버 정보 %% Note right of CA: 2. 서버 정보를 검증하고 인증서 생성 %% Note right of CA: 3. CA의 비밀키로 인증서 서명 CA ->> CA: 2. 서버 정보를 검증하고 인증서 생성 CA ->> CA: 3. CA의 비밀키로 인증서 서명 CA -->>- WS: 4. 서버로 서명된 인증서 발급 CA ->> WB: 5. 웹 브라우저에 CA의 공개키 제공 WB ->> WS: 6. 서버(웹 사이트) 접속 요청 WS -->> WB: 7. 발급받은 인증서 전달 WB ->> WB: 8. CA 공개키로 인증서 검증 WB ->> WB: 9. 서버 공개키로 대칭키 암호화 WB ->> WS: 10. 서버로 암호화된 대칭키 전송 WS ->> WS: 11. 서버 비밀키로 대칭키 복호화 WS <<->> WB: 12. 대칭키를 이용하여 암호화된 정보를 주고 받음 Note over WS, WB: https 통신
서버 세팅
서버는 아래의 스펙을 기반으로 진행하겠습니다.
- AWS EC2 : Amazon Linux 2023
- NGINX : nginx/1.26.2
- 퍼블릭 IPv4 DNS 활성화 or 개인 도메인
NGINX 설치
nginx: Linux packages를 참고해서 nginx/1.26.2
버전으로 설치했습니다.
$ sudo yum install yum-utils
$ sudo vim /etc/yum.repos.d/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/amzn/2023/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
priority=9
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/amzn/2023/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
priority=9
$ sudo yum install nginx
$ sudo systemctl restart nginx
퍼블릭 IPv4 DNS 활성화
CA 인증에 필요한 도메인은 Public IPv4 DNS
를 사용 하겠습니다. ‘VPC’ > ‘VPC 설정 편집’ > ‘DNS 호스트 이름 활성화’를 확인 합니다. 소유한 도메인이 있는 경우 해당 도메인을 사용해도 됩니다.
자체 서명된 SSL 인증서
우선은 자체 서명된 SSL 인증서를 만들어 보고, NGINX에 적용해보겠습니다.
1. SSL 인증서 생성
먼저 OpenSSL을 사용하여 자체 서명된 SSL 인증서를 생성합니다. 폴더를 생성하고 아래의 명령을 입력합니다. 이 명령은 1년간 유효한 2048비트 RSA 키 쌍과 자체 서명된 인증서를 생성합니다. 명령을 실행하면 인증서 정보를 입력하라는 프롬프트가 나타납니다.
$ sudo mkdir /etc/nignx/ssl
$ sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/self.key -out /etc/nginx/ssl/self.crt
-
req
: 인증서 서명 요청(CSR) 및 인증서를 생성하는 명령 -
-x509
: 공인 CA의 서명 없는 자체 서명된 인증서 생성 -
-nodes
: ‘no DES’의 약자로, 비밀키를 암호화하지 않음 -
-days 365
: 인증서의 유효 기간을 365일(1년)로 설정 -
-newkey rsa:2048
: 새로운 2048비트 RSA 키 쌍을 생성 -
-keyout /etc/nginx/ssl/self.key
: 생성된 비밀키를 저장할 경로를 지정 -
-out /etc/nginx/ssl/self.crt
: 생성된 인증서를 저장할 경로를 지정
2. NGINX 설정 파일 수정
SSL을 사용하도록 NGINX 설정을 변경해야 합니다. /etc/nginx/conf.d/ 디렉토리에 새 설정 파일을 만들거나 기존 파일을 수정합니다.
$ sudo vim /etc/nginx/conf.d/default.conf
ssl_certificate
지시어에 self.crt 파일을 지정하고, self.key 비밀키 파일은 ssl_certificate_key
지시어에 지정 합니다.
server {
listen 443 ssl;
server_name ec2-3-36-45-120.....; # 자신의 도메인으로 변경
ssl_certificate /etc/nginx/ssl/self.crt; # 인증서 파일
ssl_certificate_key /etc/nginx/ssl/self.key; # 비밀키 파일
# SSL 설정
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
# 나머지 서버 설정
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
# HTTP에서 HTTPS로 리다이렉트
server {
listen 80;
server_name ec2-3-36-45-120.....; # 자신의 도메인으로 변경
# 모든 요청은 HTTPS로 리다이렉트
location / {
return 301 https://$server_name$request_uri;
}
}
3. NGINX 설정 확인 & 재시작
설정 파일을 수정한 후, 구문 오류를 확인합니다. 설정이 올바르다면 NGINX를 재시작하여 변경사항을 적용합니다.
$ sudo nginx -t
$ sudo systemctl restart nginx
AWS 환경인 경우 필요에 따라 보안 그룹(Security Groups)에 http
, https
인바운드 규칙(inbound rules)을 수정합니다.
브라우저로 확인
이제 자체 서명된 SSL 인증서가 NGINX에 적용되었습니다. 브라우저에서 접속하면 보안 연결이 설정되었음을 확인할 수 있습니다. 생성된 인증서는 개발 환경이나 내부 테스트용으로는 적합하지만, 프로덕션 환경의 공개 웹사이트에서는 사용자에게 보안 경고를 표시할 수 있으므로 사용 할 수 없습니다.
> 보안 경고와 자체 서명 된 인증서를 확인 가능
CA 인증 : GOGETSSL
GOGETSSL 사이트에 90일 동안 유효한 CA 인증서를 발급 받을 수 있습니다. 로그인하고 SSL Certificates 탭에서 Domain Validation
을 선택합니다. Product 리스트에서 90-day Trial SSL를 찾아서 선택합니다.
인증서 발급 해보기
처음 SSL Certificates에서 Status
가 Incomplete 상태로 생성 됩니다. View
버튼을 누르고 Generate Certificate
버튼을 눌러서 서버 정보를 검증하고 인증서를 생성해 보겠습니다.
CSR Configuration
CSR은 SSL 인증서를 발급받기 위해 CA에 제출하는 암호화된 텍스트 파일입니다. Online CSR Generator
을 사용하여 CSR Generation Form을 작성해서 생성 할 수 있습니다.
CSR Generation Form 작성
CSR Generation Form에 가장 첫번째에 common name
에 도메인 이름을 작성합니다. DV 인증서의 경우, 도메인을 제외한 나머지 값은 아무렇게 넣어도 상관없습니다. Generate CSR 하면 두개의 키값이 생성이 됩니다.
CSR 값, 비밀키 저장
Certificate Signing Request(CSR)의 아래의 문장으로 시작하는 값을 이전 페이지(= CSR Configuration)에서 Paste your CSR
에 붙여 넣어줍니다.
-----BEGIN CERTIFICATE REQUEST-----
MIICtTCCAZ0CAQAwcDELMAkGA1UEBhMCQlMxCjAIBgNVBAgMAXgxCjAIBgNVBAcM
...
-----END CERTIFICATE REQUEST-----
여기서 중요합니다! Your Private Server Key
는 서버에 저장해야 하는 비밀키입니다. 이 파일은 반드시 자신의 서버에 저장합니다. 아래의 경로에 해당 비밀키를 저장하도록 하겠습니다.
$ sudo vim /etc/nginx/ssl/GoGetSSL_private.key
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2EwrnXq5f6EtL
...
-----END PRIVATE KEY-----
Validation Methods
Validation Methods에서 http를 선택합니다. 다음 필요한 정보를 입력합니다.
Domain Validation
SSL Certificates에서 Status
가 Processing 상태로 변경된 것을 확인 할수 있습니다. Domain Validation
탭에서 서버 인증용 파일(Validation File)을 받아서 서버에 저장 하겠습니다.
다운 받은 파일의 내용을 아래 경로 파일에 붙여넣겠습니다.
$ sudo vim /usr/share/nginx/html/validation.txt
4182A51E1A437B4763ACE010E0DCEABEE1BCCEF81872BE2C0C8841C542C393F7
sectigo.com
t0031261001728017854
NGINX 수정
alias
지시어를 사용하여 검증 URL이 해당 파일을 찾을 수 있게, 파일을 직접 지정해 줍니다. 이후 몇 분 기다려 보면 SSL Certificates에서 Status
가 Active 상태로 변경되고 서버 인증이 완료됩니다.
server {
# SSL 설정
...
# CA가 인증 파일에 접근할 수 있도록 설정
location = /.well-known/pki-validation/350105A2....txt {
alias /usr/share/nginx/html/validation.txt;
}
}
전체 인증서 파일 다운 & 업로드
이제 https 통신에 필요한 SSL 인증서가 만들졌습니다. All files
버튼으로 전체 파일을 다운로드 해서 서버에 3개의 인증서 파일을 업로드 하겠습니다.
home/
├── ec-user/
│ └── ec2-3-...compute_amazonaws_com.crt
│ └── GoGetSSL_RSA_DV_CA.crt
│ └── USERTrust_RSA_Certification_Authority.crt
이 3개의 파일을 통해 인증서 체인(Chain of Trust)에 사용할 fullchain.crt
파일을 생성해야 합니다. 잠시 후에 서버에 적용해 보도록 하겠습니다.
CA 인증서 발급 정리
여기까지가 CA 인증서를 발급받는 과정입니다. 다이어그램을 다시 한번 보면서 과정을 이해해 봅시다.
CSR을 통한 인증서 발급
GOGETSSL 사이트에서 했던 작업 순서를 다시 기억해 봅시다.
- CSR 생성
- 비밀키를 서버에 저장
- CA에서 서버 검증
- 서버의 인증서 발급
CA는 서버의 인증서에 자신의 비밀키로 디지털 서명을 합니다.
%%{ init: { 'theme': 'base', 'themeVariables': { 'primaryColor': '#2a3844', 'tertiaryColor': '#fff' } } }%% sequenceDiagram participant WS as 웹 서버 participant CA as CA (인증기관) WS ->>+ CA: 1. CSR : 공개 키 + 서버 정보 %% Note right of CA: 2. 서버 정보를 검증하고 인증서 생성 %% Note right of CA: 3. CA의 비밀키로 인증서 서명 CA ->> CA: 2. 서버 정보를 검증하고 인증서 생성 CA ->> CA: 3. CA의 비밀키로 인증서 서명 CA -->>- WS: 4. 서버로 서명된 인증서 발급
브라우저에서 인증서
CA가 인증서에 해둔 디지털 서명을 통해, 브라우저에서 이 인증서가 유효하다는 것을 CA의 공개키를 통해 검증 할 수 있게 됩니다.
유효한 인증서 내부에는 아래의 정보가 포함되어 있습니다.
- 서버의 공개키
- 서버의 정보
- CA의 디지털 서명
%%{ init: { 'theme': 'base', 'themeVariables': { 'primaryColor': '#2a3844', 'tertiaryColor': '#fff' } } }%% sequenceDiagram participant WS as 웹 서버 participant CA as CA (인증기관) participant WB as 웹 브라우저 CA -->> WS: 4. 서버로 서명된 인증서 발급 CA ->> WB: 5. 웹 브라우저에 CA의 공개키 제공 WB ->> WS: 6. 서버(웹 사이트) 접속 요청 WS -->> WB: 7. 발급받은 인증서 전달 WB ->> WB: 8. CA 공개키로 인증서 검증
https
유효한 인증서 내부에 있는 서버의 공개키가 안전하다는 것을 브라우저가 확인 했습니다. 검증된 서버의 공개키를 사용해 서버와 브라우저가 함께 사용할 대칭키를 안전하게 생성할 수 됐습니다. 이로써 브라우저와 서버간 https 통신이 가능하게 됩니다.
%%{ init: { 'theme': 'base', 'themeVariables': { 'primaryColor': '#2a3844', 'tertiaryColor': '#fff' } } }%% sequenceDiagram participant WS as 웹 서버 participant WB as 웹 브라우저 WB ->> WB: 8. CA 공개키로 인증서 검증 WB ->> WB: 9. 서버 공개키로 대칭키 암호화 WB ->> WS: 10. 서버로 암호화된 대칭키 전송 WS ->> WS: 11. 서버 비밀키로 대칭키 복호화 WS <<->> WB: 12. 대칭키를 이용하여 암호화된 정보를 주고 받음 Note over WS, WB: https 통신
위의 과정으로 인증서를 통해 서버의 공개키가 안전하다 것은 이해했습니다. 그런데 인증서 자체가 유효한지는 어떻게 알수 있을까요?
Fullchain 동작 방식
인증서가 유효한지 검증하는 Fullchain
방식에 대해 알아보겠습니다.
- 각 단계의 CA는 하위 인증서에 대해 자신의 비밀키로 서명합니다.
- 각 인증서는 바로 상위 CA에 의해 서명됩니다.
- 루트 CA의 인증서는 자체 서명됩니다 (self-signed).
- 이 과정이 루트 CA까지 반복되어 신뢰 체인을 형성합니다.
- 루트 CA의 인증서는 보통 브라우저나 운영체제에 미리 설치되어 있어 신뢰의 앵커 포인트 역할을 합니다.
%%{ init: { 'theme': 'base', 'themeVariables': { 'primaryColor': '#2a3844', 'tertiaryColor': '#fff' } } }%% sequenceDiagram participant WS as 웹 서버 participant LCA as 하위 CA participant ICA as 중간 CA participant RCA as 루트 CA WS->>LCA: 1. CSR 제출 LCA->>LCA: 2. 서버 인증서 생성 및 서명 LCA->>ICA: 3. 하위 CA 인증서 요청 ICA->>ICA: 4. 하위 CA 인증서 생성 및 서명 ICA->>RCA: 5. 중간 CA 인증서 요청 RCA->>RCA: 6. 중간 CA 인증서 생성 및 서명 RCA-->>ICA: 7. 서명된 중간 CA 인증서 ICA-->>LCA: 8. 서명된 하위 CA 인증서 LCA-->>WS: 9. 서명된 서버 인증서 + 인증서 체인
클라이언트(브라우저)는 이 체인을 따라 각 인증서를 검증하며, 최종적으로 루트 CA까지 도달하여 전체 체인의 신뢰성을 확인합니다.
fullchain.crt 파일 생성
아직 서버 설정이 끝나지 않았으니 계속해서 진행해 봅시다. 풀체인 파일은 SSL 인증서 체인을 구성하는 여러 인증서를 하나로 결합한 파일입니다. 여러개의 인증서 파일을 하나로 합쳐줌으로써 생성 할 수 있습니다.
$ cat (server.crt) (Intermediate.crt) [Root.crt] > fullchain.crt
$ cat ec2-3-...compute_amazonaws_com.crt GoGetSSL_RSA_DV_CA.crt USERTrust_RSA_Certification_Authority.crt > /etc/nginx/ssl/GoGetSSL_fullchain.crt
풀체인 파일을 만들 때의 일반적인 순서
루트 인증서의 경우 대부분의 브라우저와 운영 체제에 이미 신뢰할 수 있는 인증서로 포함되어 있기 때문에 생략이 가능합니다.
- 서버(도메인) 인증서
- 중간 인증서
- 루트 인증서 (선택적)
NGINX 설정
NGINX에서 이 풀체인 파일을 사용할 때는 ssl_certificate
지시어에 이 파일을 지정하면 됩니다. 비밀키 파일은 별도로 ssl_certificate_key
지시어에 지정 합니다.
server {
listen 443 ssl;
server_name ec2-3-36-45-120.....;
ssl_certificate /etc/nginx/ssl/GoGetSSL_fullchain.crt; # 체인 파일
ssl_certificate_key /etc/nginx/ssl/GoGetSSL_private.key; # 비밀키
...
}
전체 파일 구성 & NGINX 설정
전체 파일 구성
etc/
├── nginx/
│ └── ssl/
│ ├── GoGetSSL_fullchain.crt
│ └── GoGetSSL_private.key
usr/
├── share/nginx/html/
│ └── validation.txt
NGINX 설정
server {
listen 443 ssl;
server_name ec2-3-36-45...;
ssl_certificate /etc/nginx/ssl/GoGetSSL_fullchain.crt;
ssl_certificate_key /etc/nginx/ssl/GoGetSSL_private.key;
# SSL 설정
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
# HTTP 인증 파일에 접근할 수 있도록 설정
location = /.well-known/pki-validation/257021C3....txt {
alias /usr/share/nginx/html/validation.txt;
}
# 나머지 서버 설정
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
# HTTP에서 HTTPS로 리다이렉트
server {
listen 80;
server_name ec2-3-36-45...;
# 다른 모든 요청은 HTTPS로 리다이렉트
location / {
return 301 https://$server_name$request_uri;
}
}
마무리
https 통신을 하기 위한 준비 과정으로 SSL 인증서 발급을 공부해 봤습니다. 기본적인 ‘공개키 & 비밀키’에 대해서 알고 있다면 좀더 이해하기 쉬운 내용입니다.
추가로 아래의 내용을 공부해 보면 좋을듯 합니다. 😊
- 인증서 갱신 과정
- Let’s Encrypt + CertBot 사용
- 자주 발생할 수 있는 문제점들과 해결 방법 (예: 인증서 만료, 자체 서명 인증서 사용 시 주의사항 등)