istio에 jwt 검증 proxy 추가하기
서비스 메시란?
- API Gateway 와 서비스 메시는 다르다, 구조가 다름
- 서비스메시의 인증은 API 게이트웨이단에서의 사용자 인증과는 거리가 멈, 허가된 사용자의 요청인지 확인하는 것은 애플리케이션 보안단(API 게이트웨이 등)에서 해야할 일이며, 서비스메시에서의 보안은 TLS 등의 패킷 자체에대한 보안으로 보임
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 검증을 수행하기 위한 리소스.
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 란?
요청을 필터링하거나 특정 조건에 맞는 요청만 허용하기 위해 사용
AuthorizationPolicy
는 app
별로 적용되기에 적용되어야할 app
이 여러개라면 똑같이 여러개의 AuthorizationPolicy
를 생성해야한다
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
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
까지 명시하는게 좋아보인다.
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 를 각 파드별로 사이드카 등록을 해줘야한다
- 네임스페이스에 사이드카 주입 라벨이 설정되어있는지 확인
kubectl get namespace <namespace name> --show-labels
출력에 istio-injection=enabled 라벨이 없으면 추가
kubectl label namespace <namespace name> istio-injection=enabled
- Deployment를 다시 배포하여 사이드카가 주입되도록 변경
kubectl rollout restart deployment <deployment name> -n <namespace name>
- 재배포된 Pod에 istio-proxy가 포함되었는지 확인
kubectl describe pod <pod-name> -n <namespace name>
만약 사이트카를 해제하고 싶다면?
네이스페이스에 사이트카 주입을 비허용시키고 사이트주입을 해제하고 싶던 디플로이먼트를 재시작하면된다
- 네임스페이스 라벨 확인
kubectl get namespace <namespace-name> --show-labels
- 라벨 제거
kubectl label namespace <namespace-name> istio-injection-
- Deployment를 다시 배포하여 사이드카 주입이 해제되도록 변경
kubectl rollout restart deployment <deployment name> -n <namespace name>
아예 특정 Deployment 에 사이트카 주입이 안되도록 하려면?
해당 deploment의 yaml 에 metadata.annotations.sidecar.istio.io/inject: "false"
를 지정하면된다
아래는 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을 넣어서 로그 확인