Istio 를 사용하여 JWT 인증하기

Istio 를 사용한 JWT(JSON Web Token) 인증은 마이크로서비스 아키텍처에서 보안과 사용자 인증을 강화하는 중요한 방법입니다. 마이크로서비스 아키텍처는 현대적인 애플리케이션 개발에서 널리 사용되고 있으며, 이는 애플리케이션을 작고, 독립적으로 배포 가능한 서비스로 분할하는 방식입니다. 이러한 접근 방식은 유연성과 확장성을 크게 향상시키지만, 동시에 보안 문제, 특히 서비스 간의 안전한 통신과 사용자 인증을 어렵게 만듭니다.

Istio는 이러한 문제를 해결하기 위해 설계된 Open Source Service Mesh 플랫폼입니다. Service Mesh는 마이크로서비스 간의 통신을 관리하고, 보안, 모니터링, 로깅 등의 기능을 제공하여 개발자가 애플리케이션 로직에 더 집중할 수 있도록 돕습니다. Istio는 이러한 Service Mesh의 한 예로, 특히 보안 측면에서 강력한 기능을 제공합니다.

JWT 인증은 Istio에서 제공하는 보안 기능 중 하나입니다. JWT는 JSON 객체를 사용하여 사용자의 신원 정보를 안전하게 제공하는 보안 기능 중 하나입니다. 이 포스트에서는 Istio를 사용한 JWT 인증을 활성화하는 방법에 대해 이야기합니다. 또한 이 포스트에서는 Istio를 설치하는 방법은 포함하지 않습니다. Istio를 설치 및 배포하는 방법에 대해서는 여기를 확인하세요.

목차

1. JWT 인증 테스트 환경
2. Istio JWT 요청 인증 정의하기
3. Istio JWT 승인 정책 활성화
4. JWT 인증 테스트

1. JWT 인증 테스트 환경

환경 정보는 다음과 같습니다:

  • Kubernetes v1.28.x
  • Istio 1.21.2
  • NGINX Plus Ingress Controller 3.5.0

해당 테스트는 “nginx-ingress”라는 namespace에 대한 서비스에 적용시켰습니다.

NGINX Plus Ingress Controller는 NodePort 타입으로 30000 포트에 할당되어 있습니다.

$ kubectl get svc nginx-ingress -n nginx-ingress
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
nginx-ingress   NodePort    10.106.24.138   <none>        80:30000/TCP,443:30001/TCP   4d4h

Service 및 Deploy:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: coffee
  namespace: nginx-ingress
spec:
  selector:
    matchLabels:
      app: coffee
  template:
    metadata:
      labels:
        app: coffee
    spec:
      containers:
      - name: coffee
        image: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: coffee-svc
  namespace: nginx-ingress
spec:
  ports:
  - port: 80
    targetPort: 80
    name: http-coffee
  selector:
    app: coffee
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tea
  namespace: nginx-ingress
spec:
  selector:
    matchLabels:
      app: tea 
  template:
    metadata:
      labels:
        app: tea 
    spec:
      containers:
      - name: tea 
        image: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: tea-svc
  namespace: nginx-ingress
spec:
  ports:
  - port: 80
    targetPort: 80
    name: http-tea
  selector:
    app: tea

VirtualServer:

apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
  name: cafe
  namespace: nginx-ingress
spec:
  host: hodevops.nginxstore.kr
  upstreams:
  - name: tea
    service: tea-svc
    port: 80
  - name: coffee
    service: coffee-svc
    port: 80
  routes:
  - path: /coffee
    action:
      proxy:
        upstream: coffee
        rewritePath: /
  - path: /tea
    action:
      proxy:
        upstream: tea
        rewritePath: /

2. Istio JWT 요청 인증 정의하기

Istio에서는 RequestAuthentication 리소스를 사용하여 JWT 인증 정책을 정의합니다. 이 리소스는 어떤 JWT 발급자(Issuer)를 사용할 것인지, 그리고 JWT 인증에 필요한 정보(예: JWKS URI)를 지정합니다.

이 예시에서는 위에서 작성한 coffee 서비스에 대해 JWT 인증을 활성화합니다.

apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
  name: jwt-example
  namespace: nginx-ingress
spec:
  selector:
    matchLabels:
      app: coffee
  jwtRules:
  - issuer: "testing@secure.istio.io"
    jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.21/security/tools/jwt/samples/jwks.json"

여기서 사용한 jwksUri 는 Istio에서 제공하는 테스트용JWKS URI입니다.

위에서 작성한 RequestAuthentication 리소스를 저장 및 배포한 뒤, 확인합니다.

$ kubectl apply -f requestauthentication.yaml
requestauthentication.security.istio.io/jwt-example created

# ra는 RequestAuthentication의 약자입니다.
$ kubectl get ra -A 
NAMESPACE       NAME          AGE
nginx-ingress   jwt-example   54s

3. Istio JWT 승인 정책 활성화

해당 요청이 서비스에 대한 접근 권한을 가지고 있는지를 확인하기 위해 AuthorizationPolicy 리소스를 사용합니다. 실제로 서비스에 대한 접근 제어는 AuthorizationPolicy 리소스를 사용하여 특정 조건(예: 유효한 JWT 토큰을 제시해야 함)에 따라 접근을 허용하거나 거부합니다.

해당 예시에서는 유효한 JWT 토큰을 제시해야 접근을 허용하도록 하는 구성입니다:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: require-jwt
  namespace: nginx-ingress
spec:
  selector:
    matchLabels:
      app: coffee
  action: ALLOW
  rules:
  - from:
    - source:
        requestPrincipals: ["*"]

여기서 requestPrincipals: [“*”] 필드를 사용함으로써 JWT 토큰이 유효하기만 하면 허용하겠다는 의미이며, requestPrincipals 필드는 issuer/sub 형식을 사용하여 특정 조합으로부터 오는 요청만 허용하도록 구성할 수 있습니다.

4. JWT 인증 테스트

위에서 작성한 RequestAuthentication과 AuthorizationPolicy를 배포한 뒤, curl 명령어를 사용하여 coffee 서비스에 접근합니다.

$ curl hodevops.nginxstore.kr:30000/coffee -I

HTTP/1.1 403 Forbidden
server: istio-envoy
date: Mon, 13 May 2024 06:28:47 GMT
content-type: text/plain
content-length: 19
x-envoy-upstream-service-time: 4
x-envoy-decorator-operation: nginx-ingress.nginx-ingress.svc.cluster.local:80/*

status code 403을 반환하여 JWT 인증이 활성화된 것을 확인할 수 있습니다.

반대로 tea 서비스에 접근해보면:

$ curl hodevops.nginxstore.kr:30000/tea -I

HTTP/1.1 200 OK
server: istio-envoy
date: Mon, 13 May 2024 06:30:11 GMT
content-type: text/html
content-length: 615
last-modified: Tue, 16 Apr 2024 14:29:59 GMT
etag: "661e8b67-267"
accept-ranges: bytes
x-envoy-upstream-service-time: 9
x-envoy-decorator-operation: nginx-ingress.nginx-ingress.svc.cluster.local:80/*

JWT 인증을 활성화하지 않았기 때문에 정상적으로 접근이 됩니다.

JWT를 헤더에 삽입하여 coffee 서비스에 접근해봅니다:

$ curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9zP7c-LS9qd_vpdLG4Tn1A15NxfCjp5f7QNBUo-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZzvc7M__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCgefSj_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvHsU60_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8NxUg" hodevops.nginxstore.kr:30000/coffee -I

HTTP/1.1 200 OK
server: istio-envoy
date: Mon, 13 May 2024 07:30:56 GMT
content-type: text/html
content-length: 615
last-modified: Tue, 16 Apr 2024 14:29:59 GMT
etag: "661e8b67-267"
accept-ranges: bytes
x-envoy-upstream-service-time: 6
x-envoy-decorator-operation: nginx-ingress.nginx-ingress.svc.cluster.local:80/*

유효한 JWT를 가지고 요청시 정상적으로 접근되는 것을 확인할 수 있습니다.

Istio JWT Token에 대해 자세한 가이드는 공식 페이지를 확인하세요.

NGINX Plus를 직접 사용해 보시려면 30일 무료 평가판을 신청하거나 NGINX STORE에 연락하여 논의하십시오.

NGINX STORE를 통한 솔루션 도입 및 기술지원 무료 상담 신청

* indicates required