API Gateway와 Open Policy Agent (OPA)를 사용한 RBAC
May 15, 2023
다양한 접근 제어 모델과 구현 방법이 있음에도 불구하고, 백엔드 서비스 API를 위한 권한 부여 시스템을 구축하는 것은 여전히 도전적일 수 있습니다. 그러나 궁극적인 목표는 적절한 개인이 관련 리소스에 적절하게 접근할 수 있도록 하는 것입니다. 이 글에서는 오픈소스 API 게이트웨이인 Apache APISIX와 Open Policy Agent (OPA)를 사용하여 API에 역할 기반 접근 제어(RBAC) 권한 부여 모델을 활성화하는 방법에 대해 논의하겠습니다.
학습 목표
이 글을 통해 다음을 배우게 됩니다:
- RBAC란 무엇이며 어떻게 작동하는가?
- OPA란 무엇이며 어떻게 작동하는가?
- OPA와 Apache APISIX를 사용하여 RBAC를 구현하는 방법은?
- OPA에서 정책을 정의하고 등록하는 방법은?
- 업스트림, 라우트를 생성하고 OPA 플러그인을 활성화하는 방법은?
- 사용자의 역할과 권한이 JWT 토큰 페이로드 또는 소비자 데이터에서 어떻게 파싱되는가?
RBAC란 무엇인가?
역할 기반 접근 제어 (RBAC)와 속성 기반 접근 제어 (ABAC)는 컴퓨터 시스템에서 리소스에 대한 접근을 관리하고 제어하기 위해 사용되는 두 가지 일반적인 접근 제어 모델입니다. RBAC는 조직 내 사용자의 역할에 따라 권한을 할당합니다. RBAC에서 역할은 사용자의 기능 또는 책임에 따라 정의되며, 이러한 역할에 권한이 할당됩니다. 사용자는 하나 이상의 역할에 할당되며, 해당 역할과 관련된 권한을 상속받습니다. API 컨텍스트에서 예를 들어, 개발자 역할은 API 리소스를 생성하고 업데이트할 수 있는 권한을 가질 수 있지만, 최종 사용자 역할은 API 리소스를 읽거나 실행할 수 있는 권한만 가질 수 있습니다.
기본적으로, RBAC는 사용자 역할에 기반하여 권한을 할당하고, ABAC는 사용자 및 리소스와 관련된 속성에 기반하여 권한을 할당합니다.
RBAC에서 정책은 사용자의 할당된 역할, 허용된 작업, 그리고 해당 작업을 수행할 수 있는 리소스의 조합으로 정의됩니다.
OPA란 무엇인가?
OPA (Open Policy Agent)는 전체 분산 시스템에서 정책 적용을 위한 통합 접근 방식을 제공하는 정책 엔진 및 도구 세트입니다. 이를 통해 단일 지점에서 정책을 정의, 관리, 적용할 수 있습니다. 정책을 코드로 정의함으로써 OPA는 정책을 쉽게 검토, 편집, 롤백할 수 있게 하여 효율적인 정책 관리를 가능하게 합니다.
OPA는 Rego라는 선언적 언어를 제공하며, 이를 통해 스택 전체에서 정책을 생성하고 적용할 수 있습니다. OPA에 정책 결정을 요청하면, .rego
파일에 제공된 규칙과 데이터를 사용하여 쿼리를 평가하고 응답을 생성합니다. 쿼리 결과는 정책 결정으로 반환됩니다. OPA는 모든 정책과 필요한 데이터를 메모리 캐시에 저장합니다. 결과적으로 OPA는 빠르게 결과를 반환합니다. 다음은 간단한 OPA Rego 파일의 예입니다:
package example
default allow = false
allow {
input.method == "GET"
input.path =="/api/resource"
input.user.role == "admin"
}
이 예제에서는 "example"이라는 패키지가 있으며, "allow"라는 규칙을 정의합니다. "allow" 규칙은 입력 메서드가 "GET"이고, 요청된 경로가 /api/resource
이며, 사용자의 역할이 "admin"인 경우 요청을 허용합니다. 이러한 조건이 충족되면 "allow" 규칙이 "true"로 평가되어 요청이 진행됩니다.
왜 RBAC에 OPA와 API 게이트웨이를 사용하는가?
API 게이트웨이는 API와 API 소비자를 구성하고 관리할 수 있는 중앙 집중식 위치를 제공합니다. 이를 통해 각 개별 서비스가 서비스 내부에서 인증 로직을 구현하는 것을 피함으로써 중앙 집중식 인증 게이트웨이로 사용할 수 있습니다. 반면, OPA는 권한 부여 계층을 추가하고 코드에서 정책을 분리하여 권한 부여에 대한 독특한 이점을 제공합니다. 이 조합을 통해 API 리소스에 대한 권한을 역할에 추가할 수 있습니다. 사용자는 하나 이상의 사용자 역할과 연관될 수 있습니다. 각 사용자 역할은 RBAC 리소스(URI 경로로 정의됨)에 대한 권한(GET, PUT, DELETE) 집합을 정의합니다. 다음 섹션에서는 이 두 가지를 사용하여 RBAC를 구현하는 방법을 배워보겠습니다.
OPA와 Apache APISIX를 사용하여 RBAC를 구현하는 방법
Apache APISIX에서는 라우트와 플러그인을 구성하여 API의 동작을 정의할 수 있습니다. APISIX opa 플러그인을 사용하여 RBAC 정책을 적용할 수 있으며, 요청을 OPA로 전달하여 결정을 내립니다. 그런 다음 OPA는 사용자의 역할과 권한을 기반으로 실시간으로 권한 부여 결정을 내립니다.
Conference API가 있다고 가정해 보겠습니다. 이 API를 통해 이벤트 세션, 주제 및 발표자 정보를 검색/편집할 수 있습니다. 발표자는 자신의 세션과 주제만 읽을 수 있지만, 관리자는 더 많은 세션과 주제를 추가/편집할 수 있습니다. 또는 참가자는 발표자의 세션에 대한 피드백을 /speaker/speakerId/session/feedback
에 POST 요청으로 남길 수 있으며, 발표자는 동일한 URI의 GET 메서드를 요청하여 피드백을 볼 수 있습니다. 아래 다이어그램은 전체 시나리오를 보여줍니다:
- API 소비자는 인증 헤더에 JWT 토큰과 같은 자격 증명을 포함하여 API 게이트웨이에 라우트를 요청합니다.
- API 게이트웨이는 JWT 헤더와 함께 소비자 데이터를 OPA 엔진으로 전송합니다.
- OPA는 .rego 파일에 지정된 정책(역할 및 권한)을 사용하여 소비자가 리소스에 접근할 권한이 있는지 평가합니다.
- OPA 결정이 허용되면 요청이 업스트림 Conference 서비스로 전달됩니다.
다음으로, APISIX를 설치 및 구성하고 OPA에 정책을 정의합니다.
전제 조건
- Docker는 컨테이너화된 etcd와 APISIX를 설치하는 데 사용됩니다.
- curl은 APISIX Admin API에 요청을 보내는 데 사용됩니다. Postman과 같은 도구를 사용하여 API와 상호 작용할 수도 있습니다.
1단계: Apache APISIX 설치
APISIX는 다음의 빠른 시작 스크립트를 사용하여 쉽게 설치하고 시작할 수 있습니다:
curl -sL https://run.api7.ai/apisix/quickstart | sh
2단계: 백엔드 서비스(업스트림) 구성
Conference API에 대한 요청을 백엔드 서비스로 라우팅하려면, Apache APISIX에서 Admin API를 통해 업스트림 서버를 추가하여 구성해야 합니다.
curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -X PUT -d '
{
"name":"Conferences API upstream",
"desc":"Register Conferences API as the upstream",
"type":"roundrobin",
"scheme":"https",
"nodes":{
"conferenceapi.azurewebsites.net:443":1
}
}'
3단계: API 소비자 생성
다음으로, Apache APISIX에서 jack
이라는 사용자 이름으로 소비자(새로운 발표자)를 생성합니다. 이는 지정된 키와 비밀을 사용하여 소비자에 대해 jwt-auth 플러그인을 설정합니다. 이를 통해 소비자는 JSON Web Token (JWT)을 사용하여 인증할 수 있습니다.
curl http://127.0.0.1:9180/apisix/admin/consumers -X PUT -d '
{
"username": "jack",
"plugins": {
"jwt-auth": {
"key": "user-key",
"secret": "my-secret-key"
}
}
}'
4단계: JWT 토큰을 생성할 공개 엔드포인트 생성
또한 public-api 플러그인을 사용하여 토큰을 생성하고 서명하는 새로운 라우트를 설정해야 합니다. 이 시나리오에서 API 게이트웨이는 소비자 jack의 키를 사용하여 토큰을 생성하고 검증하는 ID 제공자 서버 역할을 합니다. ID 제공자는 Google, Okta, Keycloak, Ory Hydra와 같은 다른 타사 서비스일 수도 있습니다.
curl http://127.0.0.1:9180/apisix/admin/routes/jas -X PUT -d '
{
"uri": "/apisix/plugin/jwt/sign",
"plugins": {
"public-api": {}
}
}'
5단계: API 소비자를 위한 새로운 JWT 토큰 요청
이제 API 게이트웨이에서 생성한 공개 엔드포인트를 사용하여 발표자 Jack을 위한 새로운 토큰을 얻을 수 있습니다. 다음 curl 명령은 Jack의 자격 증명을 사용하여 새로운 토큰을 생성하고 페이로드에 역할과 권한을 할당합니다.
curl -G --data-urlencode 'payload={"role":"speaker","permission":"read"}' http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=user-key -i
위 명령을 실행한 후, 토큰이 응답으로 반환됩니다. 이 토큰을 어딘가에 저장해 두세요. 나중에 이 토큰을 사용하여 새로운 API 게이트웨이 엔드포인트에 접근할 것입니다.
6단계: 새로운 플러그인 구성 생성
이 단계에서는 APISIX의 3가지 플러그인, proxy-rewrite, jwt-auth, opa 플러그인을 구성합니다.
curl "http://127.0.0.1:9180/apisix/admin/plugin_configs/1" -X PUT -d '
{
"plugins":{
"jwt-auth":{
},
"proxy-rewrite":{
"host":"conferenceapi.azurewebsites.net"
}
}
}'
proxy-rewrite
플러그인은conferenceapi.azurewebsites.net
호스트로 요청을 프록시하도록 구성됩니다.- OPA 인증 플러그인은 http://localhost:8181/v1/data/rbacExample에서 실행 중인 OPA 정책 엔진을 사용하도록 구성됩니다. 또한 APISIX는 모든 소비자 관련 정보를 OPA로 전송합니다. 이 정책
.rego
파일은 Opa 구성 섹션에서 추가할 것입니다.
7단계: Conference 세션을 위한 라우트 생성
마지막 단계는 Conferences API 발표자 세션을 위한 새로운 라우트를 생성하는 것입니다:
curl "http://127.0.0.1:9180/apisix/admin/routes/1" -X PUT -d '
{
"name":"Conferences API speaker sessions route",
"desc":"Create a new route in APISIX for the Conferences API speaker sessions",
"methods": ["GET", "POST"],
"uris": ["/speaker/*/topics","/speaker/*/sessions"],
"upstream_id":"1",
"plugin_config_id":1
}'
페이로드에는 라우트의 이름, 설명, 메서드, URI, 업스트림 ID, 플러그인 구성 ID와 같은 정보가 포함됩니다. 이 경우, 라우트는 /speaker/topics
및 /speaker/sessions
두 가지 URI에 대한 GET 및 POST 요청을 처리하도록 구성됩니다. "upstream_id" 필드는 이 라우트에 대한 들어오는 요청을 처리할 업스트림 서비스의 ID를 지정하며, "plugin_config_id" 필드는 이 라우트에 사용할 플러그인 구성의 ID를 지정합니다.
8단계: OPA 없이 설정 테스트
지금까지 APISIX가 Conference API 엔드포인트로 들어오는 요청을 전달하도록 필요한 모든 구성을 설정했습니다. 이제 API 소비자가 엔드포인트에 접근하려면 JWT 토큰을 제공하여 Conference 백엔드 서비스에서 데이터를 검색해야 합니다. 엔드포인트와 요청 중인 도메인 주소가 실제 Conference 서비스가 아닌 우리의 사용자 정의 API 게이트웨이임을 확인할 수 있습니다:
curl -i http://127.0.0.1:9080/speaker/1/topics -H 'Authorization: {API_CONSUMER_TOKEN}'
9단계: OPA 서비스 실행
다음 두 단계는 Docker를 사용하여 OPA 서비스를 실행하고, 들어오는 요청에 대한 권한 부여 정책을 평가하는 데 사용할 정책 정의를 API를 통해 업로드하는 것입니다.
docker run -d --network=apisix-quickstart-net --name opa -p 8181:8181 openpolicyagent/opa:latest run -s
이 Docker 명령은 최신 버전의 OPA 이미지 컨테이너를 실행합니다. 이는 기존 APISIX 네트워크 apisix-quickstart-net
에 opa
라는 이름으로 새로운 컨테이너를 생성하고 포트 8181
을 노출합니다. 따라서 APISIX는 [http://opa:8181](http://opa:8181)
주소를 사용하여 OPA에 직접 정책 확인 요청을 보낼 수 있습니다. OPA와 APISIX는 동일한 Docker 네트워크에서 실행되어야 합니다.
10단계: 정책 정의 및 등록
OPA 측의 두 번째 단계는 API 리소스에 대한 접근을 제어하는 데 사용될 정책을 정의하는 것입니다. 이러한 정책은 접근에 필요한 속성(어떤 사용자가 어떤 역할을 가지고 있는지)과 해당 속성에 기반하여 허용되거나 거부되는 권한(어떤 역할이 어떤 권한을 가지고 있는지)을 정의해야 합니다. 예를 들어, 아래 구성에서 우리는 OPA에게 user_roles
테이블을 확인하여 jack
의 역할이 무엇인지 확인하도록 지시합니다. 이 정보는 APISIX가 input.consumer.username
내부로 전송합니다. 또한 JWT 페이로드를 읽고 token.payload.permission
을 추출하여 소비자의 권한을 확인합니다. 주석은 단계를 명확히 설명합니다.
curl -X PUT '127.0.0.1:8181/v1/policies/rbacExample' \
-H 'Content-Type: text/plain' \
-d 'package rbacExample
# 사용자 역할 할당
user_roles := {
"jack": ["speaker"],
"bobur":["admin"]
}
# 역할 권한 할당
role_permissions := {
"speaker": [{"permission": "read"}],
"admin": [{"permission": "read"}, {"permission": "write"}]
}
# JWT 헬퍼 함수
bearer_token := t {
t := input.request.headers.authorization
}
# 인증 토큰을 디코딩하여 역할과 권한을 얻음
token = {"payload": payload} {
[_, payload, _] := io.jwt.decode(bearer_token)
}
# RBAC를 구현하는 로직
default allow = false
allow {
# 사용자의 역할 목록을 조회
roles := user_roles[input.consumer.username]
# 해당 목록의 각 역할에 대해
r := roles[_]
# 역할 r에 대한 권한 목록을 조회
permissions := role_permissions[r]
# 각 권한에 대해
p := permissions[_]
# r에 부여된 권한이 사용자의 요청과 일치하는지 확인
p == {"permission": token.payload.permission}
}'
11단계: OPA 플러그인으로 기존 플러그인 구성 업데이트
OPA 서비스에 정책을 정의한 후, 라우트에 대한 기존 플러그인 구성을 OPA 플러그인을 사용하도록 업데이트해야 합니다. OPA 플러그인의 policy
속성에 지정합니다.
curl "http://127.0.0.1:9180/apisix/admin/plugin_configs/1" -X PATCH -d '
{
"plugins":{
"opa":{
"host":"http://opa:8181",
"policy":"rbacExample",
"with_consumer":true
}
}
}'
12단계: OPA로 설정 테스트
이제 OPA 정책으로 모든 설정을 테스트할 수 있습니다. 동일한 curl 명령을 실행하여 API 게이트웨이 엔드포인트에 접근하려고 하면, 먼저 JWT 토큰을 인증 프로세스로 확인하고, 소비자와 JWT 토큰 데이터를 OPA로 전송하여 역할과 권한을 권한 부여 프로세스로 확인합니다. JWT 토큰이 없거나 허용된 역할이 없는 요청은 거부됩니다.
curl -i http://127.0.0.1:9080/speaker/1/topics -H 'Authorization: {API_CONSUMER_TOKEN}'
결론
이 글에서는 OPA와 Apache APISIX를 사용하여 RBAC를 구현하는 방법을 배웠습니다. 우리는 API 소비자의 역할과 권한을 기반으로 API 리소스 접근을 허용/거부하는 간단한 사용자 정의 정책 로직을 정의했습니다. 또한 이 튜토리얼은 APISIX가 전송한 JWT 토큰 페이로드 또는 소비자 객체에서 API 소비자 관련 정보를 추출하는 방법을 보여주었습니다.