Skip to content

Commit 12c955f

Browse files
committed
feat: deploy with OAuth2
Signed-off-by: Xie Zhihao <zhihao.xie@bytedance.com>
1 parent c63e923 commit 12c955f

9 files changed

Lines changed: 446 additions & 13 deletions

File tree

veadk/cli/cli_deploy.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,23 @@
4949
type=click.Choice(["local", "mysql"]),
5050
help="Backend for short-term memory",
5151
)
52+
@click.option("--use-adk-web", is_flag=True, help="Whether to use ADK Web")
5253
@click.option(
5354
"--auth-method",
5455
default="none",
55-
type=click.Choice(["none", "api-key"]),
56+
type=click.Choice(["none", "api-key", "oauth2"]),
5657
help="=Authentication method for agent",
5758
)
58-
@click.option("--use-adk-web", is_flag=True, help="Whether to use ADK Web")
59+
@click.option(
60+
"--veidentity-user-pool-name",
61+
default="",
62+
help="Expected Volcengine Identity user pool name",
63+
)
64+
@click.option(
65+
"--veidentity-client-name",
66+
default="",
67+
help="Expected Volcengine Identity client name",
68+
)
5969
@click.option("--path", default=".", help="Local project path")
6070
def deploy(
6171
access_key: str,
@@ -67,6 +77,8 @@ def deploy(
6777
short_term_memory_backend: str,
6878
use_adk_web: bool,
6979
auth_method: str,
80+
veidentity_user_pool_name: str,
81+
veidentity_client_name: str,
7082
path: str,
7183
) -> None:
7284
"""Deploy a user project to Volcengine FaaS application.
@@ -99,6 +111,8 @@ def deploy(
99111
use_adk_web: Flag to enable ADK Web interface for the deployed agent
100112
auth_method: Authentication for the agent.
101113
Choices are 'none', 'api-key' or 'oauth2'.
114+
veidentity_user_pool_name: Optional Volcengine Identity user pool name
115+
veidentity_client_name: Optional Volcengine Identity client name
102116
path: Local directory path containing the VeADK project to deploy
103117
104118
Note:
@@ -141,6 +155,8 @@ def deploy(
141155
"veapig_upstream_name": veapig_upstream_name,
142156
"use_adk_web": use_adk_web,
143157
"auth_method": auth_method,
158+
"veidentity_user_pool_name": veidentity_user_pool_name,
159+
"veidentity_client_name": veidentity_client_name,
144160
"veadk_version": VERSION,
145161
}
146162

veadk/cli/cli_init.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,12 @@ def _render_prompts() -> dict[str, Any]:
6666
auth_method_options = {
6767
"1": "None",
6868
"2": "API key",
69+
"3": "OAuth2",
6970
}
7071
auth_methods = {
7172
"1": "none",
7273
"2": "api-key",
74+
"3": "oauth2",
7375
}
7476

7577
click.echo("Choose an authentication method:")
@@ -81,13 +83,27 @@ def _render_prompts() -> dict[str, Any]:
8183
)
8284
auth_method = auth_methods[auth_method_idx]
8385

86+
veidentity_user_pool_name = ""
87+
veidentity_client_name = ""
88+
if auth_method == "oauth2":
89+
veidentity_user_pool_name = click.prompt(
90+
"Volcengine Identity user pool name", default="", show_default=True
91+
)
92+
93+
if use_adk_web:
94+
veidentity_client_name = click.prompt(
95+
"Volcengine Identity client name", default="", show_default=True
96+
)
97+
8498
return {
8599
"vefaas_application_name": vefaas_application_name,
86100
"veapig_instance_name": veapig_instance_name,
87101
"veapig_service_name": veapig_service_name,
88102
"veapig_upstream_name": veapig_upstream_name,
89103
"use_adk_web": use_adk_web,
90104
"auth_method": auth_method,
105+
"veidentity_user_pool_name": veidentity_user_pool_name,
106+
"veidentity_client_name": veidentity_client_name,
91107
"veadk_version": VERSION,
92108
}
93109

veadk/cloud/cloud_agent_engine.py

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import json
1516
import os
1617
import socket
1718
import subprocess
@@ -23,7 +24,9 @@
2324

2425
from veadk.cloud.cloud_app import CloudApp
2526
from veadk.config import getenv, veadk_environments
27+
from veadk.integrations.ve_apig.ve_apig import APIGateway
2628
from veadk.integrations.ve_faas.ve_faas import VeFaaS
29+
from veadk.integrations.ve_identity.ve_identity import Identity
2730
from veadk.utils.logger import get_logger
2831
from veadk.utils.misc import formatted_timestamp
2932

@@ -43,6 +46,8 @@ class CloudAgentEngine(BaseModel):
4346
Defaults to VOLCENGINE_SECRET_KEY environment variable.
4447
region (str): Region for Volcengine services. Defaults to "cn-beijing".
4548
_vefaas_service (VeFaaS): Internal VeFaaS client instance, initialized post-creation.
49+
_veapig_service (APIGateway): Internal VeAPIG client instance, initialized post-creation.
50+
_veidentity_service (Identity): Internal Identity client instance, initialized post-creation.
4651
4752
Note:
4853
Credentials must be set via environment variables for default behavior.
@@ -81,6 +86,16 @@ def model_post_init(self, context: Any, /) -> None:
8186
secret_key=self.volcengine_secret_key,
8287
region=self.region,
8388
)
89+
self._veapig_service = APIGateway(
90+
access_key=self.volcengine_access_key,
91+
secret_key=self.volcengine_secret_key,
92+
region=self.region,
93+
)
94+
self._veidentity_service = Identity(
95+
access_key=self.volcengine_access_key,
96+
secret_key=self.volcengine_secret_key,
97+
region=self.region,
98+
)
8499

85100
def _prepare(self, path: str, name: str):
86101
"""Prepares the local project for deployment by validating path and name.
@@ -197,8 +212,10 @@ def deploy(
197212
gateway_name: str = "",
198213
gateway_service_name: str = "",
199214
gateway_upstream_name: str = "",
200-
auth_method: str = "none",
201215
use_adk_web: bool = False,
216+
auth_method: str = "none",
217+
identity_user_pool_name: str = "",
218+
identity_client_name: str = "",
202219
local_test: bool = False,
203220
) -> CloudApp:
204221
"""Deploys a local agent project to Volcengine FaaS, creating necessary resources.
@@ -211,8 +228,10 @@ def deploy(
211228
gateway_name (str, optional): Custom gateway resource name. Defaults to timestamped.
212229
gateway_service_name (str, optional): Custom service name. Defaults to timestamped.
213230
gateway_upstream_name (str, optional): Custom upstream name. Defaults to timestamped.
214-
auth_method (str, optional): Authentication for the agent. Defaults to none.
215231
use_adk_web (bool): Enable ADK Web configuration. Defaults to False.
232+
auth_method (str, optional): Authentication for the agent. Defaults to none.
233+
identity_user_pool_name (str, optional): Custom user pool name. Defaults to timestamped.
234+
identity_client_name (str, optional): Custom client name. Defaults to timestamped.
216235
local_test (bool): Perform FastAPI server test before deploy. Defaults to False.
217236
218237
Returns:
@@ -256,6 +275,12 @@ def deploy(
256275
gateway_service_name = f"{application_name}-gw-svr-{formatted_timestamp()}"
257276
if not gateway_upstream_name:
258277
gateway_upstream_name = f"{application_name}-gw-us-{formatted_timestamp()}"
278+
if not identity_user_pool_name:
279+
identity_user_pool_name = (
280+
f"{application_name}-id-up-{formatted_timestamp()}"
281+
)
282+
if not identity_client_name:
283+
identity_client_name = f"{application_name}-id-cli-{formatted_timestamp()}"
259284

260285
try:
261286
vefaas_application_url, app_id, function_id = self._vefaas_service.deploy(
@@ -268,6 +293,103 @@ def deploy(
268293
)
269294
_ = function_id # for future use
270295

296+
app = self._vefaas_service.get_application_details(app_id=app_id)
297+
cloud_resource = json.loads(app["CloudResource"])
298+
veapig_gateway_id = cloud_resource["framework"]["triggers"][0][
299+
"DetailedConfig"
300+
]["GatewayId"]
301+
veapig_route_id = cloud_resource["framework"]["triggers"][0]["Routes"][0][
302+
"Id"
303+
]
304+
305+
if auth_method == "oauth2":
306+
# Get or create the Identity user pool.
307+
identity_user_pool_id = self._veidentity_service.get_user_pool(
308+
name=identity_user_pool_name,
309+
)
310+
if not identity_user_pool_id:
311+
identity_user_pool_id = self._veidentity_service.create_user_pool(
312+
name=identity_user_pool_name,
313+
)
314+
315+
# Create APIG upstream for Identity.
316+
identity_domain = f"auth.id.{self.region}.volces.com"
317+
veapig_identity_upstream_id = (
318+
self._veapig_service.check_domain_upstream_exist(
319+
domain=identity_domain,
320+
port=443,
321+
gateway_id=veapig_gateway_id,
322+
)
323+
)
324+
if not veapig_identity_upstream_id:
325+
veapig_identity_upstream_id = (
326+
self._veapig_service.create_domain_upstream(
327+
domain=f"auth.id.{self.region}.volces.com",
328+
port=443,
329+
is_https=True,
330+
gateway_id=veapig_gateway_id,
331+
upstream_name=f"id-{formatted_timestamp()}",
332+
)
333+
)
334+
335+
# Create plugin binding.
336+
plugin_name = ""
337+
plugin_config = {}
338+
if use_adk_web:
339+
# Get or create the Identity client.
340+
identity_client_id = ""
341+
identity_client_secret = ""
342+
identity_client = self._veidentity_service.get_user_pool_client(
343+
user_pool_uid=identity_user_pool_id,
344+
name=identity_client_name,
345+
)
346+
if identity_client:
347+
identity_client_id = identity_client[0]
348+
identity_client_secret = identity_client[1]
349+
else:
350+
identity_client_id, identity_client_secret = (
351+
self._veidentity_service.create_user_pool_client(
352+
user_pool_uid=identity_user_pool_id,
353+
name=identity_client_name,
354+
client_type="WEB_APPLICATION",
355+
)
356+
)
357+
358+
self._veidentity_service.register_callback_for_user_pool_client(
359+
user_pool_uid=identity_user_pool_id,
360+
client_uid=identity_client_id,
361+
callback_url=f"{vefaas_application_url}/callback",
362+
web_origin=vefaas_application_url,
363+
)
364+
365+
plugin_name = "wasm-oauth2-sso"
366+
plugin_config = {
367+
"AuthorizationUrl": f"https://auth.id.{self.region}.volces.com/userpool/{identity_user_pool_id}/authorize",
368+
"UpstreamId": veapig_identity_upstream_id,
369+
"TokenUrl": f"https://auth.id.{self.region}.volces.com/userpool/{identity_user_pool_id}/oauth/token",
370+
"RedirectPath": "/callback",
371+
"SignoutPath": "/signout",
372+
"ClientId": identity_client_id,
373+
"ClientSecret": identity_client_secret,
374+
}
375+
else:
376+
plugin_name = "wasm-jwt-auth"
377+
plugin_config = {
378+
"RemoteJwks": {
379+
"UpstreamId": veapig_identity_upstream_id,
380+
"Url": f"auth.id.{self.region}.volces.com/userpool/{identity_user_pool_id}/keys",
381+
},
382+
"Issuer": f"https://auth.id.{self.region}.volces.com/userpool/{identity_user_pool_id}",
383+
"ValidateConsumer": False,
384+
}
385+
386+
self._vefaas_service.apig_client.create_plugin_binding(
387+
scope="ROUTE",
388+
target=veapig_route_id,
389+
plugin_name=plugin_name,
390+
plugin_config=json.dumps(plugin_config),
391+
)
392+
271393
return CloudApp(
272394
vefaas_application_name=application_name,
273395
vefaas_endpoint=vefaas_application_url,

0 commit comments

Comments
 (0)