Istio를 통한 header기반 API 라우팅/호출 시 cors preflight request 이슈 트러블슈팅 기록

Istio를 통한 header기반 API 라우팅/호출 시 cors preflight request 이슈 트러블슈팅 기록
Photo by Chris Leipelt / Unsplash

현재 개발하고 있는 일부 컨테이너 기반의 서비스들을 Istio를 통해 서비스들을 구성하고 트래픽을 관리하고 있다.

이때 컨테이너 서비스가 같은 규격이 여러개가 같은 url과 port를 할당 받아서 사용해야는 애로 사항이 있어 Istio에서 header 기반으로 특별한 헤더가 있는 경우에만 라우팅이 될 수 있도록 구성하고 테스트를 진행했었다.

Istio Request Routing 예제와 같이 headermodel-api-key 값에 따라 정확하게 매치된 요청만 지정한 서비스로 라우팅 되도록 설정하였다.

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  generation: 1
  labels:
    cheetah.xxx: xxx
  name: ...
  namespace: cheetah
spec:
  gateways:
  - model-deployment-gateway
  hosts:
  - '*'
  http:
  - match:
    - headers:
        model-api-key:
          exact: "xyz"
    route:
    - destination:
        host: model-deploy-01j46dj4ah5abd1zz8pc21vkg9
        port:
          number: 8000

curl 이나 기타 다른 도구들로 테스트 시에는 큰 문제가 되진 않았는데, 브라우저에서 해당 API를 호출해서 뭔가 메타데이터를 얻어오는 경우가 있었는데, 당연하게도 서비스되는 도메인이 같지 않고 IP 기반으로 서비스를 하다보니 CORS(교차 출처 리소스 공유) 이슈가 발생했었다.

브라우저에서는 CORS를 검증하기 위한 pre-flight(사전 검증 요청) 요청을 특별한 헤더(Options)와 함께 던져서 유효한 요청인지 검증 받고 실제 API를 요청하는데 이 과정에서 아래와 같이 오류가 발생했다.

Access to XMLHttpRequest at ‘https://myapi.com/Form’ from origin ‘https://myui.net’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: Redirect is not allowed for a preflight request.

CORS Preflight 와 관련된 절차와 자세한 내용은 아래의 문서들이 진짜 정리(진리의MDN)가 잘되어 있다. 한번 훑어 보시길 권장한다.

Fetch Standard
Cross-Origin Resource Sharing (CORS) - HTTP | MDN
Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources. CORS also relies on a mechanism by which browsers make a “preflight” request to the server hosting the cross-origin resource, in order to check that the server will permit the actual request. In that preflight, the browser sends headers that indicate the HTTP method and headers that will be used in the actual request.

어찌됐든 일반적인 CORS 관련된 설정이거니 해서 공식 Istio 문서에서 Cors Policy 를 보고 아래와 같이 수정해서 테스트를 다시 진행했다.

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  generation: 1
  labels:
    cheetah.xxx: xxx
  name: ...
  namespace: cheetah
spec:
  gateways:
  - model-deployment-gateway
  hosts:
  - '*'
  http:
  - corsPolicy:
      allowCredentials: true
      allowHeaders:
      - authorization
      - content-type
      - accept
      - origin
      - user-agent
      - model-api-key
      allowMethods:
      - POST
      - GET
      - PUT
      - DELETE
      - OPTIONS
      allowOrigins:
      - exact: '*'
      maxAge: 24h
    match:
    - headers:
        model-api-key:
          exact: "xyz"
    route:
    - destination:
        host: model-deploy-01j46dj4ah5abd1zz8pc21vkg9
        port:
          number: 8000

corsPolicyallowHeaderallowMethds에 허용할 값들을 위처럼 잘 설정하고 다시 테스트 해보는데 이번엔 뜬금없이 404 not found가 나고 있다.

다시 한번 절차데로 제대로 되고 있는지 이것저것 로그를 확인해 보았다.

MDN Pre-flight request

위 그림 처럼 가장 첫번째 Preflight 요청을 날리는 시점이 문제였다. 해당 부분은 axiosfetch 같은 라이브러리를 사용하여 날리는 요청이 아니라 브라우저 에서 CORS 확인을 위해 준비되는 절차인데, 특별한 헤더를 사용한 요청 즉 model-api-key라는 헤더를 통해 istio로 라우팅 한 경우가 문제가 되고 있었다.

브라우저에서 Options 메소드로 Preflight 검증 요청 시에는 custom header를 지원하지 않는 것이었다.

당연히 커스텀 헤더가 없어서 라우팅할 서버가 없기 때문에 404 오류가 발생되었다.

Istio의 설정으로 뭔가 가능하지 않을까 싶었지만 결국엔 방법을 찾진 못했고 결국엔 같은 url와 port로 떠 있는 preflight 검증용 dummy 서버를 만들어서 띄워두고 preflight 검증 시에는 dummy 서버로 요청하고 실 요청은 헤더를 기반으로 요청하게끔 기능은 변경 하였다.

정리

  • CORS 처리 절차에 대해서 숙지 필요
  • Istio와 상관 없이 브라우저에서 Preflight 요청에서는 사용자 정의 header가 포함되진 않는다.
  • Istio가 아니더라도 custom header를 반드시 사용해야 하는 경우라면 dummy 서비스를 하나 띄워두고 preflight와 본 요청을 분리하여 사용한다.

Read more

나의 프로그래밍 폰트 사용 일대기

나의 프로그래밍 폰트 사용 일대기

시작은 2003년 이제 막 프로그래머로써 첫발을 내딛을 때부터 나는 프로그래밍 폰트에 대해서 관심이 많은 편이었다. 화면 붙잡고 매일 글자들과 씨름하는 직업이다보니 당연하게도 좀더 눈에 잘 보이고, 보기에 좀더 미려하고 조화스러운 폰트를 찾는 것이 어찌보면 약간 본능(?)적으로 관심을 가졌던게 아닌가 싶기도 하고 말이다. 최근까지도 이 주체할 수 없는 본능에 따라

By Kevin H. Kwon
Istio 를 통한 path(url) 기반 Local Rate Limit 적용

Istio 를 통한 path(url) 기반 Local Rate Limit 적용

몇 년 전인지는 기억나진 않지만 Rate Limit 적용은 항상 애플리케이션 쪽에서 처리하는 것이 당연하다는 것이 주된 의견이었다. 그래서 그때 당시 Bucket4J 를 통해서 Spring 쪽에서 처리하고 했던 기억이 있다. 이제는 당연하게도 Istio와 같은 Service Mesh쪽에서 처리하는 것이 응당 맞다고 생각되는 것이 개발 세상이 이제 점점 더 클라우드향으로 이동된다는 느낌이다. 강력한

By Kevin H. Kwon
Kubernetes cluster에 Feature gates 활성화 방법

Kubernetes cluster에 Feature gates 활성화 방법

최근에 nvidia a100 gpu를 mig로 나눠서 사용 하는 노드에서 cadvisor가 gpu metric을 수집을 잘 못해서 kubulet에서 계속 오류가 떨어져서 트러블슈팅을 진행했었다. dcgm-exporter로 prometheus로 metric을 수집하고 있어서 굳이 cadvisor에서 nvidia accelerator meric을 수집할 이유가 없어져서 이것저것 자료를 찾아보니 1.19 버전부터는 DisableAcceleratorUsageMetrics feature gates로 해당 수집 옵션을 비활성화 시킬 수 있는

By Kevin H. Kwon