Skip to content

fix(strands-agent-base): CVE remediation + AccessDenied retry + A2A factory fix - #36

Open
shapirov103 wants to merge 3 commits into
mainfrom
feature/oam-for-agents
Open

fix(strands-agent-base): CVE remediation + AccessDenied retry + A2A factory fix#36
shapirov103 wants to merge 3 commits into
mainfrom
feature/oam-for-agents

Conversation

@shapirov103

Copy link
Copy Markdown
Contributor

Summary

Hardens the strands-agent-base image: dependency/base-image CVE remediation, retry-with-backoff for the first-boot IAM propagation race, and two A2A SDK compatibility fixes discovered while testing on the hub cluster.

Also includes an earlier commit hardening the aws-service-identity OAM trait's init container (control-plane readiness gate on PodIdentity via kubectl wait, replacing an STS-based check that could be fooled by node-role fallback).

Changes

Dependency/base-image hardening (pyproject.toml, Dockerfile):

  • Pin fastapi==0.139.2, starlette==1.3.1 — fixes CVE-2025-62727, CVE-2026-48818, CVE-2026-54283
  • Pin pydantic==2.13.4, uvicorn==0.51.0, bedrock-agentcore==1.18.1 (previously unpinned), aws-opentelemetry-distro==0.18.0, strands-agents==1.48.0
  • Add tenacity==9.1.4 for retry-with-backoff
  • Pin Dockerfile builder image (uv:0.9.30-python3.13-bookworm-slim) and final stage (python:3.13-slim-bookworm by digest) for supply-chain immutability
  • Remaining OS-layer CVEs (zlib1g, perl, libsqlite3-0, util-linux) are Debian bookworm will_not_fix/fix_deferred/no-dsa — not resolvable via apt upgrade

Resilience (app/agent.py):

  • tenacity.retry(...) on _construct_agent, retrying only on botocore.exceptions.ClientError with code AccessDeniedException (the first-boot IAM/Pod-Identity propagation race), exponential backoff (multiplier=1, max=16s), capped at 6 attempts
  • Skip AgentCore session-manager attachment when the session id is the A2A agent-card placeholder (__agent_card__) — that probe agent is never used for real requests, and the placeholder fails AgentCore's sessionId validation regex (must start with alphanumeric)

A2A SDK compatibility (app/main.py):

  • Switch A2AServer from the deprecated single shared agent= (not multi-tenant-safe; rejected outright by strands-agents 1.48's StrandsA2AExecutor when a session_manager is attached) to agent_factory=create_agent, giving each A2A context its own context-scoped agent + session manager

Testing

  • Rebuilt multi-arch (amd64 + arm64) locally with podman, verified boot + /health on both arches
  • Re-scanned with trivy: starlette, fastapi, tenacity, bedrock_agentcore, pydantic, uvicorn all show 0 vulnerabilities post-fix
  • Pushed to public.ecr.aws/z0a4o2j5/strands-agent (:latest, :v1.1.0-security)
  • Deployed to the hub cluster (peeks-hub): all 3 my-agent pods Running 1/1, 0 restarts, Rollout phase Healthy — no AccessDenied crashes, no ValueError/ValidationException crashes

Not in scope

  • Residual Debian bookworm OS-layer CVEs (documented as accepted; not fixable without a distro-version jump)
  • Platform-wide default resources/startupProbe for the agent OAM component (flagged as a follow-up, not applied here beyond the one example)

ADRs for secretless workload identity (Shape A gateway identity; OAM identity
traits; aws-service-identity/XPodIdentity/env-config; per-cluster eks_oidc_provider)
and the user-delegated token-exchange roadmap, incl. the pending agentgateway
release that ships backend.auth.oauthTokenExchange (v1.1.0 lacks it; PRs #2189/#2458).
…nt resource requests

aws-service-identity trait: replace the STS-based init wait with a distroless,
digest-pinned Chainguard kubectl 'wait --for=condition=Ready' on the PodIdentity
resource, plus a namespaced Role/RoleBinding (get/list/watch podidentities) so the
pod ServiceAccount can read it. Control-plane readiness only; the brief IAM
data-plane propagation window is handled by app-level retry.

example-agent-agentcore-memory: add CPU/memory requests (+ mem limit) so the agent
isn't CPU-starved on contended nodes (root cause of the liveness-kill crashloops).

Regenerated oam-agent-components templates.
…ctory fix

Dependency/base-image hardening:
- Pin fastapi==0.139.2, starlette==1.3.1 (fixes CVE-2025-62727, CVE-2026-48818,
  CVE-2026-54283), pydantic==2.13.4, uvicorn==0.51.0, bedrock-agentcore==1.18.1
  (previously unpinned), aws-opentelemetry-distro==0.18.0, strands-agents==1.48.0.
- Add tenacity==9.1.4 for retry-with-backoff (replaces hand-rolled loop).
- Pin Dockerfile builder (uv:0.9.30-python3.13-bookworm-slim) and final stage
  (python:3.13-slim-bookworm by digest) for supply-chain immutability.
- Remaining OS-layer CVEs (zlib1g, perl, libsqlite3-0, util-linux) are Debian
  bookworm will_not_fix/fix_deferred/no-dsa - not resolvable via apt upgrade.

Resilience:
- agent.py: tenacity retry() on _construct_agent, retrying only on botocore
  AccessDeniedException (first-boot IAM/Pod-Identity propagation race),
  exponential backoff (multiplier=1, max=16s), capped at 6 attempts.
- agent.py: skip AgentCore session-manager attachment for the A2A agent-card
  placeholder context id (__agent_card__) - that probe agent is never used for
  real requests, and the placeholder fails AgentCore's sessionId validation
  regex (must start with alphanumeric).
- main.py: switch A2AServer from the deprecated single shared agent param (not
  multi-tenant-safe, and rejected by strands-agents 1.48's StrandsA2AExecutor
  when a session_manager is attached) to the agent_factory param, giving
  each A2A context its own context-scoped agent + session_manager.

Verified: rebuilt multi-arch (amd64+arm64), re-scanned with trivy (starlette/
fastapi/tenacity/etc. all 0 vulnerabilities), pushed to
public.ecr.aws/z0a4o2j5/strands-agent (:latest, :v1.1.0-security), and
confirmed on the hub cluster - all 3 my-agent pods Running 1/1, 0 restarts,
Rollout Healthy.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant