Skip to content

Commit 3b9d9d0

Browse files
sundargthbSundar Raghavan
andauthored
Use SDK-native certificates parameter for Code Interpreter (#1416)
The CodeInterpreter SDK wrapper supports the certificates parameter on create_code_interpreter(). Replace the boto3 control plane workaround with Certificate.from_secret_arn(), matching the pattern used for BrowserClient.create_browser(). Co-authored-by: Sundar Raghavan <sdraghav@amazon.com>
1 parent 4eafe85 commit 3b9d9d0

1 file changed

Lines changed: 32 additions & 46 deletions

File tree

01-tutorials/05-AgentCore-tools/02-Agent-Core-browser-tool/13-browser-chrome-policies/browser-chrome-policies.ipynb

Lines changed: 32 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"\n",
1515
"**Part 1** creates a Chrome policy that locks the browser to AWS documentation, uses Playwright to demonstrate the restrictions (allowed URL succeeds, blocked URL is rejected by Chrome), and uses session recording to review the enforcement.\n",
1616
"\n",
17-
"**Part 2** demonstrates custom root CA certificates using [badssl.com](https://badssl.com) \u2014 a public site with an intentionally untrusted certificate \u2014 to show how Code Interpreter sessions can trust non-public CAs."
17+
"**Part 2** demonstrates custom root CA certificates using [badssl.com](https://badssl.com) a public site with an intentionally untrusted certificate to show how Code Interpreter sessions can trust non-public CAs."
1818
]
1919
},
2020
{
@@ -88,7 +88,7 @@
8888
"ACCOUNT_ID = boto3.client('sts').get_caller_identity()['Account']\n",
8989
"REGION = session.region_name\n",
9090
"\n",
91-
"# Derived names \u2014 no manual replacement needed\n",
91+
"# Derived names no manual replacement needed\n",
9292
"BUCKET_NAME = f\"ac-browser-policy-demo-{ACCOUNT_ID}-{REGION}\"\n",
9393
"AC_ROLE_NAME = \"ac-browser-policy-execution-role\"\n",
9494
"BROWSER_NAME = \"docs_research_browser\"\n",
@@ -152,7 +152,7 @@
152152
"metadata": {},
153153
"outputs": [],
154154
"source": [
155-
"# Trust policy \u2014 bedrock-agentcore.amazonaws.com is the service principal\n",
155+
"# Trust policy bedrock-agentcore.amazonaws.com is the service principal\n",
156156
"trust_policy = {\n",
157157
" \"Version\": \"2012-10-17\",\n",
158158
" \"Statement\": [{\n",
@@ -263,7 +263,7 @@
263263
"id": "ba7a07117329",
264264
"metadata": {},
265265
"source": [
266-
"> **Important \u2014 CDP compatibility:** Do not set `DeveloperToolsAvailability` to `2` (disabled). All AgentCore Browser automation uses the Chrome DevTools Protocol (CDP) via Playwright's `connect_over_cdp`. Setting this policy to `2` disables CDP at the Chrome level, which silently breaks all automation \u2014 the WebSocket connection succeeds at the proxy layer but Chrome refuses CDP commands, causing timeouts. Use `0` (allowed) or `1` (allowed only for extensions) instead.\n"
266+
"> **Important CDP compatibility:** Do not set `DeveloperToolsAvailability` to `2` (disabled). All AgentCore Browser automation uses the Chrome DevTools Protocol (CDP) via Playwright's `connect_over_cdp`. Setting this policy to `2` disables CDP at the Chrome level, which silently breaks all automation the WebSocket connection succeeds at the proxy layer but Chrome refuses CDP commands, causing timeouts. Use `0` (allowed) or `1` (allowed only for extensions) instead.\n"
267267
]
268268
},
269269
{
@@ -309,8 +309,8 @@
309309
"\n",
310310
"Create a custom browser that enforces the Chrome policy on every session. The `enterprise_policies` parameter takes a list of policy objects, each with a `location` (S3 path to the JSON file) and a `type`:\n",
311311
"\n",
312-
"- **`MANAGED`** \u2014 enforced at the browser level, cannot be overridden (maps to Chrome's `/etc/chromium/policies/managed/`)\n",
313-
"- **`RECOMMENDED`** \u2014 applied at the session level as preferences (maps to Chrome's `/etc/chromium/policies/recommended/`)\n",
312+
"- **`MANAGED`** enforced at the browser level, cannot be overridden (maps to Chrome's `/etc/chromium/policies/managed/`)\n",
313+
"- **`RECOMMENDED`** applied at the session level as preferences (maps to Chrome's `/etc/chromium/policies/recommended/`)\n",
314314
"\n",
315315
"Session recording is enabled so you can replay the session afterward in the AgentCore console."
316316
]
@@ -403,7 +403,7 @@
403403
" reason = info.get(\"failureReason\", \"Unknown\")\n",
404404
" print(f\"Browser creation failed: {reason}\")\n",
405405
" raise SystemExit(1)\n",
406-
" print(f\" Status: {status} \u2014 waiting...\")\n",
406+
" print(f\" Status: {status} waiting...\")\n",
407407
" time.sleep(5)"
408408
]
409409
},
@@ -416,12 +416,12 @@
416416
"\n",
417417
"Start a browser session and use [Playwright](https://playwright.dev/docs/intro) to navigate to two URLs:\n",
418418
"\n",
419-
"1. **`docs.aws.amazon.com`** \u2014 allowed by the policy \u2192 page loads successfully\n",
420-
"2. **`www.wikipedia.org`** \u2014 blocked by the policy \u2192 Chrome displays an error page\n",
419+
"1. **`docs.aws.amazon.com`** allowed by the policy page loads successfully\n",
420+
"2. **`www.wikipedia.org`** blocked by the policy Chrome displays an error page\n",
421421
"\n",
422422
"This demonstrates that the restriction happens at the browser level, independent of any agent prompt or reasoning logic.\n",
423423
"\n",
424-
"> **Tip:** While this cell runs, you can watch the browser live in the AgentCore console. Navigate to **Built-in tools** \u2192 **docs_research_browser** \u2192 **View live session**."
424+
"> **Tip:** While this cell runs, you can watch the browser live in the AgentCore console. Navigate to **Built-in tools** **docs_research_browser** **View live session**."
425425
]
426426
},
427427
{
@@ -457,7 +457,7 @@
457457
" context = browser.contexts[0]\n",
458458
" page = context.pages[0] if context.pages else await context.new_page()\n",
459459
"\n",
460-
" # \u2500\u2500 Test 1: Navigate to ALLOWED URL \u2500\u2500\n",
460+
" # ── Test 1: Navigate to ALLOWED URL ──\n",
461461
" print(\"\\n\" + \"=\" * 60)\n",
462462
" print(\"TEST 1: Navigate to docs.aws.amazon.com (ALLOWED)\")\n",
463463
" print(\"=\" * 60)\n",
@@ -480,7 +480,7 @@
480480
" print(f\"Extracted {len(text)} chars\")\n",
481481
" print(f\"First 500 chars:\\n{text[:500]}\")\n",
482482
"\n",
483-
" # \u2500\u2500 Test 2: Navigate to BLOCKED URL \u2500\u2500\n",
483+
" # ── Test 2: Navigate to BLOCKED URL ──\n",
484484
" print(\"\\n\" + \"=\" * 60)\n",
485485
" print(\"TEST 2: Navigate to www.wikipedia.org (BLOCKED)\")\n",
486486
" print(\"=\" * 60)\n",
@@ -490,11 +490,11 @@
490490
" blocked_title = await page.title()\n",
491491
" content = await page.evaluate(\"() => document.documentElement.outerHTML\", None)\n",
492492
" if \"blocked\" in content.lower() or \"ERR_BLOCKED\" in content:\n",
493-
" print(\"Result: CHROME POLICY BLOCKED THIS URL \u2705\")\n",
493+
" print(\"Result: CHROME POLICY BLOCKED THIS URL \")\n",
494494
" else:\n",
495-
" print(f\"Result: Page loaded (unexpected) \u2014 title: {blocked_title}\")\n",
495+
" print(f\"Result: Page loaded (unexpected) title: {blocked_title}\")\n",
496496
" except Exception as e:\n",
497-
" print(\"Result: CHROME POLICY BLOCKED THIS URL \u2705\")\n",
497+
" print(\"Result: CHROME POLICY BLOCKED THIS URL \")\n",
498498
"\n",
499499
" await browser.close()\n",
500500
" return text\n",
@@ -522,9 +522,9 @@
522522
"5. Choose **View Recording**\n",
523523
"\n",
524524
"The replay interface shows:\n",
525-
"- **Video player** \u2014 interactive playback with timeline scrubber\n",
526-
"- **User actions** \u2014 timestamped navigation events, including the blocked URL attempt\n",
527-
"- **Network events** \u2014 confirming only `docs.aws.amazon.com` traffic succeeded"
525+
"- **Video player** interactive playback with timeline scrubber\n",
526+
"- **User actions** timestamped navigation events, including the blocked URL attempt\n",
527+
"- **Network events** confirming only `docs.aws.amazon.com` traffic succeeded"
528528
]
529529
},
530530
{
@@ -536,7 +536,7 @@
536536
"\n",
537537
"You can also use the policy-restricted browser with an AI agent framework. The cell below creates a [Strands](https://strandsagents.com/) agent that researches AgentCore documentation. The agent will succeed on `docs.aws.amazon.com` and observe that `wikipedia.org` is blocked.\n",
538538
"\n",
539-
"This sample uses Anthropic Claude through Amazon Bedrock. AgentCore is model-agnostic \u2014 you can substitute any model provider. For model configuration, refer to [Model Providers](https://strandsagents.com/latest/user-guide/concepts/model-providers/).\n",
539+
"This sample uses Anthropic Claude through Amazon Bedrock. AgentCore is model-agnostic you can substitute any model provider. For model configuration, refer to [Model Providers](https://strandsagents.com/latest/user-guide/concepts/model-providers/).\n",
540540
"\n",
541541
"> **Note:** The `AgentCoreBrowser` tool in `strands-agents-tools` creates browser sessions on demand. If you experience connection timeouts on the first attempt, the tool will retry. The first session creation for a newly created browser may take longer."
542542
]
@@ -596,7 +596,7 @@
596596
"\n",
597597
"Organizations that run internal services with private certificate authorities, or route traffic through SSL-intercepting corporate proxies, need their agents to trust those non-public certificates.\n",
598598
"\n",
599-
"To demonstrate this capability without requiring internal infrastructure, this section uses [https://untrusted-root.badssl.com](https://untrusted-root.badssl.com) \u2014 a public website that intentionally uses a certificate signed by an untrusted root CA. Normally, HTTPS connections to this site fail with SSL certificate errors, just like connections to your internal services would fail without the correct root CA."
599+
"To demonstrate this capability without requiring internal infrastructure, this section uses [https://untrusted-root.badssl.com](https://untrusted-root.badssl.com) a public website that intentionally uses a certificate signed by an untrusted root CA. Normally, HTTPS connections to this site fail with SSL certificate errors, just like connections to your internal services would fail without the correct root CA."
600600
]
601601
},
602602
{
@@ -677,7 +677,7 @@
677677
"id": "04d58e025d2e",
678678
"metadata": {},
679679
"source": [
680-
"### Step 6: Code Interpreter WITHOUT root CA \u2014 expect SSL error\n",
680+
"### Step 6: Code Interpreter WITHOUT root CA expect SSL error\n",
681681
"\n",
682682
"Create a default Code Interpreter session and attempt to connect to `https://untrusted-root.badssl.com`. The connection will fail because the root CA is not trusted."
683683
]
@@ -727,11 +727,9 @@
727727
"id": "43c58bb1e8f7",
728728
"metadata": {},
729729
"source": [
730-
"### Step 7: Code Interpreter WITH root CA \u2014 expect HTTP 200\n",
730+
"### Step 7: Code Interpreter WITH root CA expect HTTP 200\n",
731731
"\n",
732-
"Create a custom Code Interpreter that trusts the BadSSL root CA certificate using the `certificates` parameter.\n",
733-
"\n",
734-
"> **Note:** The `CodeInterpreter` SDK wrapper does not yet support the `certificates` parameter in `create_code_interpreter()`. The cell below uses the boto3 control plane client directly for creation, then switches back to the SDK for session operations. Once the SDK is updated, you can use `Certificate.from_secret_arn(secret_arn)` directly \u2014 the same pattern shown in the Browser\u2019s `create_browser()` call.\n"
732+
"Create a custom Code Interpreter that trusts the BadSSL root CA certificate using the `certificates` parameter. This uses the same `Certificate.from_secret_arn(...)` pattern shown in the Browser's `create_browser()` call.\n"
735733
]
736734
},
737735
{
@@ -741,33 +739,21 @@
741739
"metadata": {},
742740
"outputs": [],
743741
"source": [
744-
"from bedrock_agentcore._utils.endpoints import get_control_plane_endpoint\n",
742+
"from bedrock_agentcore.tools import Certificate\n",
745743
"\n",
746-
"# The CodeInterpreter SDK wrapper does not yet support the certificates parameter.\n",
747-
"# Use the boto3 control plane client directly for creation, then use the SDK for\n",
748-
"# session operations (start, invoke, stop).\n",
749-
"cp_client = boto3.client(\n",
750-
" \"bedrock-agentcore-control\",\n",
751-
" region_name=REGION,\n",
752-
" endpoint_url=get_control_plane_endpoint(REGION),\n",
753-
")\n",
744+
"ci_client_with_ca = CodeInterpreter(REGION)\n",
754745
"\n",
755-
"response = cp_client.create_code_interpreter(\n",
746+
"response = ci_client_with_ca.create_code_interpreter(\n",
756747
" name=\"demo_rootca_interpreter\",\n",
757-
" executionRoleArn=EXECUTION_ROLE_ARN,\n",
758-
" networkConfiguration={\"networkMode\": \"PUBLIC\"},\n",
759-
" certificates=[\n",
760-
" {\"location\": {\"secretsManager\": {\"secretArn\": secret_arn}}}\n",
761-
" ],\n",
748+
" execution_role_arn=EXECUTION_ROLE_ARN,\n",
749+
" network_configuration={\"networkMode\": \"PUBLIC\"},\n",
750+
" certificates=[Certificate.from_secret_arn(secret_arn)],\n",
762751
" description=\"Code interpreter trusting BadSSL untrusted root CA\",\n",
763752
")\n",
764753
"\n",
765754
"interpreter_id = response[\"codeInterpreterId\"]\n",
766755
"print(f\"Created interpreter: {interpreter_id}\")\n",
767756
"\n",
768-
"# Use the SDK client for subsequent operations\n",
769-
"ci_client_with_ca = CodeInterpreter(REGION)\n",
770-
"\n",
771757
"# Wait for ready\n",
772758
"print(\"Waiting for interpreter to become ready...\")\n",
773759
"while True:\n",
@@ -815,7 +801,7 @@
815801
" exit_code = structured.get(\"exitCode\", -1)\n",
816802
"\n",
817803
" if exit_code == 0 and \"200\" in stdout:\n",
818-
" print(\"Result: SUCCESS \u2014 HTTP 200\")\n",
804+
" print(\"Result: SUCCESS HTTP 200\")\n",
819805
" print(\" The connection succeeded because the root CA is now trusted.\")\n",
820806
" print(f\" Output: {stdout[:200]}\")\n",
821807
" else:\n",
@@ -839,7 +825,7 @@
839825
"| Internal corporate services | Your organization's root CA certificate (HR portal, Jira, Artifactory) | Reference the secret ARN in `certificates` when creating a browser or code interpreter |\n",
840826
"| SSL-intercepting corporate proxies | Your proxy's root CA certificate (Zscaler, Palo Alto Networks) | Reference the secret ARN in `certificates` and configure proxy settings |\n",
841827
"\n",
842-
"You can combine root CA certificates with Chrome policies in a single `create_browser` call \u2014 see the accompanying blog post for a combined example."
828+
"You can combine root CA certificates with Chrome policies in a single `create_browser` call see the accompanying blog post for a combined example."
843829
]
844830
},
845831
{
@@ -981,4 +967,4 @@
981967
},
982968
"nbformat": 4,
983969
"nbformat_minor": 5
984-
}
970+
}

0 commit comments

Comments
 (0)