SSL/TLS
Secure Sockets Layer / Transport Layer Security
네트워크 통신을 암호화하는 보안 프로토콜. HTTPS의 기반 기술로, 인증서를 통해 서버 신원을 확인하고 데이터를 암호화합니다. TLS 1.3이 현재 최신 표준입니다.
Secure Sockets Layer / Transport Layer Security
네트워크 통신을 암호화하는 보안 프로토콜. HTTPS의 기반 기술로, 인증서를 통해 서버 신원을 확인하고 데이터를 암호화합니다. TLS 1.3이 현재 최신 표준입니다.
SSL(Secure Sockets Layer)은 1995년 Netscape가 개발한 암호화 프로토콜이며, TLS(Transport Layer Security)는 SSL 3.0을 기반으로 IETF가 표준화한 후속 프로토콜입니다. 현재 SSL은 보안 취약점으로 완전히 폐기되었고, TLS 1.2와 TLS 1.3이 실제로 사용됩니다. 관례적으로 "SSL"이라 부르지만, 실제로는 TLS를 의미합니다. TLS 1.3은 2018년 RFC 8446으로 표준화되어 더 빠르고 안전한 연결을 제공합니다.
TLS 핸드셰이크는 클라이언트와 서버가 암호화된 연결을 수립하는 과정입니다. 클라이언트가 지원하는 암호화 스위트를 제안하면 서버가 선택하고, 인증서를 교환하며, 세션 키를 협상합니다. TLS 1.3에서는 핸드셰이크가 1-RTT(Round Trip Time)로 단축되어 연결 지연이 크게 감소했습니다. 또한 0-RTT 재연결 기능으로 이전에 연결했던 서버에 즉시 데이터를 전송할 수 있습니다.
인증서는 서버의 신원을 증명하는 디지털 문서입니다. CA(Certificate Authority)가 발급하며, 도메인 소유권 검증(DV), 조직 검증(OV), 확장 검증(EV) 등급이 있습니다. Let's Encrypt 같은 무료 CA 덕분에 HTTPS 보급률이 급증했습니다. mTLS(Mutual TLS)는 서버뿐 아니라 클라이언트도 인증서를 제시하여 양방향 인증을 수행하며, 마이크로서비스 간 통신에서 많이 사용됩니다.
AI/ML 시스템에서 TLS는 API 통신, 모델 서빙, 데이터 파이프라인 암호화에 필수입니다. MLflow, TensorFlow Serving, gRPC 등 모든 ML 인프라가 TLS를 지원합니다. 특히 민감한 학습 데이터나 추론 결과를 전송할 때 반드시 TLS를 적용해야 하며, 내부 서비스 간에도 Zero Trust 원칙에 따라 mTLS를 권장합니다. 인증서 자동 갱신(cert-manager, ACME)은 운영 안정성의 핵심입니다.
# Nginx TLS 1.3 최적 설정
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name api.example.com;
# 인증서 경로
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
# TLS 버전 - 1.2, 1.3만 허용 (1.0, 1.1 비활성화)
ssl_protocols TLSv1.2 TLSv1.3;
# 강력한 암호화 스위트만 사용
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off; # TLS 1.3에서는 off 권장
# OCSP Stapling - 인증서 유효성 검증 가속화
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/api.example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
# 세션 캐시 - 핸드셰이크 최적화
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off; # Forward Secrecy 보장
# HSTS - HTTPS 강제
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# mTLS 설정 (클라이언트 인증서 요구)
# ssl_client_certificate /etc/nginx/client-ca.crt;
# ssl_verify_client on;
location / {
proxy_pass http://backend:8080;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# HTTP → HTTPS 리다이렉트
server {
listen 80;
listen [::]:80;
server_name api.example.com;
return 301 https://$server_name$request_uri;
}
# Python TLS/SSL 설정 예제
import ssl
import requests
from urllib3.util.ssl_ import create_urllib3_context
# === requests 라이브러리 TLS 설정 ===
# 기본 HTTPS 요청 (시스템 CA 인증서 사용)
response = requests.get("https://api.example.com/v1/models")
print(f"TLS Version: {response.raw.version}") # 사용된 TLS 버전
# 커스텀 CA 인증서 지정 (사내 PKI 사용 시)
response = requests.get(
"https://internal-api.company.com",
verify="/path/to/company-ca-bundle.crt"
)
# mTLS - 클라이언트 인증서 사용
response = requests.get(
"https://secure-api.example.com/v1/data",
cert=("/path/to/client.crt", "/path/to/client.key"),
verify="/path/to/server-ca.crt"
)
# === ssl 모듈 직접 사용 (저수준 제어) ===
# TLS 1.3 강제, 약한 암호화 비활성화
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.minimum_version = ssl.TLSVersion.TLSv1_2
context.maximum_version = ssl.TLSVersion.TLSv1_3
# 인증서 검증 필수
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
context.load_verify_locations("/etc/ssl/certs/ca-certificates.crt")
# 연결 테스트
import socket
with socket.create_connection(("api.example.com", 443)) as sock:
with context.wrap_socket(sock, server_hostname="api.example.com") as ssock:
print(f"TLS Version: {ssock.version()}")
print(f"Cipher: {ssock.cipher()}")
cert = ssock.getpeercert()
print(f"Server: {cert['subject']}")
# === FastAPI/Uvicorn TLS 서버 설정 ===
# uvicorn main:app --ssl-keyfile=./key.pem --ssl-certfile=./cert.pem
# === gRPC mTLS 설정 ===
import grpc
# 서버 측
server_credentials = grpc.ssl_server_credentials(
[(open('server.key', 'rb').read(), open('server.crt', 'rb').read())],
root_certificates=open('client-ca.crt', 'rb').read(),
require_client_auth=True # mTLS 활성화
)
# 클라이언트 측
channel_credentials = grpc.ssl_channel_credentials(
root_certificates=open('server-ca.crt', 'rb').read(),
private_key=open('client.key', 'rb').read(),
certificate_chain=open('client.crt', 'rb').read()
)
channel = grpc.secure_channel('api.example.com:443', channel_credentials)
# OpenSSL CLI - TLS 디버깅 및 인증서 관리
# === TLS 연결 테스트 ===
# 서버 TLS 설정 확인
openssl s_client -connect api.example.com:443 -tls1_3
# 인증서 체인 전체 출력
openssl s_client -connect api.example.com:443 -showcerts
# SNI(Server Name Indication) 지정
openssl s_client -connect api.example.com:443 -servername api.example.com
# 지원 암호화 스위트 확인
openssl s_client -connect api.example.com:443 -cipher 'ECDHE+AESGCM'
# === 인증서 정보 확인 ===
# 원격 서버 인증서 만료일 확인
echo | openssl s_client -connect api.example.com:443 2>/dev/null | \
openssl x509 -noout -dates
# 인증서 상세 정보
openssl x509 -in server.crt -text -noout
# 인증서와 개인키 일치 확인
openssl x509 -noout -modulus -in server.crt | openssl md5
openssl rsa -noout -modulus -in server.key | openssl md5
# 두 해시가 같아야 함
# === 자체 서명 인증서 생성 (개발용) ===
# 개인키 생성
openssl genrsa -out server.key 4096
# CSR(Certificate Signing Request) 생성
openssl req -new -key server.key -out server.csr \
-subj "/CN=api.example.com/O=MyOrg/C=KR"
# 자체 서명 인증서 생성 (365일 유효)
openssl x509 -req -days 365 -in server.csr \
-signkey server.key -out server.crt
# 한 줄로 키+인증서 생성
openssl req -x509 -newkey rsa:4096 -nodes -days 365 \
-keyout server.key -out server.crt \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
# === Let's Encrypt 인증서 발급 (certbot) ===
# 설치
apt install certbot python3-certbot-nginx
# Nginx 자동 설정으로 발급
certbot --nginx -d api.example.com
# 인증서만 발급 (수동 설정)
certbot certonly --webroot -w /var/www/html -d api.example.com
# 갱신 테스트
certbot renew --dry-run
# 자동 갱신 (cron)
# 0 0 * * * certbot renew --quiet && systemctl reload nginx
"TLS 1.0, 1.1은 이미 deprecated됐으니까 nginx에서 비활성화해주세요. ssl_protocols에 TLSv1.2 TLSv1.3만 남기고, Qualys SSL Labs에서 A+ 받는지 확인해봅시다."
"내부 서비스 간 통신도 mTLS 적용해야 합니다. Istio 쓰면 자동으로 사이드카가 mTLS 핸드셰이크하니까, PeerAuthentication을 STRICT 모드로 설정하면 돼요."
"인증서 만료로 API 장애났어요. cert-manager 적용해서 Let's Encrypt 인증서 자동 갱신되게 하고, 만료 30일 전에 Slack 알림 오도록 모니터링 추가합시다."
verify=False, CERT_NONE 같은 옵션은 MITM 공격에 노출됩니다. 개발 환경에서도 자체 서명 인증서를 만들어 사용하고, 프로덕션에서는 절대 비활성화하지 마세요.
TLS 1.0, 1.1은 POODLE, BEAST 등 알려진 취약점이 있습니다. PCI-DSS 등 컴플라이언스에서도 금지합니다. 최소 TLS 1.2, 가능하면 1.3만 사용하세요.
인증서 만료는 가장 흔한 장애 원인입니다. cert-manager, ACME 프로토콜로 자동 갱신을 설정하고, 만료 임박 시 알림을 받도록 구성하세요.
HSTS 헤더로 HTTPS를 강제하고, OCSP Stapling으로 인증서 검증을 가속화하세요. 개인키는 HSM이나 Vault에 안전하게 보관하고, Forward Secrecy를 위해 ECDHE 암호화 스위트를 사용하세요.