EKS – HTTPS 인증서

암호화 기초 개념

단방향 암호화

단방향 암호화의 특징은 암호화만 가능하고 복호화는 불가능한 특징을 갖는다. 비밀번호 저장(SHA-256)이나 세션/토큰(해시 함수)을 만들 때 사용하며 한 번 암호화하면 원본으로 되돌리 수 없다

양방향 암호화

양방향 암호화의 특징은 암호화와 복호화 모두가 가능하다

  • 암호화: 평문 + 비밀키 → 암호문
  • 복호화: 암호문 + 비밀키 → 평문
특징
  • 암호화와 복호화에 동일한 키 사용
  • 키를 안전하게 공유해야 하는 문제 발생
  • 빠른 처리 속도
비대칭키 방식 (공개키 암호화)
  • 키 생성: 공개키(Public Key) + 비밀키(Private Key)
  • 암호화: 평문 + 공개키 → 암호문
  • 복호화: 암호문 + 비밀키 → 평문

주요 알고리즘으로는 RSA와 ECDSA 등이 있으며 활용 사례로는 비트코인이나 HTTPS 통신이 있다

HTTPS 통신과 SSL/TLS 인증서

HTTPS 통신 원리

[사용자 접속]
사용자가 https://server.example.com 접속
         ↓
[인증서 전달]
서버가 SSL/TLS 인증서를 브라우저에 전송
(인증서에는 공개키가 포함됨)
         ↓
[데이터 암호화]
브라우저가 공개키로 데이터를 암호화
         ↓
[암호문 전송]
암호화된 데이터를 서버로 전송
         ↓
[데이터 복호화]
서버가 비밀키로 암호화된 데이터를 복호화

HTTPS가 필요한 이유

HTTP의 문제점

  • GET 파라미터로 전송할 경우 URL에 노출이 되어서 위험도가 높다
  • POST Body로 전송할 경우 URL에는 안 보이지만 암호화가 안 되어 위험도가 높다
HTTPS는 모든 데이터를 암호화 한다

중요: <form> 태그나 axios를 통한 POST 요청도 HTTPS 없이는 평문으로 전송된다

인증서 발급 프로세스

수동 발급 프로세스 (일반적인 방법)

1. 서버에서 공개키/비밀키 생성
         ↓
2. 공개키 + 서버 정보로 CSR 생성
   (Certificate Signing Request)
         ↓
3. CA 기관에 CSR 제출
         ↓
4. CA가 도메인 소유 여부 검증
         ↓
5. CA가 디지털 서명하여 인증서 발급
         ↓
6. 서버에 인증서 설치

Kubernetes 자동화 프로세스

1. ClusterIssuer 생성 (CA 기관 지정)
         ↓
2. Certificate 생성 (도메인 정보)
         ↓
3. cert-manager가 자동으로
   - 공개키/비밀키 생성
   - CSR 생성
   - CA에 제출
   - 도메인 검증 처리
   - 인증서 발급
   - Secret에 저장
         ↓
4. Ingress가 Secret 참조하여 HTTPS 활성화

Kubernetes 인증서 관리 구조

핵심 구성 요소

  • ClusterIssuer: CA 기관 및 인증서 종류를 지정하여 선언적 리소스 타입이다
  • Certificate: 도메인 정보 및 발급 요청을 하며 선언적 리소스 타입이다
  • cert-manager: 실제 발급 작업을 수행하하며 컨트롤러 (실행 프로그램)이다

비유

           Ingress         : Ingress Controller
              ‖
ClusterIssuer, Certificate : cert-manager

cert-manager의 역할

  • Certificate 리소스 모니터링
  • 공개키 / 비밀키 자동 생성
  • CSR 생성 및 CA 제출
  • 도메인 소유권 검증 처리
  • 발급된 인증서를 Secret에 저장
  • 인증서 만료 전 자동 갱신

cert-manager 설치

namespace 생성

kubectl create namespace cert-manager

# 성공 메시지
namespace/cert-manager created

중요: Namespace 이름은 반드시 cert-manager 여야 한다. 다른 이름 사용 시 설치에 실패한다.

cert-manager CRDs 설치

CRDs(Custom Resource Definitions): cert-manager가 작동하기 위한 기반 구조

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.5.0/cert-manager.crds.yaml
설치되는 리소스
  • Issuer, ClusterIssuer 리소스 타입 정의
  • Certificate 리소스 타입 정의
  • 기타 cert-manager 관련 리소스 정의

cert-manager 본체 설치

cert-manager 프로그램 (Pod, Deployment 등) 설치
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.5.0/cert-manager.yaml
설치되는 구성 요소
  • cert-manager Pod(실제 작업 수행)
  • cert-manager Deployment
  • cert-manager Service
  • 필요한 RBAC(Role-Based Access Control) 설정

ClusterIssuer 설정

ClusterIssuer YAML

https.yml (첫 번째 부분)

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: my-issuer
  namespace: hyeok  # 본인의 namespace로 변경
spec:
  acme:
    # CA 서버 주소 - Let's Encrypt 사용
    server: https://acme-v02.api.letsencrypt.org/directory
    # 인증서 만료 알림 이메일
    email: your-email@gmail.com  # 실제 이메일로 변경
    privateKeySecretRef:
      # CA 통신용 Secret 이름
      name: my-issuer
    solvers:
    - http01:
        ingress:
          # nginx 기반 Ingress Controller 사용
          class: nginx

설정 항목 설명

  • name: ClusterIssuer 이름으로 Certificate에서 참조
  • server: Let’s Encrypt CA 서버 주소
  • email: 인증서 만료 알림 수신 이메일 (실제 이메일 주소 필수)
  • privateKeySecretRef.name: CA 통신용 키 저장 Secret (자동 생성됨)
  • solvers.http01.ingress.class: 도메인 검증 방식 (nginx Ingress Controller 사용)

Let’s Encrypt는 무료 SSL/TLS 인증서 발급 기관으로 자동화된 인증서 발급을 지원해주며 전 세계적으로 신뢰받는 CA(Certificate Authority)이다

Certificate 설정

Certificate YAML

https.yml (두 번째 부분)

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: server-hyeok4444-com-tls
  namespace: hyeok  # 본인의 namespace로 변경
spec:
  # 인증서가 저장될 Secret 이름 (Ingress와 일치 필수!)
  secretName: server-hyeok4444-com-tls
  duration: 2160h     # 90일
  renewBefore: 360h   # 만료 15일 전 갱신
  issuerRef:
    name: my-issuer   # ClusterIssuer 이름과 일치
    kind: ClusterIssuer
  commonName: server.hyeok4444.shop
  dnsNames:
  - server.hyeok4444.shop  # 본인의 도메인으로 변경
  • metadata.name: Certificate 리소스 이름
  • secretName: 매우 중요하며 Ingress의 secretName와 일치해야 한다
  • duration: 인증서 유효 기간
  • renewBefore: 만료 며칠 전에 갱신할 지
  • issuerRef.name: ClusterIssuer 이름 참조
  • commonName: 대표 도메인
  • dnsNames: 인증서에 포함할 모든 도메인

여러 서브 도메인 추가

dnsNames:
- server.hyeok4444.shop
- api.hyeok4444.shop
- admin.hyeok4444.shop

Ingress와 Certificate 연동

Ingress YAML (HTTPS 설정 포함)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: order-backend-ingress
  namespace: hyeok
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: my-issuer
spec:
  tls:
  - hosts:
    - "server.hyeok4444.shop"
    # Certificate의 secretName과 정확히 일치해야 한다
    secretName: server-hyeok4444-com-tls
  rules:
  - host: server.hyeok4444.shop
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ordersystem-backend-service
            port:
              number: 80

핵심 연결 포인트

1. Certificate 리소스가 인증서 발급
         ↓
2. server-hyeok4444-com-tls Secret에 저장
         ↓
3. Ingress가 해당 Secret 참조
         ↓
4. HTTPS (443 포트) 자동 활성화

인증서 발급 및 확인

리소스 배포

kubectl apply -f https.yml

#예상 출력
clusterissuer.cert-manager.io/my-issuer created
certificate.cert-manager.io/server-hyeok4444-com-tls created

Certificate 상태 확인

kubectl get certificate -n hyeok

# 정상 상태
NAME                       READY   SECRET                     AGE
server-hyeok4444-com-tls   True    server-hyeok4444-com-tls   5m

READY 컬럼 의미

  • True: 인증서 발급 성공, Secret에 저장되며 정상 처리
  • False: 발급 진행 중 또는 실패로 describe 명령어로 확인 필요

문제 발생 시 확인

  • Waiting for http-01 challenge: 도메인 검증 실패로 Route53, Ingress 설정을 확인해봐야 한다
  • Self check failed: HTTP 라우팅이 안 된 것으로 Ingress로 HTTP 접속 테스트를 해봐야 한다
  • Invalid email: 이메일 형식 오류로 실제 이메일 주소를 사용해야 한다

도메인 검증 프로세스

CA가 도메인 소유권을 확인하는 방법
1. Let's Encrypt가 HTTP 요청 전송
   GET http://server.hyeok4444.shop/.well-known/acme-challenge/xxx
         ↓
2. 요청이 Route53 → Load Balancer → Ingress Controller를 거쳐 도달
         ↓
3. cert-manager가 임시 응답 제공
         ↓
4. Let's Encrypt가 응답 확인 → 소유권 인정
         ↓
5. 인증서 발급

중요: 인증서 발급 전에 HTTP 통신이 정상적으로 작동해야 한다

Secret 확인

kubectl get secret -n hyeok

# 예상 출력
NAME                       TYPE                DATA   AGE
my-app-secrets             Opaque              2      22h
server-hyeok4444-com-tls   kubernetes.io/tls   2      5m

HTTPS 테스트

Postman 테스트

헬스체크
GET https://server.hyeok4444.shop/health
→ 응답: "ok"

로그인
POST https://server.hyeok4444.shop/member/doLogin
Headers:
  Content-Type: application/json
Body:
{
  "email": "admin@example.com",
  "password": "12341234"
}
→ 응답: { "token": "..." }

브라우저 테스트

HTTP VS HTTPS 비교
  • http://server.hyeok4444.shop는 ⚠️ 안전하지 않고 암호화가 안 됨
  • https://server.hyeok4444.shop는 🔒 자물쇠 아이콘이며 암호화됨

브라우저에서 확인

  • https://server.hyeok4444.shop 접속
  • 주소창에 자물쇠 아이콘 클릭
  • 인증서 정보 확인 가능
http
https

HTTPS 동작 원리

접속

사용자가 https://server.hyeok4444.shop 입력

인증서 다운로드

브라우저가 서버로부터 SSL/TLS 인증서 수신(이 인증서는 Ingress가 Secret에서 가져옴)

인증서 검증

브라우저가 인증서의 유효성 확인
  • Let’s Encrypt CA가 서명 했는지 확인
  • 도메인이 일치하는지 확인
  • 만료되지 않았는지 확인

암호화 통신 시작

브라우저가 인증서의 공개키로 데이터 암호화

암호화된 데이터 전송

  • POST / member/create
  • BODY: (암호화된 데이터)

서버에서 복호화

서버가 비밀키로 데이터 복호화

응답도 암호화

서버 응답도 암호화하여 전송

전체 구조도

사용자
  ↓ HTTPS 요청
Route53
  ↓
Load Balancer
  ↓
Ingress Controller
  ↓ (Secret의 인증서 사용)
  ├─ 인증서 제공 (최초 접속 시)
  └─ 암호화된 데이터 복호화
  ↓
Service
  ↓
Pod (Spring)

출처 – eks를 활용한 spring 운영서버 배포(feat. devops의 모든것)