소개
APISIX는 Nginx와 etcd를 기반으로 한 고성능 및 확장 가능한 클라우드 네이티브 API 게이트웨이입니다. 이것은 Apache Software Foundation의 오픈 소스 프로젝트입니다. 또한, APISIX가 훌륭한 이유는 인증, 모니터링, 라우팅 등의 기능을 구현하는 데 사용할 수 있는 많은 훌륭한 내장 플러그인의 지원입니다. 그리고 APISIX의 플러그인들이 핫 리로드(재시작 없이)되는 사실이 매우 동적으로 만듭니다.
그러나 APISIX를 사용하는 동안, 애플리케이션에서 복잡한 인증 로직을 추가하려는 시나리오가 있을 수 있습니다. 이때 authz-casbin이 도움이 될 수 있습니다. authz-casbin은 다양한 접근 제어 모델을 기반으로 강력한 인증을 가능하게 하는 Lua Casbin 기반의 APISIX 플러그인입니다. Casbin은 ACL, RBAC, ABAC와 같은 접근 제어 모델을 지원하는 인증 라이브러리입니다. 원래 Go로 작성되었지만, 이것은 많은 언어로 포팅되었고 Lua Casbin은 Casbin의 Lua 구현입니다. authz-casbin의 개발은 APISIX 저장소에서 인증을 위한 새로운 플러그인을 제안했을 때 시작되었습니다(#4674) 이에 핵심 멤버들이 동의했습니다. 그리고 몇 가지 주요 변경과 개선을 이끈 도움이 되는 리뷰 후에, PR(#4710)이 마침내 병합되었습니다.
이 블로그에서는 authz-casbin 플러그인을 사용하여 APISIX에서 역할 기반 접근 제어(RBAC)를 기반으로 한 인증 모델을 어떻게 구현할 수 있는지 보여줄 것입니다.
참고: Casbin은 인증만 수행하므로 사용자를 인증하기 위해 다른 플러그인이나 사용자 정의 워크플로우를 사용해야 합니다.
모델 생성
플러그인은 모든 요청을 인증하는 데 세 가지 매개변수를 사용합니다 - 주체, 객체, 행동. 여기서 주체는 [username: alice]
와 같은 사용자 이름 헤더의 값입니다. 그런 다음, 객체는 접근되는 URL 경로이고 행동은 사용되는 요청 메서드입니다.
세 가지 리소스가 있는 모델을 생성하려고 합니다 - 경로 /
, /res1
및 /res2
. 그리고 이런 모델을 가지고 싶습니다:
이것은 모든 사용자(*
) 예를 들어 jack
이 홈페이지(/
)에 접근할 수 있다는 것을 의미합니다. 그리고 admin
권한이 있는 사용자들, 예를 들어 alice
와 bob
은 모든 페이지와 리소스(res1
과 res2
같은)에 접근할 수 있습니다. 또한, 어떤 관리 권한도 없는 사용자들이 GET
요청 메서드만 사용하도록 제한합시다. 이 시나리오에 대해, 우리는 모델을 다음과 같이 정의할 수 있습니다:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)
정책 생성
위의 시나리오에서, 정책은 다음과 같을 것입니다:
p, *, /, GET
p, admin, *, *
g, alice, admin
g, bob, admin
모델에서의 매처는 다음을 의미합니다:
(g(r.sub, p.sub) || keyMatch(r.sub, p.sub))
: 요청의 주체가 정책의 주체 역할을 가지거나 요청의 주체가keyMatch
에서 정책의 주체와 일치합니다.keyMatch
는 Lua Casbin의 내장 함수로, 함수의 설명과 더 유용할 수 있는 다른 함수들을 여기에서 확인할 수 있습니다.keyMatch(r.obj, p.obj)
: 요청의 객체가 정책의 객체(URL 경로 여기)와 일치합니다.keyMatch(r.act, p.act)
: 요청의 동작이 정책의 동작(HTTP 요청 메서드 여기)과 일치합니다.
경로에서 플러그인 활성화
모델과 정책을 생성한 후에는 APISIX Admin API를 사용하여 경로에서 활성화할 수 있습니다. 모델과 정책 파일 경로를 사용하여 활성화하려면:
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"authz-casbin": {
"model_path": "/path/to/model.conf",
"policy_path": "/path/to/policy.csv",
"username": "username"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/*"
}'
여기서 username 필드는 주체를 전달하는 데 사용할 헤더 이름입니다. 예를 들어, username 헤더를 user: alice
로 전달하면 "username": "user"
를 사용하게 됩니다.
파일 대신 모델/정책 텍스트를 사용하려면 model
과 policy
필드를 대신 사용할 수 있습니다:
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"authz-casbin": {
"model": "[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)",
"policy": "p, *, /, GET
p, admin, *, *
g, alice, admin
g, bob, admin",
"username": "username"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/*"
}'
전역 모델/정책을 사용하여 플러그인 활성화
여러 경로에서 단일 모델과 정책 구성을 사용하려는 상황이 있을 수 있습니다. 먼저 PUT
요청을 보내 플러그인의 메타데이터에 모델과 정책 구성을 추가함으로써 이를 수행할 수 있습니다:
curl http://127.0.0.1:9080/apisix/admin/plugin_metadata/authz-casbin -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -i -X PUT -d '
{
"model": "[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)",
"policy": "p, *, /, GET
p, admin, *, *
g, alice, admin
g, bob, admin"
}'
그런 다음 같은 구성을 어떤 경로에서 활성화하려면 Admin API를 사용하여 요청을 보냅니다:
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"authz-casbin": {
"username": "username"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/route1/*"
}'
이렇게 하면 플러그인 메타데이터 구성이 경로에 추가됩니다. 플러그인 메타데이터에 업데이트된 모델과 정책 구성으로 요청을 다시 보내 플러그인 메타데이터 구성을 쉽게 업데이트할 수도 있습니다. 플러그인은 자동으로 플러그인 메타데이터를 사용하는 모든 경로를 업데이트합니다.
사용 사례
- 이 플러그인의 주요 사용 사례는 API에서 인증을 구현하는 것입니다. 인증 모델과 정책 구성을 사용하는 API 경로에 이 플러그인을 쉽게 추가할 수 있습니다.
- 모든 API에 대해 단일 인증 모델을 사용하려면 전역 모델/정책 방법을 사용할 수 있습니다. 이렇게 하면 모든 경로에 대한 정책을 쉽게 업데이트할 수 있습니다. 왜냐하면 etcd에서 메타데이터만 업데이트하면 되기 때문입니다.
- 반면, 각기 다른 경로마다 다른 모델을 사용하려면 경로 방법을 사용할 수 있습니다. 이는 다른 API 경로가 다른 사용자 권한 세트를 가질 때 유용합니다. 이는 더 큰 정책을 다룰 때도 사용할 수 있습니다. 왜냐하면 이를 여러 경로로 필터링하면 인증이 더 빨라지기 때문입니다.