Skip to content

Feat/aws profile auth support#415

Open
Jagdeep1 wants to merge 3 commits intoGetStream:mainfrom
Jagdeep1:feat/aws-profile-auth-support
Open

Feat/aws profile auth support#415
Jagdeep1 wants to merge 3 commits intoGetStream:mainfrom
Jagdeep1:feat/aws-profile-auth-support

Conversation

@Jagdeep1
Copy link

@Jagdeep1 Jagdeep1 commented Mar 12, 2026

PR Title

feat(aws): Add AWS profile support for Bedrock LLM and Realtime plugins

Description

Problem

The AWS plugin only supported authentication via explicit AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY environment variables or constructor parameters. Users authenticating via AWS profiles (SSO, named profiles in
~/.aws/credentials) could not use the plugin without manually exporting keys.

Solution

Added aws_profile parameter to both BedrockLLM and Realtime constructors, enabling the full boto3 credential chain (env vars, shared credentials files, AWS profiles, SSO, EC2 instance profiles, etc.).

Changes

  • aws_realtime.py: Added Boto3CredentialsResolver class implementing smithy's IdentityResolver interface using boto3.Session. This replaces EnvironmentCredentialsResolver and supports the full credential chain.
    Added aws_profile parameter to Realtime.init.
  • aws_llm.py: Added aws_profile parameter to BedrockLLM.init. Switched from boto3.client() to boto3.Session(**kwargs).client() so profile_name is respected.
  • .env.example: Added AWS_PROFILE option, removed AWS_BEARER_TOKEN_BEDROCK.

Usage

python

Profile-based auth (SSO, named profiles)

llm = aws.LLM(model="qwen.qwen3-32b-v1:0", aws_profile="my-profile")
realtime = aws.Realtime(aws_profile="my-profile")

Or set AWS_PROFILE env var — boto3 picks it up automatically

llm = aws.LLM(model="qwen.qwen3-32b-v1:0")

Explicit credentials still work (backward compatible)

llm = aws.LLM(model="qwen.qwen3-32b-v1:0", aws_access_key_id="...", aws_secret_access_key="...")

Why a custom resolver?

smithy-python's built-in resolvers only cover: static config, env vars, IMDS, and container credentials. There is no profile/shared-credentials-file resolver. Boto3CredentialsResolver delegates to boto3.Session
which handles the full AWS credential chain. This is the same pattern used by LiveKit's AWS plugin.

Backward Compatibility

  • Existing env var auth (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY) continues to work via boto3's credential chain.
  • Explicit key/secret/token constructor params on BedrockLLM still work as overrides.
  • TTS (Polly) was already using boto3's default chain — no changes needed.

Summary by CodeRabbit

  • New Features

    • Added AWS profile-based authentication for Bedrock services, letting users use named AWS profiles instead of inline credentials.
    • Credential resolution now leverages the AWS SDK chain with profile support and caches resolved credentials for more reliable realtime access.
  • Documentation

    • Updated environment template to recommend using AWS_PROFILE while keeping explicit credential options for backward compatibility.

Jagdeep Soni added 2 commits March 11, 2026 11:32
- Add aws_profile parameter to BedrockLLM for profile-based credential selection
- Replace environment variable credential resolution with boto3.Session for full credential chain support
- Implement Boto3CredentialsResolver class to delegate credential resolution to boto3
- Support AWS profiles, SSO, EC2 instance profiles, and shared credentials files
- Remove hardcoded AWS_BEDROCK_API_KEY environment variable handling
- Remove unused os import from aws_llm.py
- Update BedrockLLM client initialization to use boto3.Session
- Add aws_profile parameter to Realtime class constructor
- Improve type hints for session_kwargs in BedrockLLM
- Import os module for environment variable access
- Add support for AWS_BEDROCK_API_KEY environment variable in BedrockLLM initialization
- Set aws_session_token from environment variable when AWS_BEDROCK_API_KEY is present
- Enables credential resolution through environment variables for improved flexibility
@coderabbitai
Copy link

coderabbitai bot commented Mar 12, 2026

📝 Walkthrough

Walkthrough

This PR adds optional AWS profile-based authentication alongside explicit credentials: .env.example documents AWS_PROFILE, aws_llm.py accepts an aws_profile parameter and builds a boto3 Session when provided, and aws_realtime.py adds Boto3CredentialsResolver plus an aws_profile parameter to Realtime to resolve credentials via boto3.Session.

Changes

Cohort / File(s) Summary
Configuration
plugins/aws/example/.env.example
Removed AWS_BEARER_TOKEN_BEDROCK; added AWS_PROFILE documentation and preserved explicit credential lines (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY).
LLM client
plugins/aws/vision_agents/plugins/aws/aws_llm.py
Added optional aws_profile parameter to BedrockLLM.__init__; when set, constructs a boto3.Session(profile_name=...) and creates the Bedrock client from that session.
Realtime & credential resolution
plugins/aws/vision_agents/plugins/aws/aws_realtime.py
Added Boto3CredentialsResolver (resolves and caches credentials via boto3.Session); replaced environment-only resolver with the boto3-based resolver and added aws_profile parameter to Realtime.__init__.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant App as Client App
participant Session as boto3.Session (profile)
participant Resolver as Boto3CredentialsResolver
participant Bedrock as Bedrock Runtime Client
participant AWS as AWS Credentials Provider
App->>Resolver: request identity (with aws_profile)
Resolver->>Session: create Session(profile_name)
Session->>AWS: resolve credentials (profile chain)
AWS-->>Session: credentials + optional expiration
Session-->>Resolver: returned credentials
Resolver-->>Bedrock: provide AWSCredentialsIdentity
App->>Bedrock: call realtime/llm APIs (signed)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

The profile waits like a tongue in the dark room,
an old key turned under the ribs of the cloud.
We pull the cord — boto3 listens, a small breathing,
and credentials rise like ghosts in daylight.
The machine learns the names we no longer speak.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feat/aws profile auth support' directly and clearly describes the main change: adding AWS profile-based authentication support to the AWS plugins.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

Flake8 can be used to improve the quality of Python code reviews.

Flake8 is a Python linter that wraps PyFlakes, pycodestyle and Ned Batchelder's McCabe script.

To configure Flake8, add a '.flake8' or 'setup.cfg' file to your project root.

See Flake8 Documentation for more details.

@Jagdeep1 Jagdeep1 marked this pull request as ready for review March 12, 2026 16:09
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
plugins/aws/vision_agents/plugins/aws/aws_realtime.py (1)

194-203: Document aws_profile on the public constructor.

The new auth parameter is public API, but this constructor still has an empty docstring. A short Google-style Args: block would make the new profile flow discoverable.

As per coding guidelines, "Use Google style docstrings and keep them short".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/aws/vision_agents/plugins/aws/aws_realtime.py` around lines 194 -
203, The public constructor __init__ in aws_realtime.py lacks documentation for
the new aws_profile parameter; update the docstring for the __init__ method (the
class constructor) to a short Google-style docstring with an Args: section that
documents model, region_name, voice_id, reconnect_after_minutes, and aws_profile
(describe that aws_profile is an optional AWS CLI/profile name used for
credentials lookup), noting defaults and types; keep it concise (one-line
summary plus Args: entries) and place it immediately above the method signature
to make the new auth flow discoverable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugins/aws/vision_agents/plugins/aws/aws_llm.py`:
- Around line 69-72: The code currently injects AWS_BEDROCK_API_KEY into boto3
session_kwargs as aws_session_token which is invalid and can override profile
credentials; remove the block that maps os.environ.get("AWS_BEDROCK_API_KEY") to
session_kwargs["aws_session_token"] in aws_llm.py so session creation uses only
region_name and optional aws_profile, or if Bedrock bearer tokens are required,
instead rely on AWS_BEARER_TOKEN_BEDROCK being set in the environment (do not
place it into session_kwargs) and ensure session creation logic around
session_kwargs, region_name, and aws_profile remains unchanged.

In `@plugins/aws/vision_agents/plugins/aws/aws_realtime.py`:
- Around line 51-77: Remove the credential caching and private-attribute access:
delete self._cached and any short-circuit return using it in __init__ and
get_identity, so get_identity always calls self._session.get_credentials() each
time; remove use of getattr(credentials, "_expiry_time", None) (do not read
botocore's private _expiry_time) and instead pass a safe value (e.g., None) for
AWSCredentialsIdentity.expiration when constructing the AWSCredentialsIdentity
in get_identity; keep validation of access_key/secret_key and session_token
handling as-is.

---

Nitpick comments:
In `@plugins/aws/vision_agents/plugins/aws/aws_realtime.py`:
- Around line 194-203: The public constructor __init__ in aws_realtime.py lacks
documentation for the new aws_profile parameter; update the docstring for the
__init__ method (the class constructor) to a short Google-style docstring with
an Args: section that documents model, region_name, voice_id,
reconnect_after_minutes, and aws_profile (describe that aws_profile is an
optional AWS CLI/profile name used for credentials lookup), noting defaults and
types; keep it concise (one-line summary plus Args: entries) and place it
immediately above the method signature to make the new auth flow discoverable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1e08258f-de83-449b-9d5b-ad20fe93acb1

📥 Commits

Reviewing files that changed from the base of the PR and between b7db941 and dbeb457.

📒 Files selected for processing (3)
  • plugins/aws/example/.env.example
  • plugins/aws/vision_agents/plugins/aws/aws_llm.py
  • plugins/aws/vision_agents/plugins/aws/aws_realtime.py

Comment on lines +69 to +72
# Build boto3 Session kwargs
session_kwargs: Dict[str, Any] = {"region_name": region_name}
if aws_profile:
session_kwargs["profile_name"] = aws_profile
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Does the AWS boto3 bedrock-runtimeclient support authenticating with an API key mapped toaws_session_token, or should profile / standard AWS credentials remain the only supported auth inputs here?

💡 Result:

No—aws_session_token in boto3/botocore is only the third value in the standard AWS credential triple (access key ID + secret access key + session token) used for SigV4-signed requests; it’s not a generic “API key” slot, and you can’t authenticate to bedrock-runtime by stuffing a Bedrock API key into aws_session_token. [1][2]

If you want API-key-style auth for Amazon Bedrock Runtime, AWS provides Bedrock API keys that are sent as a Bearer token (for example via the environment variable AWS_BEARER_TOKEN_BEDROCK, or an Authorization: Bearer ... header). With recent SDKs, boto3 will work when that env var is set and you create a normal boto3.client("bedrock-runtime", ...). [1][3]

So the supported auth inputs are:

  • Standard AWS credentials / profiles / default credential chain (SigV4), optionally with aws_session_token as part of temporary creds. [2]
  • Bedrock API key bearer-token flow via AWS_BEARER_TOKEN_BEDROCK (not via aws_session_token). [1][3]

Sources
[1] Amazon Bedrock User Guide – “Use an Amazon Bedrock API key” (AWS_BEARER_TOKEN_BEDROCK, Authorization: Bearer ..., boto3 example)
[2] Boto3 credentials guide (defines aws_access_key_id/aws_secret_access_key/aws_session_token as AWS credentials)
[3] AWS ML Blog (Jul 8, 2025) – Bedrock API keys; SDKs detect AWS_BEARER_TOKEN_BEDROCK and support API-key authentication


Remove AWS_BEDROCK_API_KEY override to aws_session_token—it's not a valid Bedrock authentication method.

The code at lines 80–81 maps AWS_BEDROCK_API_KEY to aws_session_token, but aws_session_token in boto3 is only the session-token component of standard AWS credentials (SigV4), not a slot for Bedrock API keys. According to AWS Bedrock documentation, Bedrock API keys should be passed via the AWS_BEARER_TOKEN_BEDROCK environment variable, which boto3 detects and uses automatically. The current code both misuses the boto3 API and clobbers any profile-derived credentials set by the new aws_profile path.

Either remove this block entirely if only standard AWS credentials should be supported, or replace it with proper Bedrock API key handling via AWS_BEARER_TOKEN_BEDROCK.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/aws/vision_agents/plugins/aws/aws_llm.py` around lines 69 - 72, The
code currently injects AWS_BEDROCK_API_KEY into boto3 session_kwargs as
aws_session_token which is invalid and can override profile credentials; remove
the block that maps os.environ.get("AWS_BEDROCK_API_KEY") to
session_kwargs["aws_session_token"] in aws_llm.py so session creation uses only
region_name and optional aws_profile, or if Bedrock bearer tokens are required,
instead rely on AWS_BEARER_TOKEN_BEDROCK being set in the environment (do not
place it into session_kwargs) and ensure session creation logic around
session_kwargs, region_name, and aws_profile remains unchanged.

Comment on lines +51 to +77
def __init__(self, profile_name: Optional[str] = None) -> None:
self._session = boto3.Session(profile_name=profile_name)
self._cached: Optional[AWSCredentialsIdentity] = None

async def get_identity(
self, *, properties: AWSIdentityProperties, **kwargs: Any
) -> AWSCredentialsIdentity:
if self._cached is not None:
return self._cached

credentials = self._session.get_credentials()
if not credentials:
raise ValueError("Unable to load AWS credentials via boto3")

creds = credentials.get_frozen_credentials()
if not creds.access_key or not creds.secret_key:
raise ValueError("AWS credentials are incomplete")

expiry = getattr(credentials, "_expiry_time", None)

self._cached = AWSCredentialsIdentity(
access_key_id=creds.access_key,
secret_access_key=creds.secret_key,
session_token=creds.token or None,
expiration=expiry,
)
return self._cached
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

For boto3/botocore sessions that use SSO, assume-role, or instance-profile credentials, do credentials auto-refresh, and is _expiry_time on the credentials object considered a private implementation detail?

💡 Result:

  • Do SSO / assume-role / instance-profile creds auto-refresh? Yes—when they come from botocore’s refreshable credential providers, botocore will keep using cached temporary credentials until near/at expiration and then refresh them automatically (i.e., you don’t normally recreate the Session). This is the documented behavior for temporary credentials in boto3. (docs.aws.amazon.com)

    • AssumeRole (from ~/.aws/config, e.g., role_arn) is handled by botocore’s assume-role provider in the default credential chain, which uses refreshable credentials under the hood. (github.com)
    • Instance profile (EC2 IMDS) / container task roles are also providers in the default chain and are refreshable. (github.com)
    • SSO / IAM Identity Center profiles are provided by SSOProvider in the profile provider chain and are designed to refresh as long as the underlying SSO token/session is still valid; if that token is expired/invalid, refresh can fail and you’ll need to re-auth (e.g., aws sso login). (github.com)
  • Is _expiry_time private? Yes. In botocore it’s an underscore-prefixed attribute (self._expiry_time) on RefreshableCredentials, not a documented/stable public API, and botocore issue discussions indicate callers want (but don’t have) a public and stable expiration interface—so depending on _expiry_time is relying on an internal implementation detail. (github.com)

Citations:


Remove credential caching to enable boto3's automatic refresh.

Caching AWSCredentialsIdentity in self._cached prevents boto3/botocore from refreshing temporary credentials (SSO, assume-role, instance profiles). Even though botocore auto-refreshes when the session is reused, this code short-circuits that mechanism by caching the frozen credentials from the first call and never calling session.get_credentials() again. Line 69 also violates the guideline against getattr by accessing botocore's private _expiry_time attribute.

Remove the cache and call session.get_credentials() on every get_identity() call.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/aws/vision_agents/plugins/aws/aws_realtime.py` around lines 51 - 77,
Remove the credential caching and private-attribute access: delete self._cached
and any short-circuit return using it in __init__ and get_identity, so
get_identity always calls self._session.get_credentials() each time; remove use
of getattr(credentials, "_expiry_time", None) (do not read botocore's private
_expiry_time) and instead pass a safe value (e.g., None) for
AWSCredentialsIdentity.expiration when constructing the AWSCredentialsIdentity
in get_identity; keep validation of access_key/secret_key and session_token
handling as-is.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
plugins/aws/vision_agents/plugins/aws/aws_realtime.py (1)

51-77: ⚠️ Potential issue | 🟠 Major

Credential caching disables boto3's automatic refresh for temporary credentials.

The caching mechanism here entombs credentials in amber—once frozen, they never stir again. For SSO, assume-role, and instance-profile credentials, botocore auto-refreshes when the session is reused, but this implementation short-circuits that by caching the frozen credentials from the first call and never invoking session.get_credentials() again.

Additionally, line 69 violates two constraints:

  1. Uses getattr which the coding guidelines prohibit
  2. Accesses botocore's underscore-prefixed _expiry_time attribute, which is an internal implementation detail without a stable public API

Remove self._cached and the caching logic. Call self._session.get_credentials() on every get_identity() invocation to let boto3 handle refresh. For expiration, pass None since there's no public API to retrieve it.

,

🔧 Proposed fix
     def __init__(self, profile_name: Optional[str] = None) -> None:
         self._session = boto3.Session(profile_name=profile_name)
-        self._cached: Optional[AWSCredentialsIdentity] = None

     async def get_identity(
-        self, *, properties: AWSIdentityProperties, **kwargs: Any
+        self, *, properties: AWSIdentityProperties, **kwargs: object
     ) -> AWSCredentialsIdentity:
-        if self._cached is not None:
-            return self._cached
-
         credentials = self._session.get_credentials()
         if not credentials:
             raise ValueError("Unable to load AWS credentials via boto3")

         creds = credentials.get_frozen_credentials()
         if not creds.access_key or not creds.secret_key:
             raise ValueError("AWS credentials are incomplete")

-        expiry = getattr(credentials, "_expiry_time", None)
-
-        self._cached = AWSCredentialsIdentity(
+        return AWSCredentialsIdentity(
             access_key_id=creds.access_key,
             secret_access_key=creds.secret_key,
             session_token=creds.token or None,
-            expiration=expiry,
+            expiration=None,
         )
-        return self._cached

As per coding guidelines: "Avoid getattr, hasattr, delattr, setattr; prefer normal attribute access" and "Avoid using Any type".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/aws/vision_agents/plugins/aws/aws_realtime.py` around lines 51 - 77,
Remove the credential caching in AWSCredentialsIdentity provider: delete the
self._cached attribute and all logic that returns or sets it so get_identity()
calls self._session.get_credentials() on every invocation (letting botocore
auto-refresh temp creds); stop using getattr(..., "_expiry_time") or accessing
the internal _expiry_time attribute—set expiration to None when creating
AWSCredentialsIdentity; and update the get_identity signature to avoid Any
(e.g., use **kwargs: Mapping[str, object]) to comply with typing guidelines.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@plugins/aws/vision_agents/plugins/aws/aws_realtime.py`:
- Around line 51-77: Remove the credential caching in AWSCredentialsIdentity
provider: delete the self._cached attribute and all logic that returns or sets
it so get_identity() calls self._session.get_credentials() on every invocation
(letting botocore auto-refresh temp creds); stop using getattr(...,
"_expiry_time") or accessing the internal _expiry_time attribute—set expiration
to None when creating AWSCredentialsIdentity; and update the get_identity
signature to avoid Any (e.g., use **kwargs: Mapping[str, object]) to comply with
typing guidelines.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a9192ab7-8cc3-4957-b407-66a78535459d

📥 Commits

Reviewing files that changed from the base of the PR and between dbeb457 and f295abc.

📒 Files selected for processing (1)
  • plugins/aws/vision_agents/plugins/aws/aws_realtime.py

@Nash0x7E2
Copy link
Member

Hi @Jagdeep1, I fixed the CI errors, @d3xvn is testing the PR before merging

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants