티스토리 뷰

반응형

쿠버네티스 실습: 서비스 간 권한 인증 — JWT, OAuth2, SPIFFE/SPIRE 기반 마이크로서비스 접근 제어

앞선 글에서는 Zero Trust 아키텍처의 기반인
Istio + Vault + OPA + Kyverno를 활용해 네트워크, 정책, 런타임 레벨까지 완전한 보안 통제를 실현했습니다.
이번 글에서는 한 단계 더 들어가, 서비스 간(Service-to-Service) 인증과 인가를 구현합니다.

즉, 단순히 “mTLS로 암호화된 통신”이 아니라,
“각 마이크로서비스가 자신이 누구인지 증명하고, 접근 권한을 검증받는 구조”를 완성합니다.


1) 목표 아키텍처

[User] ──▶ [Frontend] ──(JWT/OAuth2)──▶ [Backend] ──▶ [Database]
                      │
                      └──▶ [Auth Service / SPIRE Agent]

핵심 요소

  • JWT/OAuth2 → 사용자 및 서비스 요청의 인증 토큰 관리
  • SPIFFE/SPIRE → 서비스 ID 기반 자동 인증
  • OPA/Gatekeeper → 서비스 정책 검증
  • Istio AuthorizationPolicy → RBAC 기반 트래픽 제어

2) 인증(Authentication) vs 인가(Authorization)

구분 설명 예시

인증(Authentication) “너는 누구냐?” JWT / OIDC / SPIFFE
인가(Authorization) “무엇을 할 수 있느냐?” OPA / Istio RBAC / Kyverno

3) JWT 기반 서비스 인증

3-1. JWT 발급 예시 (NestJS Auth Service)

auth.controller.ts

import { Controller, Post, Body } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

@Controller('auth')
export class AuthController {
  constructor(private jwtService: JwtService) {}

  @Post('login')
  login(@Body() body) {
    const payload = { username: body.username, role: 'user' };
    return {
      access_token: this.jwtService.sign(payload, { expiresIn: '1h' }),
    };
  }
}

3-2. 백엔드에서 JWT 검증

backend.guard.ts

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import * as jwt from 'jsonwebtoken';

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const req = context.switchToHttp().getRequest();
    const token = req.headers['authorization']?.replace('Bearer ', '');
    try {
      const decoded = jwt.verify(token, process.env.JWT_SECRET);
      req.user = decoded;
      return true;
    } catch {
      return false;
    }
  }
}

이제 서비스 간 호출 시에도 JWT를 헤더에 포함해야 합니다.


4) Istio AuthorizationPolicy로 인가 제어

반응형

Istio는 HTTP 헤더에 포함된 JWT를 인식하고, RBAC 정책으로 인가를 제어할 수 있습니다.

authorization-policy.yaml

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: backend-policy
  namespace: team-a
spec:
  selector:
    matchLabels:
      app: backend
  action: ALLOW
  rules:
  - from:
    - source:
        requestPrincipals: ["auth.fuelstation.app/*"]
    to:
    - operation:
        methods: ["GET", "POST"]

→ 인증된 서비스(즉, 올바른 JWT 서명 포함 요청)만 백엔드 접근 허용.

JWT 클레임(iss, sub)은 Vault 또는 OIDC 서버에서 검증됩니다.


5) SPIFFE/SPIRE를 통한 서비스 ID 기반 인증

JWT는 사용자의 인증에는 유용하지만, 서비스 간 통신에는 한계가 있습니다.
여기서 등장하는 것이 SPIFFE (Secure Production Identity Framework for Everyone) 입니다.

5-1. SPIFFE 개념

  • 서비스마다 고유한 SPIFFE ID (spiffe://domain/ns/service) 부여
  • 각 서비스는 SPIRE Agent를 통해 자동으로 X.509 인증서를 발급받음
  • Istio와 연동하면 mTLS에서 이 ID를 기반으로 서비스 인증 가능

5-2. SPIRE 설치

kubectl apply -f https://github.com/spiffe/spire/releases/latest/download/spire-k8s.yaml

확인:

kubectl get pods -n spire

출력 예시:

spire-server-0   Running
spire-agent-0    Running

5-3. 서비스 등록

kubectl exec -n spire spire-server-0 -- \
  /opt/spire/bin/spire-server entry create \
  -spiffeID spiffe://fuelstation.app/ns/team-a/sa/backend \
  -selector k8s:ns:team-a \
  -selector k8s:sa:backend \
  -parentID spiffe://fuelstation.app/ns/spire/sa/spire-agent \
  -ttl 3600

→ backend 서비스가 spiffe://fuelstation.app/ns/team-a/sa/backend 라는 ID를 가지게 됩니다.


6) Istio와 SPIFFE 연동

Istio는 SPIRE Agent가 발급한 인증서를 활용해 mTLS에 ID 기반 인증을 추가할 수 있습니다.

PeerAuthentication 설정:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: strict-mtls
  namespace: team-a
spec:
  mtls:
    mode: STRICT

이후 Istio 내부적으로 SPIFFE ID를 요청자 정보로 포함합니다.
istioctl authn tls-check 실행 시 다음과 같이 표시됩니다:

SOURCE: spiffe://fuelstation.app/ns/team-a/sa/frontend
TARGET: spiffe://fuelstation.app/ns/team-a/sa/backend
STATUS: OK (mTLS + SPIFFE)

7) OPA 기반 접근 제어 고도화

OPA를 사용하면 단순 RBAC을 넘어 정책 코드화(Policy-as-Code) 가 가능합니다.

service_policy.rego

package istio.authz

default allow = false

allow {
  input.method == "GET"
  input.parsed_body.user == "admin"
}

적용:

kubectl apply -f opa-configmap.yaml

OPA는 Istio Envoy 사이드카와 통합되어,
각 요청마다 정책 평가 → 허용/거부를 반환합니다.


8) 실제 서비스 시나리오

상황 인증 수단 인가 정책 결과

frontend → backend 정상 호출 JWT + SPIFFE ALLOW (정상 토큰)  
unauthenticated pod → backend 없음 DENY (mTLS 거부)  
frontend → DB 직접 접근 SPIFFE 불일치 DENY  
backend → Redis mTLS 허용 ALLOW  
frontend (expired token) 만료 JWT DENY (401 Unauthorized)  

9) 종합 아키텍처

User(OIDC/JWT)
   ↓
Frontend ──▶ Auth Service (JWT 발급)
   ↓
Istio Gateway + mTLS
   ↓
Backend (SPIFFE 인증)
   ↓
Database (OPA 정책)
  • JWT/OAuth2 → 사용자 인증
  • SPIFFE/SPIRE → 서비스 ID 인증
  • Istio mTLS → 전송 암호화
  • OPA → 세분화된 접근 제어

완전한 Zero Trust + Service Identity 기반 마이크로서비스 보안 체계 완성


10) 정리

  • JWT/OAuth2: 사용자 및 서비스 요청의 표준 인증 방식
  • SPIFFE/SPIRE: 마이크로서비스 간 신원 증명 (X.509 기반)
  • Istio AuthorizationPolicy: 트래픽 단위 인가
  • OPA: 정책 중심 접근 제어 (Policy-as-Code)
  • Vault/OIDC와의 통합으로 인증서 관리 자동화

다음 글에서는 이 보안 구조 위에
실시간 서비스 트래픽 관찰 + 위협 탐지 시스템 (Falco + Prometheus + Loki + Grafana Stack) 을 구축하여
보안 이상 탐지 및 대응 자동화(SOAR) 환경을 실습하겠습니다.


 

쿠버네티스,JWT,SPIFFE,SPIRE,OAuth2,ZeroTrust,마이크로서비스보안,Istio,OPA,DevSecOps,K8s실습

 

 


✅ 참고할 최신 자료

  • SPIRE(SPIFFE Runtime Environment) + Istio 연동 가이드: 공식 문서를 통해 SPIRE가 서비스 메시 워크로드 ID 기반 인증을 지원한다는 설명이 있습니다. (Istio)
  • Argo CD Vault Plugin: HashiCorp Vault 및 GitOps 환경에서 시크릿을 자동 주입하는 플러그인으로, GitOps + Vault 통합을 설명하는 자료가 많습니다. (argocd-vault-plugin.readthedocs.io)

⚠️ 보완/강화 제안

  • JWT / OAuth2 부분: 사용자 인증 흐름에 대해 더 구체적인 예(예: OIDC Provider 설정, 권한 클레임 설계)를 넣으면 좋습니다.
  • SPIFFE/SPIRE 부분: 클러스터 외부 VM 또는 멀티클러스터 환경까지 고려한다는 언급이 좋은데, 실제로 SPIRE가 워크로드 ID를 발급하고 인증서 생명주기를 관리한다는 점을 강조하면 좋습니다. (imesh.ai)
  • Istio AuthorizationPolicy + OPA/Kyverno 조합: 실제 정책 코드 예시 외에도 운영 시 발생할 수 있는 오류 사례나 정책 미적용 시 위험을 간단히 언급하면 도움이 됩니다.
  • 보안 운영 팁: “서비스 계정(ServiceAccount) 권한 최소화”, “토큰 만료 및 갱신 정책”, “이미지 서명 강제화”, “로그 및 감사(Audit) 활성화” 등을 추가하면 현실감이 높아집니다.

 

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
글 보관함
반응형