본문 바로가기
WIKI 기술 지식 베이스

OAuth 2.0 토큰 인트로스펙션 인증

원문 보기 위키 갱신

출처: OAuth 2.0 Token Introspection Authentication

본문

Token Introspection

Traefik Hub 기능

이 미들웨어는 Traefik Hub에서만 사용할 수 있어요. Traefik Hub의 고급 기능에 대해 더 알아보세요.

OAuth 2.0 토큰 인트로스펙션(Token Introspection)은 Token Introspection 확장을 사용해 OAuth 2.0 서버에서 접근 토큰에 대한 메타데이터를 가져올 수 있게 해 줍니다.

이 메타데이터는 애플리케이션에 대한 접근을 제한하는 데 사용할 수 있어요. 자세한 내용은 RFC를 참고하세요.

구성 예시

Middleware OAuth Token Introspection

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: test-oauth-intro
spec:
  plugin:
    oAuthIntrospection:
      tokenSource:
        header: Authorization
        headerAuthScheme: Bearer
      clientConfig:
        url: "https://YOUR-KEYCLOAK-ADDRESS/realms/YOUR-REALM/protocol/openid-connect/token/introspect"
        headers:
          Authorization: Basic ZXhhbX...cGxl # echo -n "$CLIENT_ID:$CLIENT_SECRET" | base64
        tokenTypeHint: access_token
      forwardHeaders:
        Group: grp
        Expires-At: exp
      claims: Equals(`grp`, `admin`)

구성 옵션

| Field | Description | Default | Required | | claims | 요청을 승인하기 위해 검증할 클레임을 정의해요. claims 옵션은 JWT 형식 토큰에서만 사용할 수 있어요. (자세한 내용은 여기) | "" | No | | clientConfig.url | 인트로스펙션 엔드포인트 URL을 정의해요. 스킴과 경로를 포함해야 해요. | "" | Yes | | clientConfig.headers | 모든 인트로스펙션 요청에 보낼 헤더를 정의해요. 값은 일반 문자열이거나 유효한 Go 템플릿일 수 있어요. 현재 템플릿에서는 인트로스펙션되는 요청에 해당하는 Request 유형 변수에 접근할 수 있습니다. | "" | No | | clientConfig.tokenTypeHint | 인트로스펙션되는 토큰의 유형을 정의하며, 인트로스펙션 서버에 힌트로 보냅니다. 자세한 내용은 공식 문서를 참고하세요. | "" | No | | clientConfig.tls.ca | 인증 서버와 TLS 연결을 맺는 데 사용하는 인증서 번들을 담은 PEM 인코딩 인증서 번들이나 비밀을 참조하는 URN (자세한 내용은 여기) | "" | No | | clientConfig.tls.cert | 인증 서버와 TLS 연결을 맺는 데 사용하는 인증서를 담은 PEM 인코딩 인증서나 비밀을 참조하는 URN. (자세한 내용은 여기) | "" | No | | clientConfig.tls.key | 인증 서버와 TLS 연결을 맺는 데 사용하는 키를 담은 PEM 인코딩 키나 비밀을 참조하는 URN. (자세한 내용은 여기) | "" | No | | clientConfig.tls.insecureSkipVerify | 인증 서버와 통신할 때 TLS 인증서 검증을 끕니다. 테스트 목적으로는 유용하지만 프로덕션에는 강력히 권장되지 않아요. (자세한 내용은 여기) | false | No | | clientConfig.timeoutSeconds | 인증 서버에 대한 요청을 포기하기 전의 시간을 정의해요. | 5 | No | | clientConfig.maxRetries | 실패한 인증 서버 요청에 대한 재시도 횟수를 정의해요. | 3 | No | | forwardAuthorization | 미들웨어가 요청을 승인한 뒤 authorization 헤더를 전달할지, 아니면 요청에서 제거할지 정의해요. | false | No | | forwardHeaders | 요청에 추가할 HTTP 헤더를 정의하고, 인증 서버가 반환한 접근 토큰 클레임에서 추출한 값으로 채웁니다. JWT에서 찾지 못한 전달 대상 클레임은 빈 헤더가 돼요. forwardHeaders 옵션은 JWT 형식 토큰에서만 사용할 수 있어요. | [] | No | | tokenSource.header | 클라이언트가 보낸 비밀을 담고 있는 헤더 이름을 정의해요. tokenSource 옵션 중 하나는 반드시 설정해야 해요. | "" | No | | tokenSource.headerAuthScheme | 헤더 이름으로 Authorization을 사용할 때의 스킴을 정의해요. Authorization 헤더 문서를 확인하세요. tokenSource 옵션 중 하나는 반드시 설정해야 해요. | "" | No | | tokenSource.query | 클라이언트가 보낸 비밀을 담고 있는 쿼리 파라미터 이름을 정의해요. tokenSource 옵션 중 하나는 반드시 설정해야 해요. | "" | No | | tokenSource.cookie | 클라이언트가 보낸 비밀을 담고 있는 쿠키 이름을 정의해요. tokenSource 옵션 중 하나는 반드시 설정해야 해요. | "" | No | | usernameClaim | 접근 로그의 clientusername을 채우는 데 평가할 클레임을 정의해요. usernameClaim 옵션은 JWT 형식 토큰에서만 사용할 수 있어요. | "" | No |

claims

문법

claims에서 지원하는 함수는 다음과 같아요:

| Function | Description | Example | | Equals | key의 값이 value와 같은지 검증해요. | Equals(grp, admin) | | Prefix | key의 값이 value를 접두사로 갖는지 검증해요. | Prefix(referrer, http://example.com) | | Contains (string) | key의 값이 value를 포함하는지 검증해요. | Contains(referrer, /foo/) | | Contains (array) | key 배열이 value를 포함하는지 검증해요. | Contains(areas, home) | | SplitContains | key의 값을 구분자로 나눴을 때 value를 포함하는지 검증해요. | SplitContains(scope, , writer) | | OneOf | key 배열이 values 중 하나를 포함하는지 검증해요. | OneOf(areas, office, lab) |

모든 함수는 불리언 연산자로 결합할 수 있어요. 지원되는 연산자는 다음과 같아요:

| Operand | Description | Example | | && | 두 함수를 비교해서 둘 다 참일 때만 참을 반환해요. | Equals(grp, admin) && Equals(active, true) | | || | 두 함수를 비교해서 둘 중 하나라도 참이면 참을 반환해요. | Equals(grp, admin) || Equals(active, true) | | ! | 함수가 참이면 false를, 그 외에는 참을 반환해요. | !Equals(grp, testers) |

다음 데이터 구조에서는 모든 예시가 참을 반환해요:

JSON

{
  "active": true,
  "grp": "admin",
  "scope": "reader writer deploy",
  "referrer": "http://example.com/foo/bar",
  "areas": [
    "office",
    "home"
  ]
}

중첩 클레임 (Nested Claims)

키 사이에 .를 사용해 중첩 클레임을 지원해요. 예를 들어:

Key

user.name

Claims

{
  "active": true,
  "grp": "admin",
  "scope": "reader writer deploy",
  "referrer": "http://example.com/foo/bar",
  "areas": [
    "office",
    "home"
  ],
  "user" {
    "name": "John Snow",
    "status": "undead"
  }
}

Result

John Snow

.을 포함하는 키 처리

key에 점이 포함되어 있으면 \.로 이스케이프할 수 있어요.

\를 포함하는 키 처리

key에 \가 포함되어 있으면 \\로 두 번 적어야 합니다.

clientConfig

API 게이트웨이를 Identity Provider 같은 서드파티 소프트웨어에 연결하는 데 사용하는 구성을 정의해요.

clientConfig.tls

Kubernetes secret에 비밀 값 저장하기

tls.ca, tls.cert, tls.key를 구성할 때, Middleware와 같은 네임스페이스에 정의된 Kubernetes secret을 참조할 수 있어요. Kubernetes secret에 대한 참조는 URN 형식을 취합니다:

urn:k8s:secret:[name]:[valueKey]

Middleware JWT

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: test-oauth-intro
spec:
  plugin:
    oAuthIntrospection:
      clientConfig:
        tls:
          ca: "urn:k8s:secret:tls:ca"
          cert: "urn:k8s:secret:tls:cert"
          key: "urn:k8s:secret:tls:key"
          insecureSkipVerify: true

Kubernetes TLS Secret

apiVersion: v1
kind: Secret
metadata:
  name: tls
stringData:
  ca: |-
    -----BEGIN CERTIFICATE-----
    MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV
    BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl
    Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt
    aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3
    DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl
    EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j
    RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE
    apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP
    Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX
    ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ
    98TwDIK/39WEB/V607As+KoYazQG8drorw==
    -----END CERTIFICATE-----
  cert: |-
    -----BEGIN CERTIFICATE-----
    MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV
    BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl
    Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt
    aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3
    DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl
    EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j
    RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE
    apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP
    Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX
    ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ
    98TwDIK/39WEB/V607As+KoYazQG8drorw==
    -----END CERTIFICATE-----
  key: |-
    [REDACTED PRIVATE KEY]

Traefik OSS를 프로덕션에서 사용하시나요?

직장에서 Traefik을 사용한다면, 엔터프라이즈급 API 게이트웨이 기능이나 Traefik OSS 상용 지원을 추가하는 것을 고려해 보세요.

  • API Gateway 데모 영상 보기

  • 24/7/365 OSS 지원 요청

Traefik OSS에 API 게이트웨이 기능을 추가하는 것은 빠르고 매끄러워요. 기존 구성을 교체하거나(rip and replace) 버릴 필요 없이 그대로 유지됩니다. 짧은 영상으로 직접 확인해 보세요.

더 알아보기 (Learn more)