🛡️ 1. mTLS 통신 암호화 (Mutual TLS)

✅ 목적

  • 파드 간 통신을 자동으로 암호화 및 인증
  • 클러스터 내부에서도 패킷 스니핑 공격 방지
  • 서비스 A → B 통신 시, 양쪽 모두 신뢰할 수 있는 인증서로 자신을 증명함

✅ Istio에서의 구성 방법

  1. Istio 설치 시 자동으로 Citadel 컴포넌트 생성
    • istiod가 CA 역할 수행
    • 각 사이드카 Envoy에 자동으로 TLS 인증서 주입

✅ 왜 중요한가?

보안 요소 mTLS 적용 전 mTLS 적용 후

트래픽 노출 암호화되지 않음 암호화됨
인증 확인 없음 양방향 인증
내부 위조 요청 가능 불가능 (인증서 검증 실패)

🛂 2. Policy 기반 접근 제어 (AuthorizationPolicy)

✅ 목적

  • 네임스페이스/서비스/사용자/경로/메서드 기반으로 접근 허용 또는 차단
  • 제로 트러스트 보안 모델의 실현

🎯 mTLS + Policy 통합 운영

요소 역할

mTLS 모든 통신을 암호화 + 신원 인증
AuthorizationPolicy 신원이 확인된 요청 중 허용된 것만 통과

이 둘을 함께 쓰면 통신 경로 보호 + 사용자/서비스 수준 제어까지 모두 가능합니다.

🧠 결론: 왜 이걸 쓰는가?

목적 설명

보안 강제 전 구간 암호화 (Zero Trust), 패킷 도청 방지
신원 기반 접근 제어 기존 IP 기반 ACL보다 정교한 정책 구성
DevOps 친화적 YAML 기반 정책으로 GitOps 가능
인프라와 무관 클러스터 네트워크 구조와 독립적으로 적용 가능

1. mTLS 전면 활성화 (제로 트러스트의 핵심)

vi peer-authentication.yml
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: dev
spec:
  mtls:
    mode: STRICT

→ STRICT 모드는 해당 네임스페이스 내 모든 파드 간 통신이 mTLS를 필수로 사용해야 함을 의미.

2. AuthorizationPolicy 구성

vi deny-all.yml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all
  namespace: dev
spec:
  {}

→ dev 네임스페이스에 대한 모든 요청을 기본 차단합니다

3. 서비스 계정 정의

vi front-end-service-account.yml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: frontend-sa
  namespace: dev

→ frontend 서비스가 가지는 고유한 SA 생성

4. frontend 서비스 배포 ( SA 포함 )

vi frontend-service.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-service
  namespace: dev
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      serviceAccountName: frontend-sa
      containers:
      - name: frontend
        image: 61.254.18.30:5000/frontend:1
        ports:
        - containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-service
  namespace: dev
spec:
  selector:
    app: frontend
  ports:
  - port: 80
    targetPort: 5000
  type: LoadBalancer

5. 이외 다른 서비스들 모두 배포

vi book-service.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: book-service
  namespace: dev
spec:
  replicas: 1
  selector:
    matchLabels:
      app: book
  template:
    metadata:
      labels:
        app: book
    spec:
      containers:
      - name: book
        image: 61.254.18.30:5000/book:1
        ports:
        - containerPort: 5001
---
apiVersion: v1
kind: Service
metadata:
  name: book-service
  namespace: dev
spec:
  selector:
    app: book
  ports:
  - port: 5001
    targetPort: 5001
  type: ClusterIP
vi review-service.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: review-service
  namespace: dev
spec:
  replicas: 1
  selector:
    matchLabels:
      app: review
  template:
    metadata:
      labels:
        app: review
    spec:
      containers:
      - name: review
        image: 61.254.18.30:5000/review:1
        ports:
        - containerPort: 5002
---
apiVersion: v1
kind: Service
metadata:
  name: review-service
  namespace: dev
spec:
  selector:
    app: review
  ports:
  - port: 5002
    targetPort: 5002
  type: ClusterIP

→ 현재 허용 정책이 없기 때문에 접속이 안된다.

6. 허용 정책 설정

6-1. 외부에서 ingressgateway를 통해 접근 허용

vi allow-ingress.yml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-ingress-to-nginx
  namespace: dev
spec:
  selector:
    matchLabels:
      app: frontend  # frontend 서비스로 들어오는 트래픽 허용
  rules:
  - from:
    - source:
        namespaces: ["istio-system"]  # istio-system 네임스페이스에서 오는 트래픽 허용

→ ingress를 통해 들어온 트래픽이 frontend의 페이지를 보여주고있지만, frontend가 book,review를 불러오는 정책이 없기 때문에 위와 같음 페이지만 보여짐.

6-2. frontend가 book을 호출할 수 있는 허용 정책

vi allow-frontend-book.yml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-frontend-to-book
  namespace: dev
spec:
  selector:
    matchLabels:
      app: book
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/dev/sa/frontend-sa"]

→ frontend 서비스가 book 서비스를 호출할 수 있는 정책이 생기자, book정보는 가져오지만, review 서비스는 가져오지 못하는 것을 확인할 수 있음.

6-3. frontend가 review 서비스 호출 허용 정책

vi allow-frontend-review.yml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-frontend-to-review
  namespace: dev
spec:
  selector:
    matchLabels:
      app: review
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/dev/sa/frontend-sa"]

시나리오

🔶 1. 기존 방식의 문제점 (비교 대상)

🧱 전통적인 배포 방식

  • 새 버전(v2)을 배포하면 → 모든 사용자가 동시에 받음
  • 문제 발생 시 → 서비스 전체 장애
  • 되돌리려면? → 긴급 롤백 (시간 오래 걸림, 다운타임 발생)

❌ 문제 발생 시 대처가 늦고,

❌ 실제 트래픽에서 오류 테스트는 거의 불가능함

❌ 특정 사용자만 대상으로 실험 불가능함


✅ 2. Istio가 제공하는 해결책


🧪 [1] Fault Injection – “일부러 망가뜨려보기”

시나리오:

우리는 v2를 배포했지만, DB 연동이 불안정할 수 있어.

→ Istio를 통해 v2로 가는 요청에 대해 500 Internal Server Error를 의도적으로 유발

fault:
  abort:
    percentage: 100
    httpStatus: 500

활용 포인트:

  • 실제 장애를 발생시키지 않고도 시뮬레이션 가능
  • 장애 상황에 대한 모니터링/알림 시스템을 미리 점검

🚦 [2] Canary Deployment – “조심스럽게 조금씩 배포하기”

시나리오:

  • 전체 유저 중 20%만 v2로 보내고 싶다
  • 트래픽 분산:
route:
  - subset: v1
    weight: 80
  - subset: v2
    weight: 20

활용 포인트:

  • 장애 발생 시 피해 규모 최소화
  • 실제 사용자 반응을 실시간 확인 가능
  • A/B 테스트도 간단히 구현

🔄 [3] Circuit Breaker – “망가지면 자동으로 차단하기”

시나리오:

  • v2로 보냈더니 500이 계속 난다?
  • Istio가 감지해서 자동으로 해당 엔드포인트를 차단
outlierDetection:
  consecutive5xxErrors: 1
  interval: 1s
  baseEjectionTime: 30s

활용 포인트:

  • 문제 있는 인스턴스를 자동으로 격리
  • 사용자 입장에서 무중단 대응 가능

📊 3. 비교 표 정리

항목  전통적 방식 Istio 도입 시
배포 방식 전체 사용자에 즉시 적용 일부 트래픽만 v2에 적용 가능 (Canary)
장애 테스트 실제 서버 망가뜨려야 함 Fault Injection으로 시뮬레이션 가능
문제 대응 수동 롤백 / 다운타임 발생 Circuit Breaker로 자동 차단 / 회복
A/B 테스트 별도 로직 필요 Route 조건만 바꾸면 가능
트래픽 제어 불가능 가중치 기반 정밀 분산 가능

💡 4. 결론 - 왜 Istio를 써야 하나?

"Istio는 단순히 ‘트래픽을 보내는 도구’가 아니라,

트래픽을 이해하고, 제어하고, 실험하고, 보호할 수 있게 해주는

‘서비스 메쉬 기반 운영 전략의 핵심’입니다."

→ 장애가 터지기 전에 감지하고,

→ 사용자에게 피해를 최소화하고,

→ 자동으로 회복하게 만들 수 있다면

우리는 롤백이 아니라, 롤업이 가능한 팀이 되는 거죠.


🎯 핵심 비교 포인트

항목  ① 레플리카 방식 (디플로이먼트 2개) ② Istio 트래픽 조절 방식
트래픽 제어 단위 Pod 개수 비례 실제 트래픽 비율 기반 🎯
정밀한 조절 가능? ❌ 불가능 (1:4 → 20%) ✅ 가능 (weight 17%, 23% 등 아주 정밀)
배포 전략 step-wise rollout (수동 조절) Canary / A/B / Header-based 다양하게
롤백 수동 scale 조절 or 롤백 Route만 변경하면 즉시 롤백 가능
운영 중 실험 분리 ❌ 어려움 ✅ 특정 유저만 v2 (헤더, URI 조건 등)
코드 변경 없이 실험? ❌ 어려움 ✅ 가능 (서비스 라우팅만 조절하면 끝)
관찰 + 대응 Metrics로는 가능, 자동은 아님 Prometheus + CircuitBreaker + Rollouts 연동 가능

이스티오 - 안전하게 환경 확인 후에 v2를 100%, 얘는 중단될 일이 없음

→ 중단되도록 오류 주입 → 복구 설정을 하면 알아서 재시도 → 안되면 다른 곳으로 트래픽 보냄 → 서비스 중 어디가 문제인지 확인 가능

기존꺼에 다른배포법을 쓴다면 - 서비스를 아예 이용하지 못함

Istio가 '필수’인 환경

  • 버전별 사용자 트래픽 제어가 필요할때
    • 10%의 사용자만 테스트
    • Istio의 VirtualService로 트래픽을 세분화해서 컨트롤
  • 백엔드가 여러 서비스로 확장됐을때
    • 서비스 간 호출이 많아질수록 서비스 디스커버리, 로드밸런싱, 장애 복구(retry/failover)가 필요
    • Istio는 서비스 간 호출을 사이드카(proxy)로 통제하면서 이걸 처리함
  • 비정상 상황 테스트(fault injection)가 필요할 때
    • 일부러 review-service를 느리게 응답하게 하거나, 에러를 반환하게 해보면서 UI나 다른 서비스가 어떻게 반응하는지 실험
    • 이런 실험은 Istio의 fault 기능으로 손쉽게 설정 가능
  • 서비스 간 보안 통신이 필요할 때 (mTLS)
    • 회사 보안 정책상 서비스 간 통신을 암호화(mTLS)해야 한다면, Istio가 mTLS를 기본 제공
    • 일반적인 K8s 환경에서는 직접 구현해야 함
  • 서비스 호출의 모니터링 및 트레이싱이 필요할 때
    • 여러 개의 마이크로서비스 간 복잡한 통신, 트래픽 제어, 장애 시뮬레이션, 보안 통신, 관찰성(모니터링/트레이싱)을 제어 및 실습

시나리오 자료

replica 수를 이용한 카나리 배포 방법

v1

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-v1
  namespace: default
spec:
  replicas: 4
  selector:
    matchLabels:
      app: frontend
      version: v1
  template:
    metadata:
      labels:
        app: frontend
        version: v1
    spec:
      containers:
      - name: frontend
        image: choiseungyoung/frontend:21
        ports:
        - containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-service
  namespace: default
spec:
  selector:
    app: frontend 
  ports:
    - protocol: TCP
      port: 80
      targetPort: 5000

v2

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-v2
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
      version: v2
  template:
    metadata:
      labels:
        app: frontend
        version: v2
    spec:
      containers:
      - name: frontend
        image: choiseungyoung/frontend:8
        ports:
        - containerPort: 5000

  • v1은 4개 v2는 1개로 80% 20% 비율이다.

이후 점진적으로 v1을 20퍼 v2를 80퍼로 하고싶다!

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-v1
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
      version: v1
  template:
    metadata:
      labels:
        app: frontend
        version: v1
    spec:
      containers:
      - name: frontend
        image: choiseungyoung/frontend:21
        ports:
        - containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-service
  namespace: default
spec:
  selector:
    app: frontend 
  ports:
    - protocol: TCP
      port: 80
      targetPort: 5000

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-v2
  namespace: default
spec:
  replicas: 4
  selector:
    matchLabels:
      app: frontend
      version: v2
  template:
    metadata:
      labels:
        app: frontend
        version: v2
    spec:
      containers:
      - name: frontend
        image: choiseungyoung/frontend:8
        ports:
        - containerPort: 5000

이렇게 replica를 복제하는 방법으로 카나리 배포를 하면 파드를 지우고 생성하고를 반복해야 되기 때문에 서비스 운영 중단 시간이 생긴다. 서비스가 많아 질 수록 운영 중단 시간은 더욱 더 길어질 것이다!

✅ 1. book-service에 503 오류 주입

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: book-service
  namespace: msa-demo
spec:
  hosts:
  - book-service
  http:
  - fault:
      abort:
        percentage:
          value: 100
        httpStatus: 503
    route:
    - destination:
        host: book-service

확인 후, 아래대로 꼭 지워주기

kubectl delete virtualservice book-service -n msa-demo

✅ 2. frontend-v2에만 장애 주기

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: frontend
  namespace: msa-demo
spec:
  hosts:
  - "*"
  gateways:
  - frontend-gateway
  http:
  - match:
    - headers:
        cookie:
          regex: ".*ver=2.*"
    fault:
      abort:
        httpStatus: 500
        percentage:
          value: 100.0
    route:
    - destination:
        host: frontend-service
        subset: v2
  - route:
    - destination:
        host: frontend-service
        subset: v1
  • 요청 헤더에 cookie: ver=2 가 들어있으면
  • frontend-service의 v2로 라우팅되긴 하지만
  • 무조건 HTTP 500 에러로 응답

→ 테스트/실험 용도로 일부러 쿠키를 가진 요청만 망가뜨려서 v2 버전 사용자들이 에러를 경험할때 UI가 어떻게 동작하는지와 관련된 시나리오 실험

💡 쿠키 없이 v1로, ver=2 쿠키 있으면 장애!

조건 도달하는 Pod 결과
쿠키 없음 frontend-v1 정상 응답
쿠키 있음 (ver=2) frontend-v2 HTTP 500 강제

curl --header "Cookie: ver=2" , 브라우저에서 쿠키 설정해 접속하면 v2에만 장애

  • *x-version: v2*는 버전 라우팅을 위해 직접 요청하는 헤더이고,
  • *Cookie: ver=2*는 세션 또는 상태 정보를 서버에 전달하는 쿠키입니다.

따라서 두 헤더는 서로 다른 목적을 가지고 있으며, 쿠키자동으로 관리되는 세션 정보인 반면, x-version은 버전 라우팅을 위한 수동 설정인 거죠.

  • fault injection이 100% 확률로 걸려서 HTTP 500 뜨도록 확인

curl -i --header "Cookie: ver=2" http://211.183.3.200/

curl -i --header "x-version: v2" http://211.183.3.200/

//fault-service2-v2 영상

✅ 3. review-service에만 장애 주기

이 설정은 review-service로의 요청을 받았을 때 100%의 확률로 HTTP 500 오류를 반환하도록 합니다.

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: review-vs
  namespace: msa-demo
spec:
  hosts:
    - review-service
  http:
    - fault:
        abort:
          httpStatus: 500
          percentage:
            value: 100  # 장애를 100% 확률로 주기
      route:
        - destination:
            host: review-service
            port:
              number: 5002

확인 후, 아래대로 꼭 지워주기

kubectl delete virtualservice review-service -n msa-demo

//fault-reviewErr-v2 영상

원래 계획:

Pod 로그 확인:

Kubernetes에서 직접 서비스의 로그를 확인하려면 kubectl logs 명령어를 사용해 해당 Pod에서 발생하는 오류나 로그를 확인할 수 있다는데…

kubectl logs -n msa-demo <review-service-pod-name>

Retry 확인:

Istio가 요청을 보내고 실패(예: 5xx 응답)했을 때 재시도하는 방식을 설정

  • attempts: 3 → 최대 3번까지 재시도
  • perTryTimeout: 2s → 각 시도당 최대 2초 기다리고
  • retryOn: 5xx → 5xx 오류가 나면 재시도 트리거되어야 하는디…

설정대로면 리뷰 서비스가 500을 주면 Istio는 총 3번까지 재요청을 보내야하는데…

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: review-vs
  namespace: msa-demo
spec:
  hosts:
    - review-service
  http:
    - fault:
        abort:
          httpStatus: 500
          percentage:
            value: 100
      retries:
        attempts: 3
        perTryTimeout: 2s
        retryOn: 5xx
      route:
        - destination:
            host: review-service
            port:
              number: 5002