Apache APISIX, Open Policy Agent와 통합하여 생태계를 확장하다
API7.ai
December 24, 2021
Open Policy Agent(OPA)는 소프트웨어 내장 정책 기능 모듈을 대체할 수 있는 오픈 소스 경량 범용 정책 엔진으로, 사용자가 서비스와 정책 엔진을 분리하는 데 도움을 줍니다. OPA의 잘 구축된 생태계 덕분에 사용자는 프로그램 라이브러리, HTTP API 등 다른 서비스와 OPA를 쉽게 통합할 수 있습니다.
아래 그림과 같이, OPA는 먼저 정책 언어 Rego를 통해 정책을 기술하고, JSON을 통해 정책 데이터를 저장한 후, 사용자가 쿼리 요청을 보낼 수 있습니다. 쿼리 요청을 받은 OPA는 정책, 데이터 및 사용자 입력을 결합하여 정책 결정을 생성하고 이를 서비스에 전달합니다.
플러그인 소개
Apache APISIX는 opa
플러그인을 제공하여 사용자가 OPA가 제공하는 정책 기능을 Apache APISIX에 편리하게 도입하여 유연한 인증 및 접근 제어 기능을 활성화할 수 있도록 합니다.
라우트에 opa
플러그인을 구성한 후, Apache APISIX는 응답 요청을 처리할 때 요청 정보, 연결 정보 등을 JSON 데이터로 조합하여 정책 결정 API 주소로 전송합니다. OPA에 배포된 정책이 Apache APISIX가 설정한 데이터 규격을 준수하는 한, 요청 통과, 요청 거부, 사용자 정의 상태 코드, 사용자 정의 응답 헤더, 사용자 정의 응답 헤더 등의 기능을 구현할 수 있습니다.
이 글은 HTTP API를 예로 들어 opa
플러그인을 소개하고, Apache APISIX와 OPA를 통합하여 백엔드 서비스의 인증 권한을 분리하는 방법을 상세히 설명합니다.
사용 방법
테스트 환경 구축
-
Docker를 사용하여 OPA 서비스를 구축합니다.
# Docker로 OPA 실행 docker run -d --name opa -p 8181:8181 openpolicyagent/opa:0.35.0 run -s
-
example
정책을 생성합니다.# 정책 생성 curl -XPUT 'localhost:8181/v1/policies/example' \ --header 'Content-Type: text/plain' \ --data-raw 'package example import input.request import data.users default allow = false allow { # test-header 이름의 요청 헤더 값이 only-for-test인 경우 request.headers["test-header"] == "only-for-test" # 요청 메서드가 GET인 경우 request.method == "GET" # 요청 경로가 /get으로 시작하는 경우 startswith(request.path, "/get") # GET 파라미터 test가 존재하고 abcd가 아닌 경우 request.query["test"] != "abcd" # GET 파라미터 user가 존재하는 경우 request.query["user"] } reason = users[request.query["user"]].reason { not allow request.query["user"] } headers = users[request.query["user"]].headers { not allow request.query["user"] } status_code = users[request.query["user"]].status_code { not allow request.query["user"] }'
-
users
데이터를 생성합니다.# 테스트 사용자 데이터 생성 curl -XPUT 'localhost:8181/v1/data/users' \ --header 'Content-Type: application/json' \ --data-raw '{ "alice": { "headers": { "Location": "http://example.com/auth" }, "status_code": 302 }, "bob": { "headers": { "test": "abcd", "abce": "test" } }, "carla": { "reason": "Give you a string reason" }, "dylon": { "headers": { "Content-Type": "application/json" }, "reason": { "code": 40001, "desc": "Give you a object reason" } } }'
라우트 생성 및 플러그인 활성화
다음 명령어를 실행하여 라우트를 생성하고 opa
플러그인을 활성화합니다.
curl -XPUT 'http://127.0.0.1:9080/apisix/admin/routes/r1' \
--header 'X-API-KEY: <api-key>' \
--header 'Content-Type: application/json' \
--data-raw '{
"uri": "/*",
"methods": [
"GET",
"POST",
"PUT",
"DELETE"
],
"plugins": {
"opa": {
"host": "http://127.0.0.1:8181",
"policy": "example"
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'
요청 테스트
다음으로, opa
플러그인에 요청을 보내 플러그인의 실행 상태를 테스트합니다.
# 요청 허용
curl -XGET '127.0.0.1:9080/get?test=none&user=dylon' \
--header 'test-header: only-for-test'
{
"args": {
"test": "abcd1",
"user": "dylon"
},
"headers": {
"Test-Header": "only-for-test",
"with": "more"
},
"origin": "127.0.0.1",
"url": "http://127.0.0.1/get?test=abcd1&user=dylon"
}
# 요청 거부 및 상태 코드와 응답 헤더 재작성
curl -XGET '127.0.0.1:9080/get?test=abcd&user=alice' \
--header 'test-header: only-for-test'
HTTP/1.1 302 Moved Temporarily
Date: Mon, 20 Dec 2021 09:37:35 GMT
Content-Type: text/html
Content-Length: 142
Connection: keep-alive
Location: http://example.com/auth
Server: APISIX/2.11.0
# 요청 거부 및 사용자 정의 응답 헤더 반환
curl -XGET '127.0.0.1:9080/get?test=abcd&user=bob' \
--header 'test-header: only-for-test'
HTTP/1.1 403 Forbidden
Date: Mon, 20 Dec 2021 09:38:27 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 150
Connection: keep-alive
abce: test
test: abcd
Server: APISIX/2.11.0
# 요청 거부 및 사용자 정의 응답(문자열) 반환
curl -XGET '127.0.0.1:9080/get?test=abcd&user=carla' \
--header 'test-header: only-for-test'
HTTP/1.1 403 Forbidden
Date: Mon, 20 Dec 2021 09:38:58 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.11.0
Give you a string reason
# 요청 거부 및 사용자 정의 응답(JSON) 반환
curl -XGET '127.0.0.1:9080/get?test=abcd&user=dylon' \
--header 'test-header: only-for-test'
HTTP/1.1 403 Forbidden
Date: Mon, 20 Dec 2021 09:42:12 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.11.0
{"code":40001,"desc":"Give you a object reason"}
플러그인 비활성화
Apache APISIX의 동적 특성 덕분에, 라우트의 OPA 플러그인은 라우트 구성에서 opa
플러그인 관련 설정을 제거하고 저장하기만 하면 비활성화할 수 있습니다.
요약
이 글은 Apache APISIX와 Open Policy Agent를 연동하는 상세한 단계를 설명했습니다. 이 글이 Apache APISIX에서 Open Policy Agent를 사용하는 방법을 더 명확히 이해하고, 이후 실습을 용이하게 하는 데 도움이 되길 바랍니다.
Apache APISIX는 자체의 고성능 유지에만 전념하는 것이 아니라, 오픈 소스 생태계 구축에도 큰 중요성을 두고 있습니다. 현재 Apache APISIX는 10개 이상의 인증 권한 관련 플러그인을 보유하고 있으며, 업계의 주요 인증 권한 서비스와의 연동을 지원합니다.
다른 인증 권한 기관과의 연동이 필요하다면, Apache APISIX의 GitHub를 방문하여 issue를 통해 제안을 남기거나, Apache APISIX의 메일링 리스트를 구독하여 이메일로 아이디어를 표현할 수 있습니다.