[Network] HTTPS / CA인증서 / Cert-Manager / Lets'Encrypt? 정리

Donghee Kim·2025년 11월 22일

문득문득

목록 보기
13/15

해당 글을 쓰는 이유

사내 서버에 gitlab을 구축하려다보니, 기존에 구축되어 있는 cert-manager 리소스들과 충돌이 날 거 같아, gitlab yaml 을 커스텀하고 cert-manager 충돌을 막을려고 하다보니, CA / SSL/TLS/KEY / Certificate / Issuer/ClusterIssuer / Secret 등 리소스를 정확히 알고 사용하기 위해서, 해당 글을 써보고자한다.
중간 중간 내가 궁금했던 것들이 너무 많아 공부하면서 꽤 자세히 공부해보았다. 해당 공부 내용을 정리하고자 함.


1. HTTP? HTTPS?

우선 HTTP 와 HTTPS 차이와 동작 방식을 먼저 알아보자.

HTTPS

HTTP/2는 HTTPS 위에서 동작합니다.
HTTPS는 애플리케이션 계층과 전송 계층 사이에 신뢰 계층인 SSL/TLS 계층을 넣는 신뢰할 수 있는 HTTP 요청을 말합니다.
⇒ 이를 통해 ‘통신을 암호화’ 합니다.

SSL/TLS

SSL/TLS는 네트워크를 통해 동작하는 서버, 시스템 및 응용프로그램 간에 인증 및 데이터 암호화를 제공하는 암호화 프로토콜입니다.

SSL (Socker Security Layer)?

SSL 인증서는 종종 디지털 인증서로 불림.
⇒ 브라우저(사용자의 컴퓨터) ↔ 서버(웹사이트) 사이의 암호화된 연결을 수립하는 데 사용됨.

SSL 인증서?

서버가 "나는 진짜 이 도메인의 주인이고, CA가 보증했다" 라는 것을 증명하는 신분증

  • 들어있는 정보
    • CN : CommonName (DNS)
      → 브라우저는 접속한 도메인과 인증서의 CN이 동일한지 비교
    • CA(Issuer) : 발급한 기관
      → 이 인증서는 누가 발급 했는가?
      ex) DigiCert, GlobalSign, Let’s Encrypt 등
    • 유효 기간 : 인증서의 유효 기간이 만료되지 않았는지 확인

TLS (Transport Layer Security)?

TLS는 SSL의 향상된, 더욱 안전한 버전
개인 정보와 데이터 보안을 용이하게 하기 위해 설계되어 널리 채택된 보안 프로토콜

SSL에서 TLS 가 달라진점

  1. 내부 동작 시 핸드셰이크 구조 변경
  2. 암호화 알고리즘 변경
    등등이다.

TLS 인증서?

사실상 SSL인증서와 차이가 없다 = 보안 파일 구조도 똑같고 사용 방식도 100% 동일합니다.


2. 인증서 체인?

PKI?

PKI(Public Key Infrastructure)?
인터넷에서 "상대가 진짜 맞는지" 검증하고, "안전하게 암호화"된 통신을 할 수 있도록 만드는 보안 시스템 전체

  • 공개키 / 개인키
  • 인증서
  • CA 서명
  • 인증서 검증 절차

이 모든걸 묶어 놓은 완성된 신뢰 시스템

-----BEGIN CERTIFICATE-----
MIID...
-----END CERTIFICATE-----

=> 해당 파일이 X.509 인증서 형태

인증서 체인?

공개키 인프라(PKI)에서 TLS 인증서는 기본적으로 신뢰체인으로 불리는 모델을 기반으로 이루어진다.
신뢰 체인은 CA에서 발급한 Root 인증서(Root Certificate)부터 하나 이상의 중간 인증서(Intermediate Certificate) 및 서버 인증서(Leaf Certificate)로 구성되어 있음.

Root CA / Intermediate CA / Leaf Certificate

[구조]

Root CA (절대 신뢰, Self-signed, 오프라인)
        ↓ 서명(Sign)
Intermediate CA (온라인 신뢰 관리, 실무 발급 담당)
        ↓ 서명(Sign)
Leaf Certificate (서버/도메인 인증서)

서명(Sign)이란?
온라인에서 누군가 문서나 인증서에 "내가 보증한다"는 표시를 남기는 방법

Root가 Intermediate 한테 서명하고 검증하는 과정

우선 위에서 봤듯, 서명이란걸 알기 위해서 [최상위 : Root-CA][중간 : Intermediate-CA] 에게 서명하고 검증하는 과정을 알아보자

  • 폴더 구조
pki/
├─ root/
│  ├─ root.key        # Root private key
│  └─ root.crt        # Root self-signed cert
├─ intermediate/
│  ├─ intermediate.key
│  ├─ intermediate.csr
│  └─ intermediate.crt
└─ v3.ext             # cert extensions for intermediate

1. OpenSSL로 Root key 및 crt 생성 (오프라인에서)

  • 디렉토리 만들기

    mkdir -p pki/root pki/intermediate
    • root/ : Root CA 키와 인증서 보관
    • intermediate/ : Intermediate CA키, CSR, 인증서를 보관
  • Root CA key 키 생성

    openssl genpkey -algorithm RSA -out pki/root/root.key -pkeyopt rsa_keygen_bits:4096
    chmod 400 pki/root/root.key
    • openssl genpkey : 새로운 비대칭 키를 생성하는 명령어
    • 사용하는 곳?
      • Root 인증서 생성 (root.crt) => self-sign 인증서
  • Root Self-signed crt 인증서 생성

    openssl req -x509 -new -nodes -key pki/root/root.key \
    -sha256 -days 3650 \
    -subj "/C=KR/ST=Seoul/L=Seoul/O=ExampleOrg/OU=PKI/CN=Example Root CA" \
    -out pki/root/root.crt
    • openssl req : OpenSSL에서 CSR(Certificate Singing Request) 생성 또는 Self-Signed 인증서 생성
    • -x509 : 인증서 자체를 바로 생성
    • -new : 새 요청 또는 새 인증서
    • -nodes : 생성된 private key를 암호화하지 않고 저장
    • subj : 인증서 Subject 정보(국가, 조직, CN)

    → 결과물 : Root CA 인증서 (root.crt)

보안 포인트
Root 키는 절대 온라인에 연결되지 않은 상태로 보관해야 함.
why?
Root Key가 유출되면?
1. 마음대로 인증서를 발급할 수 있음.
2. 브라우저는 Root CA를 절대적으로 신뢰함.
3. 이렇게 만든 위조 인증서를 정상 인증서처럼 100% 신뢰함.
=> 전 세계 모든 TLS 웹사이트가 신뢰를 잃음.

2. Intermediate CA Key와 CSR 생성 (온라인 발급 서버)

  • Intermediate Private Key 생성

    openssl genpkey -algorithm RSA -out   pki/intermediate/intermediate.key -pkeyopt rsa_keygen_bits:4096
    chmod 400 pki/intermediate/intermediate.key
    • Root와 동일하게 RSA 4096비트 키 생성

    • 이 키로 실제 서버 인증서를 발급할 계획

      → 결과물 : Intermediate CA Key (intermediate.key)

    • intermediate.key 안에는 private / public key가 존재함.

  • CSR (Certificate Signing Request) 생성

    openssl req -new -key pki/intermediate/intermediate.key \
    -subj "/C=KR/ST=Seoul/O=ExampleOrg/OU=Issuing CA/CN=Example Intermediate CA" \
    -out pki/intermediate/intermediate.csr

    → 결과물 : Intermediate CA CSR (intermediate.csr)

    • CSR(Certificate Signing Request)?
      intermediate.key(내부의 공개키)를 CA 인증서로 만들어주세요.
      +해당 키를 추출하는건 OpenSSL의 수학적 영역
      => 해당 CSR에는 publickey + subject 정보만 포함

3. v3.ext : 인증서 확장 설정

  • v3.ext : 인증서 확장 설정
    basicConstraints = critical, CA:TRUE, pathlen:0
    keyUsage = critical, cRLSign, keyCertSign
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid:always,issuer
    # crlDistributionPoints = URI:http://crl.example.com/intermediate.crl
    # authorityInfoAccess = OCSP;URI:http://ocsp.example.com
    • basicConstraints : CA 여부, pathlen 제한
    • keyUsage : 서명 가능 권한 설정
    • subjectKeyIdentifier / authorityKeyIdentifier : 체인 검증용
    • 실무에서는 반드시 확장 설정 필요

4. Root에서 Intermediate CSR 서명(오프라인)

  • Root Intermediate CSR 서명
    openssl x509 -req -in pki/intermediate/intermediate.csr \
      -CA pki/root/root.crt \
      -CAkey pki/root/root.key \
      -CAcreateserial \
      -out pki/intermediate/intermediate.crt \
      -days 1825 \ 
      -sha256 \ 
      -extfile pki/v3.ext \

→ 결과물 : Intermediate CA 인증서(intermediate.crt)

아무래도 root.key를 통해 intermediate.crt 인증서를 만들어낼텐데 오프라인에 있는 root.key를 어떻게 이용해야하는가?

정답 : 파일을 전달해줘야함.

  • Intermediate file(intermediate.csr / intermediate.crt) 전달 방식
    • USB
    • 오프라인 저장 매체
    • 안전한 네트워크(SFTP, SCP)
    • 이메일은 권장 X

5. OpenSSL 체인 검증

openssl verify -CAfile pki/root/root.crt pki/intermediate/intermediate.crt
  • 출력 : OK → Intermediate가 Root에 의해 정상 서명됨

결과

이후, Leaf Key 도 생성한 후, CSR을 생성하고 intermediate에게 Leaf Certificate + ext(CA : False) 를 만들어서 같이 주면, 더 이상 인증서를 발급할 수 없는 Leaf 인증서(Leaf Certificate)가 발급이 된다.

+6. 브라우저 내부에서 인증서 체인 과정

1. Leaf Certificate 유효성 확인

  • 현재 날짜가 범위 내인지 확인

  • CN or SAN 필드가 접속 URL과 일치하는지

  • 인증서가 폐기되지 않았는지

2. Intermediate → Root 체인 확인

  • Leaf Certificate의 IssuerIntermediate CA인지 확인

  • Intermediate CA의 IssuerRoot CA인지 확인

Issuer?
이 인증서를 발급한 CA의 이름

3. 서명 검증

https 연결시, 서버는 TLS 핸드셰이크 중, client에게 Leaf CertificateIntermediate Certificate를 반드시 보냄.

  • Root는 이미 브라우저/OS 안에 내장되어 있기 때문
  • Root는 온라인 노출 최소화해야 해서 서버가 보내지 않음
  1. Leaf 인증서 서명 검증
    (Leaf ⇄ Intermediate)

  2. Intermediate 인증서 서명 검증
    (Intermediate ⇄ Root(브라우저/OS 내장 신뢰소))

✔ 같으면 → 해당 CA가 실제로 서명한 것이 맞다.
✘ 다르면 → 위조된 인증서 → "안전하지 않은 연결" 경고


지금까지 내용을 보면 해당 개념들은 다음과 같이 이해할 수 있을 것이다.

Root CA? = 대통령

가장 위에 존재하는 최상위 인증 기관

  • Self-signed
  • 오프라인 보관
    • 절대 온라인에 두지 않음.
    • 보통 USB HSM 같은 폐쇄형 장비에만 존재.
    • 유출시..? 해당 인증서를 위조할 수 있음.
  • Intermediate CA 인증서를 서명하는 역할만 수행
    • 직접 서버(Leaf) 인증서 서명 x
  • 세계 모든 브라우저/os의 신뢰저장소에 내장됨.

Intermediate CA? = 여권 발급청

실제 발급 담당
Leaf Certificate 발급하는 기관

  • 온라인에서 동작
  • Root는 거의 사용하지 않고 Intermediate가 대부분의 업무를 처리.
    • Root Key 노출 방지 역할
      • 발급은 모두 Intermediate가 수행
  • 여러 계층의 Intermediate를 둘 수 있음.

Leaf Certificate? = 여권

실제 서비스 도메인에 사용하는 인증서

  • HTTPS에서 서버의 신원 확인
  • 서버 → 클라이언트로 공개키 전송

3. Cert-Manager

Cert-manager?

Kubernetes 내부에서 HTTPS 통신을 위한 X.509 인증서를 생성하고, 또 X.509 인증서의 만료 기간이 되면 자동으로 X.509 인증서를 갱신해주는 역할을 하는 Certificate-manager Controller입니다.

  • 주요 기능
    • 선언 (CRD : Certificate)에 따라 인증서 발급 및 Secret (kubernetes.io/tls : tls.crt/tls.key) 생성
    • 만료 자동 감지 및 자동 갱신 (기본은 만료 30일 전부터 갱신 시도)
    • 여러 발급 방식(issuers) 지원
      • ACME(Let's Encrypt)
      • CA Issuer(사내 CA 사용)
      • Selfsigned
      • HashiCrop Vault 등
    • Ingress, Gateway, 서비스와 연계되어 TLS 제공 자동화
  • 설치 구성 요소
    • cert-manager : 컨트롤러, 실제로직
    • webhook : CRD 유효성 검사 및 변환
    • cainjector : 자동으로 Secret/CA 주입 등
    • CRD : Certificate / Issuer / ClusterIssuer / Order / Challenge / CertificateReqeust
  • 유용한 경우
    • Let's Encrypt를 통해 외부 도메인에 자동 TLS 발급/갱신
    • 내부 사설 PKI로 사설 인증서 운영
    • Kubernetes 네이티브 방식으로 인증서 라이프사이클 관리하고 싶은 경우

Cert-Manager 주요 리소스

1) Issuer / ClusterIssuer

"누가 인증서를 발급할 것인지?"를 정의하는 CA 프로파일

  • Issuer : 특정 namespace 전용

  • ClusterIssuer : Cluster 전체에서 사용 가능

즉, Certificate 객체가 어떤 Issuer로부터 인증서를 발급 받을지를 결정한다.

  • Issuer 예시 (ACME - Let’s Encrypt)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx

ACME(Automatic Certificate Managment Environment)?

  • HTTPS 인증서를 자동으로 발급/갱신하기 위한 표준 프로토콜
  • ACME Server : 인증서 발급 기관(CA)
  • ACME Client : Cert-Manger, Certbot 같은 도구

2) Certificate

"이 도메인의 TLS 인증서를 만들어 주세요." 라는 요청 객체

  • Certificate : 발급 요청서이며, 직접 인증서를 가진 것이 아님.
  • Secret : 발급된 인증서
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-app-cert
spec:
  secretName: my-app-tls       # 여기에 발급된 인증서가 저장됨
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames: # 어떤 도메인을 위한 cert인지 지정
    - example.com
    - www.example.com

3) Secret

실제 인증서 파일(tls.crt + tls.key)을 저장하는 Kubernetes Secret

  • Certificate 객체가 발급되면? cert-manager는 다음 Secret을 생성
apiVersion: v1
kind: Secret
type: kubernetes.io/tls
metadata:
  name: my-app-tls
data:
  tls.crt: BASE64
  tls.key: BASE64
  • tls.crt : 공개키 + 서버 인증서 체인
  • tls.key: 개인키(private key)
  • Ingress, Gateway, Pod에서 이 Secret을 직접 참조하여 TLS 구성

4) Order / Challenge

Order

ACME(예: Let's Encrypt)를 사용할 때만 자동 생성되는 내부 리소스

  • “Let's Encrypt에게 인증서 발급 요청함” 상태를 표현
  • Certificate → Issuer(ACME) → Order 생성
  • 내용
    • 어떤 도메인인지
    • 어떤 방식(http-01, dns-01)으로 인증할지
    • 서버 응답을 기다리는 중인가? / 발급 완료됐는가?

Challenge

“이 도메인이 정말 네 것이 맞냐?” 검증 단계

apiVersion: acme.cert-manager.io/v1
kind: Challenge
spec:
  authorizationURL: https://acme-v02.api.letsencrypt.org/acme/authz/1234
  solver:
    http01:
      ingress:
        class: nginx
  • Challenge가 성공적으로 검증되면?
    • Order가 "fulfilled"로 변경됨
    • cert-manager가 인증서를 받아와 Secret에 저장

전체 흐름 요약

Certificate 생성
        ↓
Issuer 선택 (ACME / CA / SelfSigned)
        ↓
(ACME일 경우만)
Order 생성 → Let’s Encrypt 요청
        ↓
Challenge 생성 → 도메인 소유권 검증
        ↓
검증 성공 → LE가 인증서 발급
        ↓
cert-manager가 Secret 생성 (tls.crt + tls.key)
        ↓
Certificate Ready=True

이후, Ingress + Cert-Manager

전체 그림

  1. 사용자는 HTTPS로 서비스에 접속한다.

  2. Ingress Controller(Nginx/Istio 등)가 TLS Termination을 처리한다.

  3. TLS에 필요한 인증서를 cert-manager가 자동 발급한다.

  4. cert-manager는 Issuer/ClusterIssuer 구조로 CA 또는 Let’s Encrypt와 통신한다.

  5. 발급된 인증서는 Kubernetes Secret에 저장된다.

  6. Ingress는 그 Secret을 참조해 HTTPS 제공한다.

  • Ingress TLS 요구
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls: # tls 요구
  - hosts:
    - app.example.com
    secretName: app-tls
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        backend:
          service:
            name: app-svc
            port:
              number: 80
profile
WannaB.E/D.E

0개의 댓글