Introduction
대표적 Service Mesh 제품인 Istio에 대한 overview로 Kubernetes를 배경으로 설명한다.
Summary
•
보안 관점에서 Istio는 ZTA(Zero Trust Architecture)를 추구하는 것으로 보인다.
•
Istio는 사용자 관점 보안으로 JWT/JWK 기반의 OIDC(OpenID Connect)를 지원한다.
•
Istio는 서비스 관점 보안으로 mTLS 및 SPIFFE(Secure Production Identity Framework for Everyone)를 지원한다.
•
AuthorizationPolicy 를 통해 L7 수준에서 access control이 가능하다.
Security
Istio는 ZTA(Zero Trust Architecture)를 추구하는 것으로 보이는데, 실제 위 공식 문서는 Zero Trust network를 언급한다. 이는 Istio가 multi clusters 및 외부 host가 포함된 환경도 지원함을 고려하면 충분히 이해되는 부분이다(이들 환경에서는 traffic이 보호되지 않거나 보안 정책이 상이한 구간을 지나기 마련이다).
ZTA; Zero Trust Architecture란 (하기 링크 요약)
경계 없는 보안(perimeterless security)로도 불리는 ZTA의 주요 개념은 "신뢰하지 않고 항상 확인"이다. 이는 위치에 관계 없이 resource에 접근하는 user와 device가 기본적으로 신뢰 불가하다는 뜻으로, LAN, VPN 등 전통적 보안 요소가 클라우드 서비스, 인프라, IoT 서비스 등의 현대 network 환경에서는 부족하다는 인식에 근간한다.
ZTA는 기본적으로 user와 device 모두에 대한 인증과 최소 권한 부여를 요구하여, 전체 구현에는 향상된 ID 거버넌스 및 정책 기반 액세스 제어, 마이크로 세분화, 오버레이 네트워크(overlay network)가 포함된다.
위의 ZTA 설명 중 오버레이 네트워크가 특히 눈에 띄는데, Service Mesh, 즉 Istio 자체가 일종의 오버레이 네트워크이기 때문이다.
맨 앞의 그림은 이러한 관점에서의 Istio의 보안 features 전체의 요약으로, Istio의 보안 서비스는 사용자와 서비스 관점 보안으로 나눠 볼 수 있어, 각각 좌측과 우측에 해당한다. 양자 공통으로 인증(AuthN; AutheNtication), 인가(AuthZ; AuthoriZation)를 제공하는데, 서비스 관점 보안에서는 mTLS을 통해, 기밀성, 무결성, 부인방지가 추가된다. 사용자 관점에서 이는 불필요한데, 일반적으로 public CA(Certificate Authority) 관리 하에 TLS가 동작하기 때문이다.
참고로, AAA(Authentication, Authorization, Audit) 중 Audit은 아래 설명할 AuthorizationPolicy 의 action 에서 AUDIT (logging)으로 동작한다. 이외에도
Istio overview: Observability에서 논한 (Access) Logs는 Audit을 위한 장치로 볼 수 있다.
사용자 관점 보안 via OIDC, RequestAuthentication
Istio의 사용자 보안 구조
사용자 인증으로는 대표적인 인증 프로토콜인 JWT/JWK, OAuth 2.0 기반의 OpenID Connect(OIDC)를 지원한다. RequestAuthentication Istio resource는 IdP(ID Provider) 정보 및 적용할 workload를 지정하기 위해 사용한다.
아래는 위 공식 문서에 담긴 RequestAuthentication 및 AuthorizationPolicy 예를 의미를 명확히 하기 위해 일부 수정한 코드로, app:httpbin 인 workload에 접근을 위해서는 issuer-foo 란 IdP(ID Provider)가 발급한 JWT에, Host header가 httpbin.com 인 request 일 경우에만 허용함을 의미한다.
apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
name: httpbin
namespace: foo
spec:
selector:
matchLabels:
app: httpbin # app:httpbin label을 가진 workload에 적용. 없을 경우 namespace(foo)의 모든 workload에 적용됨.
jwtRules:
- issuer: "issuer-foo" # IdP 지정. JWT의 ISS에 해당: https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1
jwksUri: https://issuer-foo.com/.well-known/jwks.json # IdP의 JWKS endpoint (JWT validation 용도)
---
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: httpbin
namespace: foo
spec:
selector:
matchLabels:
app: httpbin # app:httpbin label을 가진 workload에 적용. 없을 경우 namespace(foo)의 모든 workload에 적용됨.
rules:
- from:
- source:
requestPrincipals: ["issuer-foo/*"] # JWT의 "<ISS>/<SUB>"에 매칭
to:
- operation:
hosts: ["httpbin.com"] # HTTP request의 Host header value에 매칭
YAML
복사
서비스 관점 보안 via mTLS, SPIFFE
Istio의 서비스 보안 구조
서비스 관점 보안에서 Istio의 가장 큰 특징은 mTLS와 SPIFFE로서, 이들 서비스는 자동으로 여타 Istio 서비스에 통합된다.
먼저, mTLS는 mutual TLS의 약자로 TLS에 쌍방향 인증 서비스를 추가한다는 점을 제외하고는 TLS와 동작 방식이 동일하다. SPIFFE(Secure Production Identity Framework for Everyone)는 서비스를 안전하게 식별하기 위한 open-source 표준으로 mTLS 기반 위에 동작한다. 참고로, Istio 및 Kubernetes 뿐 아니라 AWS, GCP, Azure 등 주요 CSP가 SPIFFE를 지원 중 이다(참고).
다음은 Istio 기반의 mTLS, SPIFFE 특징이다.
•
SPIFFE ID: workload ID based on k8s ServiceAccount
◦
SPIFFE ID는 workload 식별자로서 k8s ServiceAccount 에 기반
◦
e.g. spiffe://cluster.local/ns/cluster/sa/dockebi
•
SVID : SPIFFE ID in X.509 certificate
◦
SVID 는 SPIFFE Verifiable Identity Document의 약자로 SPIFFE ID가 담긴 문서를 의미.
◦
문서 format으로 JWT도 사용되나, Istio는 X.509 certificate을 사용하여 SAN(Subject Alternative Name)내 URI에 SPIFFE ID가 위치.
•
istiod as a CA(Certificate Authority) / SPIFFE Workload API
◦
istiod 는 X.509 SVID 를 각 workload에 발급함으로 SVID 발급 주체를 의미하는 SPIFFE Workload API 역할을 수행
•
Istio proxy as SPIFFE Endpoint
◦
Istio Proxy 간 통신은 SVID 기반으로 mTLS 상에 이루어짐으로 SPIFFE Workload Endpoint 역할을 수행
•
외부 SPIRE 서버 연동 지원
◦
istiod 대신 외부 SPIRE(SPIFFE Runtime Environment) 서버가 발급한 SVID 기반으로 동작 가능. https://istio.io/latest/docs/ops/integrations/spire/ 참고.
# URI(client): dockebi-tock
# By(current proxy): dockebi-storage
# Hash: SHA 256 digest of the client certificate
"X-Forwarded-Client-Cert": 'By=spiffe://cluster.local/ns/cluster/sa/dockebi-storage;Hash=252bad1a52c5523d594fbd1bb75a586b413ce501993946a27c8161b552062eaf;Subject="";URI=spiffe://cluster.local/ns/cluster/sa/dockebi-tock',
YAML
복사
참고로 사용자 인증(RequestAuthentication)에 대비되는 PeerAuthentication 란 Istio resource도 있는데, namespace, worload, port 단위로 mTLS 적용 수준(DISABLE, STRICT, PERMISSIVE)을 지정하는 기능 이외에는 없으며 Ambient mode에서는 사용되지 않는다고 한다. 별도 지정이 없으면 PERMISSIVE (mTLS 이외의 통신도 가능)로 동작하는데, 공식 문서는 보안 mTLS에만 허용된 resource에 대한 잘못된 접근 가능성으로 인해 STRICT를 권장한다.
서비스 간 보안에 사용되는 인가(AuthorizationPolicy)에 대해서는 아래에서 설명한다.
AuthorizationPolicy : Access Control in L7
앞서 논했듯 Istio는 사용자, 서비스 모두에 대한 access control을 위해 AuthorizationPolicy 를 사용한다. Kubernetes NetworkPolicy에 비교할 수 있는데, Kubernetes NetworkPolicy가 L4까지의 대응이라면 AuthorizationPolicy 는 L7까지의 대응이다.
주요 요소는 다음과 같다.
•
selector : 해당 AuthorizationPolicy가 적용될 target workload 지정. 생략될 경우 해당 namespace의 모든 workload에 적용됨.
•
action : request를 수용( ALLOW ; default)할지, 거부(DENY)할지 등의 정책을 지정. AUDIT 은 log에 기록만 하고, CUSTOM 은 외부의 policy의 평가 결과를 따른다.
•
rules action 이 수행될 조건을 지정
◦
from : request의 source를 지정
◦
to : 해당 정책이 적용될 구체적 대상을 지정
◦
when : 기타 상세 조건을 지정
아래 코드는 서비스 간 보안 상에서의 AuthorizationPolicy 예로, 아래는 코드에 대한 설명이다.
•
target workload: app:httpbin-backend label을 가진 workload 및
•
target operations: GET /info*, POST /data endpoints에 정책이 적용되어,
•
when: https://issuer-foo.com 에서 발급한 JWT가 request에 있고,
•
source: service account가 foo namespace에 name이 httpbin 인 workload 또는 test namespace인 workload만 target 접근(ALLOW) 가능
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: httpbin-backend
namespace: foo
spec:
action: ALLOW # default. rules에 지정된 규칙에 일치하는 request만 access 허용. DENY의 경우 access 거부를 의미.
selector:
matchLabels:
app: httpbin-backend # app:httpbin-backend label을 가진 workload에 적용. 없을 경우 namespace(foo)의 모든 workload에 적용됨.
rules:
- from:
- source:
principals: ["cluster.local/ns/foo/sa/httpbin"]
- source:
namespaces: ["test"]
to:
- operation:
methods: ["GET"]
paths: ["/info*"]
- operation:
methods: ["POST"]
paths: ["/data"]
when:
- key: request.auth.claims[iss]
values: ["https://issuer-foo.com"]
YAML
복사
References
본 글 작성에 주로 참조한 문서이다.