본문 바로가기

DevOps

[Istio] EKS에서 Okta와 AWS ALB, Istio를 활용하여 인증, 인가 처리하기

반응형

1. 개요

Application 단에서 Okta 인증 로직을 구현하는 것보다 AWS ALB 혹은 Istio를 통해 구현하게 된다면 로직을 상당히 줄일 수 있을 것이라 생각하였다.

 

Okta + AWS ALB + Istio를 구현하기 위해서는 다음의 지식들이 필요하다.

 


[Okta]

- JWT / OIDC / OAuth2.0 / SAML
    - ClientID, ClientSecret
    - Endpoints (Userinfo, Ahthorize, Token, ..)
        
- Org Authorization Server , Custom Authorization Server


[AWS]

- AWS Listener Authentication (OIDC)
    - x-amzn-oidc-accesstoken, x-amzn-oidc-identity, x-amzn-oidc-data    

 


[Istio]

- RequestAuthentication , AuthorizationPolicy
- Debugging (Istio ProxyConfig, Istio Log Level)

 

2. 개념 정리

OIDC

OpenID Provider : ID Token을 발급해주는 Authorization server

end user : ID Token을 포함한 End User 정보

replying party : Okta로부터 ID Token을 요청하는 Client Application

ID Token : OpenID Provider에 의해 발급되는 Token이며 엔드 유저의 Claims를 가지고 있음

Claim : End user의 정보 모음

 

OAuth 2.0

authorization server : Access Token을 발급

resource owner : Application 엔드 유저 (권한을 부여)

client : Okta로부터 Access Token을 부여받고 resource server로 접근

resource server : Access Token을 받고 유효한지 확인

 

OAuth 2.0 grant : Authorization code , Client credentials

access token : Authorization server(Okta)에 의해 발급받는 Token

refresh token : 새로운 액세스 토큰을 교환받기 위한 Token (Optional)

 

Flow

[1] Client requests authorization from the resource owner

[2] If the user gives authorization, the client passes the authorization grant to the authorization server (in this case Okta).

[3] If the grant is valid, the authorization server returns an access token, possibly alongside a refresh and/or ID token.

[4] The client now uses that access token to access the resource server

 

Authorization Code flow with PKCE(Proof Key for Code Exchange)

서버 측(웹), 기본 또는 모바일에 관계없이 대부분의 애플리케이션에 권장되는 흐름

 

SAML 2.0 Assertion flow

 

API Access Management


ID Token (OpenID Connect) , Access Token (OAuth 2.0)
ID : User Profile ( Open ID Connect = Thin ID & Fat ID )

ID, Access Token (Thin ID) 이외에 추가 정보를 제공받으려면 access token을 이용해서 /userinfo 엔드포인트를 호출해야 한다. → Fat ID Token

Authorization Server

[1] Org Authorization Server
SSO, Okta API에 대한 Access Token
Issuer : https://{OktaOrg}
Open ID : https://$yourOktaOrg}/.well-known/openid-configuration
OAuth : https://${yourOktaOrg}/.well-known/oauth-authorization-server

[2] Custom authorization server
OpenID : https://${yourOktaDomain}/oauth2/${authorizationServerId}/.well-known/openid-configuration
OAuth : https://${yourOktaDomain}/oauth2/${authorizationServerId}/.well-known/oauth-authorization-server

 

 

3. Okta, Istio 연동

Ref : https://zdenek-papez.medium.com/istio-authorization-using-okta-user-groups-in-jwt-claims-behind-aws-application-load-balancer-191f26779cad

 

Istio는 Service Mesh 도구이며 Okta는 IDP(Identity Provider)로써의 역할을 수행하는 SaaS 서비스이다.

 

EKS를 기반으로 Okta 및 AWS ALB와 함께 Istio에서의 인증, 인가 처리를 수행하도록 설정해 볼 예정이다.

 

 

(처음에 Nginx로 하려했다가 HTTPBin으로 변경했는데 귀찮아서 그냥 Nginx라고 그대로 둔 부분이 많으니 참고할 것)

 

3.1. 아키텍쳐

사용자는 oktaauthdemo.xxxxx.xxx 으로 접근한다. 이는 Route 53에서 ALB와 연결되어 있다.

유효햔 JWT가 있는지 확인하고 없을 경우 Okta로 Redirect가 된다.

 

Okta에서 인증이 정상적으로 수행되면 Istio Ingress Gateway로 전달되고 Ingress Gateway에서 Authentication, Authorization을 수행하게 된다.

 

 

3.2. Okta 설정

App을 생성해준다.

Sign-in Method : OIDC -OpenID Connect

Application Type : Web Application

 

General 탭에서 General Settings 설정

 

Grant Type : Implicit 체크

Sign-in redirect URIs : Path에 ‘/oauth2/idpresponse’ 추가

 

 

Sign On 탭에서 OpenID Connect ID Token 설정

 

Assignments에서 ‘nginxGroup’ 설정

 

3.3. ALB Listener Rule 설정

해당 ALB는 Istio로 생성한 ALB이다.

 

Authentication 클릭

 

API Authorization Server는 API 탭에서 확인할 수 있다. 해당 서비스는 인당 2$ 과금이 되는 유료 서비스인데 테스트는 Trial 계정으로 진행하기 때문에 보인다.

 

https://XXXXX.okta.com/oauth2/default/.well-known/oauth-authorization-server 로 접근하면 Issuer 등에 대한 정보를 확인할 수 있다.

 

Issuer, Authorization endpoint, Token endpoint, User info endpoint를 입력해주고

Client ID, Client Secret은 General 탭에서 확인 후 복붙해준다.

 

Scope은 openid, profile로 설정해준다.

 

3.4. Istio Gateway, Virtual Service 설정

 

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: okta-aws-nginx
  namespace: oktademo
spec:
  selector:
    istio: istio-ingressgateway-okta-alb
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - "oktaauthdemo.xxxxx.xxx"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: okta-aws-nginx
  namespace: oktademo
spec:
  hosts:
    - "oktaauthdemo.xxxxx.xxx"
  gateways:
    - mesh
    - okta-aws-nginx
  http:
    - route:
        - destination:
            port:
              number: 80
            host: nginx.oktademo.svc.cluster.local

 

이렇게 하고 oktaauthdemo.xxxxx.xxx 으로 시크릿창에서 접속하면 Okta 로그인 페이지가 나온다.

그리고 httpbin 화면이 뜨는 것을 확인할 수 있다.

 

/headers 경로로 접근하면 HTTP Header가 보일텐데 여기서 X-Amzn-Oidc-Accesstoken

을 Decode 해보자.

 

PAYLOAD가 Okta로부터 잘 전달된 것을 확인할 수 있다.

 

우리는 이것을 활용해 Istio에 RequestAuthentication, AuthorizationPolicy로 인증, 인가를 수행해 볼 예정이다.

 

3.5. Istio RequestAuthentication 설정

 

selector로 어떤 Proxy에 해당 설정을 적용할 것인지 지정할 수 있다.

RequestAuthentication에서는 jwtRules에서 issuer, jwksUri(Json Web Key Set을 받아올 수 있는 경로) 등을 설정할 수 있다.

중요 참고 : Okta에는 Org Authorization Server와 Custom Authorization Server가 있는데 Org Authorization Server는 Access Token에 대한 Key 정보를 제공하지 않는다.

참고 URL : https://devforum.okta.com/t/istio-envoy-oauth2-filter-configuration/20552

Org Server는 xxx.okta.com으로 끝나는 기본으로 제공되는 서버이며 Custom auth server는 /oauth2/xxxxx로 제공되는 API Access Management 유료 서비스이다.

따라서 Custom Authorization Server로 설정해야 /keys 엔드포인트를 사용할 수 있게 된다.

이 부분에서 엄청 애를 먹었다..

AuthorizationPolicy 또한 설정해줘야 하는데 RequestAuthentication은 JWT가 유효햔지 유효하지 않은지 확인할 수 있지만 JWT가 없을 경우 이를 인증처리해버린다.

하여 JWT가 Header로 전달되지 않을 경우 AuthorizationPolicy에서 JWT Token을 강제하도록 하는 작업이 필요하다.

apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
  name: okta-aws-nginx
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: istio-ingressgateway-okta-alb
  jwtRules:
    - issuer: "<https://trial-5111198.okta.com/oauth2/default>"
      jwksUri: "<https://trial-5111198.okta.com/oauth2/default/v1/keys>"
      forwardOriginalToken: true
      fromHeaders:
        - name: x-amzn-oidc-accesstoken
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: okta-aws-nginx
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: istio-ingressgateway-okta-alb
  action: ALLOW
  rules:
    - to:
        - operation:
            paths: ["/*"]
    - from:
        - source:
            requestPrincipals: ["<https://trial-5111198.okta.com/oauth2/default/*>"]
      when:
        - key: request.auth.claims[iss]
          values:
            - "<https://trial-5111198.okta.com/oauth2/default>"

 

 

어떻게 인증 처리가 구현되는지 확인해보기 위해 IngressGateway 쪽에 Proxy Config 에서 Log Level을 수정해보도록 하겠다.

 

 

JWT 쪽 Debug 로그를 확인해보면 x-amzn-oidc-accesstoken을 추출하고 JWT token이 Verify 된 것을 확인할 수 있다.

 

 

Issuer가 https://trial-5111198.okta.com/oauth2/default 일 때 JWT Token을 다시 받아오도록 설정한다.

  when:
    - key: request.auth.claims[iss]
      values:
        - "<https://trial-5111198.okta.com/oauth2/default>"

RequestPrinciple이 https://trial-5111198.okta.com/oauth2/default/* 로 설정했기 때문에 rbac에서 allowed 표시가 뜨는 것을 확인할 수 있다.

- from:
    - source:
        requestPrincipals: ["<https://trial-5111198.okta.com/oauth2/default/*>"]

 

 

 

 

4. Issue

[1] Istio에서 App단에 Auth 설정을 하면 JWT를 안받아온다.

→ 위에 예시도 IngressGateway에 ReqAuthentication, AuthoPolicy를 설정했는데 이상하게 Httpbin에 설정하면 JWT Debug Log도 보이지 않는다…

 

[2] Istio에서 IngressGateway단에 Auth 설정을 하면 paths 부분이 안먹는 것 같다.

→ Path 별로 권한을 다르게 부여하고 싶었는데 잘 적용이 되지 않았다..

 

[3] Okta에서 groups Claim이 안넘어간다.

→ 이 부분은 Okta에서 뭔가 추가 설정이 필요한건지 모르겠지만 groups 클레임이 전달이 안된 것 같다. Custom authz server에서 추가 설정을 해줘야하나..

 

[4] Org Authorization Server에서는 jwksUri가 안되는 것 같다. Custom Authorization Server에서만 되는 것 같음

→ 위 내용을 적용할거면 API Access Management를 꼭 사용해야하는거 같다..

 

 

Reference

 

 

 

반응형