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에 연락하여 논의하십시오.