Skip to content

Commit

Permalink
Develop (#36)
Browse files Browse the repository at this point in the history
* use apigateway instead of call_backend+call_esb
* fix lint
* add comment
* update do_migrate.py to support bk_apigateway_url
* change version to 1.1.16
  • Loading branch information
wklken authored Jul 28, 2021
1 parent 270d563 commit fef653a
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 21 deletions.
21 changes: 21 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -712,3 +712,24 @@ urlpatterns = [
url(r'^resource/api/v1/$', dispatcher.as_view([login_exempt]))
]
```

------------------------------

## 4. 切换使用 APIGateway

未来 APIGateway 高性能网关会作为一个基础的蓝鲸服务, 权限中心将会把后台及 SaaS 的所有开放 API 接入到网关中`bk-iam`

此时, 对于接入方, 不管是鉴权/申请权限还是其他接口, 都可以通过同一个网关访问到.

理解成本更低, 且相关的调用日志/文档/流控/监控等都可以在 APIGateway 统一管控.

网关地址类似: `http://bk-iam.{APIGATEWAY_DOMAIN}/{env}`, 其中 `env``prod(生产)/stage(预发布)`

SDK 目前做了兼容, 可以修改初始化 SDK 的参数, 切换流量到 APIGateway

```python
# 测试环境, 使用stage
IAM(app_code, app_secret, bk_apigateway_url="http://bk-iam.{APIGATEWAY_DOMAIN}/stage"):
# 正式环境, 使用prod
IAM(app_code, app_secret, bk_apigateway_url="http://bk-iam.{APIGATEWAY_DOMAIN}/prod"):
```
2 changes: 1 addition & 1 deletion iam/__version__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-

__version__ = "1.1.15"
__version__ = "1.1.16"
59 changes: 52 additions & 7 deletions iam/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from cachetools import TTLCache, cached
from requests.models import PreparedRequest

from iam.exceptions import AuthAPIError
from .http import http_delete, http_get, http_post, http_put

logger = logging.getLogger("iam")
Expand All @@ -33,11 +34,29 @@ class Client(object):
input: json
"""

def __init__(self, app_code, app_secret, bk_iam_host, bk_paas_host):
def __init__(self, app_code, app_secret, bk_iam_host=None, bk_paas_host=None, bk_apigateway_url=None):
"""
如果有 APIGateway 且权限中心网关接入, 则可以统一API请求全部走APIGateway
- 没有APIGateway的用法: Client(app_code, app_secret, bk_iam_host, bk_paas_host)
- 有APIGateway的用法: Client(app_code, app_secret, bk_apigateway_url)
NOTE: 未来将会下线`没有 APIGateway的用法`
"""
self._app_code = app_code
self._app_secret = app_secret
self._host = bk_iam_host
self._bk_paas_host = bk_paas_host

# enabled apigateay
self._apigateway_on = False
if bk_apigateway_url:
self._apigateway_on = True
# replace the host
self._host = bk_apigateway_url.rstrip("/")
else:
if not (bk_iam_host and bk_paas_host):
raise AuthAPIError("init client fail, bk_iam_host and bk_paas_host should not be empty")

self._host = bk_iam_host
self._bk_paas_host = bk_paas_host

# will add ?debug=true in url, for debug api/policy, show the details
isApiDebugEnabled = os.environ.get("IAM_API_DEBUG") == "true" or os.environ.get("BKAPP_IAM_API_DEBUG") == "true"
Expand Down Expand Up @@ -78,19 +97,45 @@ def _call_api(self, http_func, host, path, data, headers, timeout=None):

return True, "ok", _d

def _call_apigateway_api(self, http_func, path, data, timeout=None):
"""
统一后, 所有接口调用走APIGateway
"""
headers = {
"X-Bkapi-Authorization": json.dumps({"bk_app_code": self._app_code, "bk_app_secret": self._app_secret}),
"X-Bk-IAM-Version": BK_IAM_VERSION,
}
return self._call_api(http_func, self._host, path, data, headers, timeout=timeout)

def _call_iam_api(self, http_func, path, data, timeout=None):
"""
兼容切换到apigateway, 统一后, 这个方法应该去掉
"""
if self._apigateway_on:
return self._call_apigateway_api(http_func, path, data, timeout)

# call directly
headers = {
"X-BK-APP-CODE": self._app_code,
"X-BK-APP-SECRET": self._app_secret,
"X-Bk-IAM-Version": BK_IAM_VERSION,
}

return self._call_api(http_func, self._host, path, data, headers, timeout=timeout)

def _call_esb_api(self, http_func, path, data, bk_token, bk_username, timeout=None):
headers = {
# "BK-APP-CODE": self._app_code,
# "BK-APP-SECRET": self._app_secret,
}
"""
兼容切换到apigateway, 统一后, 这个方法应该去掉
"""
if self._apigateway_on:
apigw_path = path.replace("/api/c/compapi/v2/iam/", "/api/v1/open/")
if not path.startswith("/api/v1/open/"):
raise AuthAPIError("can't find the matched apigateway path, the esb api path is %s" % path)

return self._call_apigateway_api(http_func, apigw_path, data, timeout)

# call esb
headers = {}
data.update(
{
"bk_app_code": self._app_code,
Expand Down
29 changes: 28 additions & 1 deletion iam/contrib/iam_migration/utils/do_migrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
__version__ = "1.0.0"

BK_IAM_HOST = os.getenv("BK_IAM_V3_INNER_HOST", "http://bkiam.service.consul:5001")
USE_APIGATEWAY = os.getenv("BK_IAM_USE_APIGATEWAY", "false").lower() == "true"

APP_CODE = ""
APP_SECRET = ""
Expand Down Expand Up @@ -143,6 +144,11 @@ def __init__(self, app_code, app_secret, bk_iam_host):
# 调用权限中心方法
def _call_iam_api(self, http_func, path, data):
headers = {"X-BK-APP-CODE": self.app_code, "X-BK-APP-SECRET": self.app_secret}
if USE_APIGATEWAY:
headers = {
"X-Bkapi-Authorization": json.dumps({"bk_app_code": self.app_code, "bk_app_secret": self.app_secret}),
}

url = "{host}{path}".format(host=self.bk_iam_host, path=path)
ok, _data = http_func(url, data, headers=headers)
# TODO: add debug here
Expand Down Expand Up @@ -588,7 +594,14 @@ def do_migrate(data, bk_iam_host=BK_IAM_HOST, app_code=APP_CODE, app_secret=APP_
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument(
"-t", action="store", dest="bk_iam_host", help="bk_iam_host, i.e: http://iam.service.consul", required=True
"-t",
action="store",
dest="bk_iam_host",
help=(
"bk_iam_host, i.e: http://iam.service.consul;"
"you can use bk_apigateway_url here, set with the '--apigateway' "
),
required=True,
)
p.add_argument(
"-f",
Expand All @@ -599,9 +612,23 @@ def do_migrate(data, bk_iam_host=BK_IAM_HOST, app_code=APP_CODE, app_secret=APP_
)
p.add_argument("-a", action="store", dest="app_code", help="app code", required=True)
p.add_argument("-s", action="store", dest="app_secret", help="app secret", required=True)

p.add_argument(
"--apigateway",
action="store_true",
dest="use_apigateway",
help="you can use bk_apigateway_url in '-t', should set this flag",
)
args = p.parse_args()

BK_IAM_HOST = args.bk_iam_host.rstrip("/")
USE_APIGATEWAY = args.use_apigateway
if USE_APIGATEWAY:
print(
"use apigateway:",
args.use_apigateway,
", please make sure '-t %s' is a valid bk_apigateway_url" % args.bk_iam_host,
)

if not BK_IAM_HOST.startswith("http://"):
BK_IAM_HOST = "http://%s" % BK_IAM_HOST
Expand Down
12 changes: 10 additions & 2 deletions iam/iam.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,16 @@ class IAM(object):
input: object
"""

def __init__(self, app_code, app_secret, bk_iam_host, bk_paas_host):
self._client = Client(app_code, app_secret, bk_iam_host, bk_paas_host)
def __init__(self, app_code, app_secret, bk_iam_host=None, bk_paas_host=None, bk_apigateway_url=None):
"""
如果有 APIGateway 且权限中心网关接入, 则可以统一API请求全部走APIGateway
- 没有APIGateway的用法: IAM(app_code, app_secret, bk_iam_host, bk_paas_host)
- 有APIGateway的用法: IAM(app_code, app_secret, bk_apigateway_url)
NOTE: 未来将会下线`没有 APIGateway的用法`
TODO: 切换后, 所有暴露接口将不再依赖 bk_token/bk_username, 需考虑兼容调用方, 并文档说明
"""
self._client = Client(app_code, app_secret, bk_iam_host, bk_paas_host, bk_apigateway_url)

def _do_policy_query(self, request, with_resources=True):
data = request.to_dict()
Expand Down
2 changes: 2 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,5 +167,7 @@ def convert_example():
print("the request: ", request.to_dict())

iam = IAM("bk_paas", "2353e89a-10a2-4f30-9f6b-8973e9cd1404", "http://127.0.0.1:8080", "https://{PAAS_DOMAIN}")
# recommend if got an APIGateway
# iam = IAM("bk_paas", "2353e89a-10a2-4f30-9f6b-8973e9cd1404", bk_apigateway_url="http://{IAM_APIGATEWAY_URL}")
print("is_allowed: ", iam.is_allowed(request))
print("query: ", iam.make_filter(request))
7 changes: 7 additions & 0 deletions release.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
版本日志
===============
# v1.1.16

- add: support call apis via APIGateway

# v1.1.15

- bugfix: 修复当settings没有提供BK_IAM_SKIP变量导致migrate失败的问题

# v1.1.15

Expand Down
18 changes: 9 additions & 9 deletions tests/api/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def _test_ok_message_data(mock_request, call_func):

@patch("iam.api.client.http_post")
def test_client_policy_query(mock_post):
c = Client("bk_paas", "", "http://127.0.0.1:1234", "")
c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000")

_test_ok_message_data(mock_post, c.policy_query)

Expand Down Expand Up @@ -71,7 +71,7 @@ def _test_ok_message(mock_request, call_func, kwargs):

@patch("iam.api.client.http_post")
def test_create(mock_post):
c = Client("bk_paas", "", "http://127.0.0.1:1234", "")
c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000")

_test_ok_message(mock_post, c.add_system, dict(data={}))

Expand All @@ -84,7 +84,7 @@ def test_create(mock_post):

@patch("iam.api.client.http_put")
def test_update(mock_put):
c = Client("bk_paas", "", "http://127.0.0.1:1234", "")
c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000")

_test_ok_message(mock_put, c.update_system, dict(system_id="", data={}))

Expand All @@ -97,7 +97,7 @@ def test_update(mock_put):

@patch("iam.api.client.http_delete")
def test_delete(mock_delete):
c = Client("bk_paas", "", "http://127.0.0.1:1234", "")
c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000")

_test_ok_message(mock_delete, c.batch_delete_resource_types, dict(system_id="", data={}))

Expand All @@ -106,37 +106,37 @@ def test_delete(mock_delete):

@patch.dict(os.environ, {"ABC": "true"})
def test_client_extra_url_params_empty():
c = Client("bk_paas", "", "http://127.0.0.1:1234", "")
c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000")
assert not c._extra_url_params


@patch.dict(os.environ, {"IAM_API_DEBUG": "true"})
def test_client_extra_url_params_debug_1():
c = Client("bk_paas", "", "http://127.0.0.1:1234", "")
c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000")
assert c._extra_url_params
assert len(c._extra_url_params) == 1
assert c._extra_url_params.get("debug") == "true"


@patch.dict(os.environ, {"BKAPP_IAM_API_DEBUG": "true"})
def test_client_extra_url_params_debug_2():
c = Client("bk_paas", "", "http://127.0.0.1:1234", "")
c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000")
assert c._extra_url_params
assert len(c._extra_url_params) == 1
assert c._extra_url_params.get("debug") == "true"


@patch.dict(os.environ, {"IAM_API_FORCE": "true"})
def test_client_extra_url_params_force_1():
c = Client("bk_paas", "", "http://127.0.0.1:1234", "")
c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000")
assert c._extra_url_params
assert len(c._extra_url_params) == 1
assert c._extra_url_params.get("force") == "true"


@patch.dict(os.environ, {"BKAPP_IAM_API_FORCE": "true"})
def test_client_extra_url_params_force_2():
c = Client("bk_paas", "", "http://127.0.0.1:1234", "")
c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000")
assert c._extra_url_params
assert len(c._extra_url_params) == 1
assert c._extra_url_params.get("force") == "true"
2 changes: 1 addition & 1 deletion tests/test_iam.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@


def new_mock_iam():
return IAM("test", "test", "iam_host", "paas_host")
return IAM("test", "test", "iam_host", "paas_host", None)


def new_valid_request():
Expand Down

0 comments on commit fef653a

Please sign in to comment.