msa
istio에 jwt 검증 proxy 추가하기

istio에 jwt 검증 proxy 추가하기

서비스 메시란?

  • API Gateway 와 서비스 메시는 다르다, 구조가 다름
  • 서비스메시의 인증은 API 게이트웨이단에서의 사용자 인증과는 거리가 멈, 허가된 사용자의 요청인지 확인하는 것은 애플리케이션 보안단(API 게이트웨이 등)에서 해야할 일이며, 서비스메시에서의 보안은 TLS 등의 패킷 자체에대한 보안으로 보임

picture 0

rke 환경에서 istio 설치하기

istioctl 사용

istioctl 다운로드

curl -L https://istio.io/downloadIstio | sh -
cd istio-*
export PATH=$PWD/bin:$PATH

istio 설치

istioctl install --set profile=demo -y

설치 상태 확인

kubectl get pods -n istio-system

출력 예시

NAME                                    READY   STATUS    RESTARTS   AGE
istio-ingressgateway-6fdd76d6d7-mz9ps   1/1     Running   0          2m
istiod-8454df4fbb-7z8xz                 1/1     Running   0          2m

RequestAuthentication 와 AuthorizationPolicy 셋팅하기

RequestAuthentication 란?

RequestAuthentication은 HTTP 요청에서 JWT 검증을 수행하기 위한 리소스.

requestAuthentication-yaml
apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
  name: httpbin
  namespace: foo
spec:
  selector:
    matchLabels:
      app: httpbin
  jwtRules:
  - issuer: "issuer-foo"
    jwksUri: https://example.com/.well-known/jwks.json
  • selector : app: httpbin 라벨이 있는 Pod에 적용
  • jwtRules : JWT 토큰의 검증 규칙을 정의
  • issuer : JWT 토큰의 iss 클레임 값과 비교하여 발급자를 검증.
  • jwksUri : JWT 토큰 서명을 검증하기 위한 공개 키를 포함한 JWKS URI.

AuthorizationPolicy 란?

요청을 필터링하거나 특정 조건에 맞는 요청만 허용하기 위해 사용

AuthorizationPolicyapp 별로 적용되기에 적용되어야할 app 이 여러개라면 똑같이 여러개의 AuthorizationPolicy 를 생성해야한다

authorization-policy.yaml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: jwt-authz-policy
  namespace: my-namespace
spec:
  selector:
    matchLabels:
      app: my-app
  rules:
    - from:
        - source:
            requestPrincipals: ["*"]
      to:
        - operation:
            methods: ["GET", "POST"]
  • apiVersion : Istio의 보안 리소스가 사용하는 API 버전.
  • kind : 리소스 유형. 여기서는 AuthorizationPolicy를 정의.
  • metadata.name : 리소스의 이름.
  • metadata.namespace : 이 정책이 적용될 네임스페이스.
  • spec.selector : 정책이 적용될 대상 Pod를 지정, Pod에 할당된 라벨과 matchLabels 조건이 일치하는 경우 정책이 적용.
  • spec.selector.matchLabels : 라벨 기반 선택기. 특정 Pod를 지정하기 위해 라벨과 일치하는 조건을 설정.
  • spec.rules : 요청을 허용하거나 차단하기 위한 규칙
  • from : 요청의 출처를 기반으로 필터링.
  • from.source : 요청의 출처를 정의.
  • from.requestPrincipals : JWT 토큰의 주체 (sub 또는 iss/sub)에 따라 요청 필터링. *은 모든 요청을 허용.
  • to : 요청의 대상(HTTP 메서드, 경로 등)을 기반으로 필터링.
  • to.operation : 요청의 속성(HTTP 메서드, 경로 등)을 정의.
  • to.methods : 허용할 HTTP 메서드 (예: GET, POST).
  • to.paths : 특정 경로를 필터링.

RequestAuthentication + AuthorizationPolicy

RequestAuthentication
apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
  name: httpbin
  namespace: foo
spec:
  selector:
    matchLabels:
      app: httpbin
  jwtRules:
  - issuer: "issuer-foo"
    jwksUri: https://example.com/.well-known/jwks.json

namespace 전체에 적용하는 쉬운 방법은 selector: {} 와 같이 설정하면 되는데, 이러면 Warning: workload selector specified without labels 경고가 발생한다, istio는 namespace전체에 그냥 냅다 적용하는 방식을 권장하지 않는 것으로 보인다 특별한 이유가 없다면 selector.matchLabels.app 까지 명시하는게 좋아보인다.

AuthorizationPolicy
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: httpbin-policy
  namespace: foo
spec:
  selector:
    matchLabels:
      app: httpbin
  rules:
  - from:
      - source:
          requestPrincipals: ["issuer-foo/subject@example.com"]

등록 방법

kubectl apply -f authorization-policy.yaml

kubectl apply -f peer-authentication.yaml

사이드카 주입

여기서 사이드카소프트웨어 설계에서 주 애플리케이션 컨테이너와 함께 실행되는 보조 컨테이너를 의미한다

jwt검증을 해주는 istio-proxy 를 각 파드별로 사이드카 등록을 해줘야한다

  1. 네임스페이스에 사이드카 주입 라벨이 설정되어있는지 확인

kubectl get namespace <namespace name> --show-labels

출력에 istio-injection=enabled 라벨이 없으면 추가

kubectl label namespace <namespace name> istio-injection=enabled

  1. Deployment를 다시 배포하여 사이드카가 주입되도록 변경

kubectl rollout restart deployment <deployment name> -n <namespace name>

  1. 재배포된 Pod에 istio-proxy가 포함되었는지 확인

kubectl describe pod <pod-name> -n <namespace name>

만약 사이트카를 해제하고 싶다면?

네이스페이스에 사이트카 주입을 비허용시키고 사이트주입을 해제하고 싶던 디플로이먼트를 재시작하면된다

  1. 네임스페이스 라벨 확인

kubectl get namespace <namespace-name> --show-labels

  1. 라벨 제거

kubectl label namespace <namespace-name> istio-injection-

  1. Deployment를 다시 배포하여 사이드카 주입이 해제되도록 변경

kubectl rollout restart deployment <deployment name> -n <namespace name>

아예 특정 Deployment 에 사이트카 주입이 안되도록 하려면?

해당 deploment의 yaml 에 metadata.annotations.sidecar.istio.io/inject: "false" 를 지정하면된다

아래는 yaml 의 예시이다

sample-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-app
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: example-app
  template:
    metadata:
      labels:
        app: example-app
      annotations:
        sidecar.istio.io/inject: "false" # 사이드카 주입 비활성화
    spec:
      containers:
        - name: example-app
          image: example-app:latest

jwkUri 로 부터 keyset 을 가져왔는지 확인하는 방법

Istio Control Plane (istiod) 로그 확인

  • kubectl get pods -n istio-system 명령어로 istiod pod name 확인
NAME                                    READY   STATUS    RESTARTS   AGE
istio-egressgateway-568ccc69d8-ccftb    1/1     Running   0          43d
istio-ingressgateway-64fc6d787b-5lxjm   1/1     Running   0          43d
istiod-cdfc8b464-gwbxd                  1/1     Running   0          43d
  • kubectl logs -n istio-system istiod-cdfc8b464-gwbxd 과 같이 istiod pod name을 넣어서 로그 확인