Skip to content

feat(tools): add read-only CloudWatch tool via iron-proxy aws_auth#287

Merged
mslipper merged 7 commits into
paradigmxyz:mainfrom
0xSplits:feature/pe-7568-create-a-cloudwatch-centaur-tool
Jun 3, 2026
Merged

feat(tools): add read-only CloudWatch tool via iron-proxy aws_auth#287
mslipper merged 7 commits into
paradigmxyz:mainfrom
0xSplits:feature/pe-7568-create-a-cloudwatch-centaur-tool

Conversation

@0xdiid

@0xdiid 0xdiid commented May 29, 2026

Copy link
Copy Markdown
Contributor

What

Adds a cloudwatch infra tool mirroring the AWS CloudWatch MCP's read-only surface, backed by boto3:

  • list_log_groups, filter_log_events
  • start_query / get_query_results / stop_query (Logs Insights)
  • list_metrics, get_metric_data
  • describe_alarms, get_alarm_history

Responses are made JSON-safe (datetimes → ISO, ResponseMetadata stripped), and the boto3 clients are built lazily so tool discovery needs no credentials or network access.

Iron proxy supports AWS SigV4 signing, so credentials stay outside. This particular PR is dependent on ironsh/iron-proxy#167 to function properly, though

Changes

  • tool_managerAwsAuthSecret type + parser (access_key_id / secret_access_key / session_token refs, allowed_regions / allowed_services, hosts).
  • proxy_config — render the aws_auth transform; added to _MANAGED_TRANSFORMS.
  • iron-proxy base configs — allowlist /^x-amz-.*$/ so x-amz-target (the CloudWatch operation header) survives egress filtering.
  • cloudwatch tool — declares the aws_auth secret; signs with placeholders; region is the only real value (non-secret, read from env, defaults us-east-1).
  • kubernetes — tool-server sidecar exposes only AWS_REGION (non-secret, optional); no AWS credentials in-process.

Deploying

Store a read-only CloudWatch IAM user's keys as AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY in your secrets backend. Set AWS_REGION if your log groups aren't in us-east-1. Rebuild the API image (picks up boto3) and redeploy; confirm cloudwatch appears in GET /health/tools.

Testing

  • tools/infra/cloudwatch/test_client.py — request shaping, time-window resolution, response cleaning, error wrapping (network/boto3-free recording shim).
  • test_proxy_config.pyaws_auth parser + renderer coverage (cred sourcing, host merging, scoping).
  • test_sandbox_kubernetes_backend.py — sidecar exposes AWS_REGION and asserts AWS credentials are absent from the process.

Smoketested on our deploy as well:
Screenshot 2026-05-28 at 11 11 23 PM

@0xdiid 0xdiid force-pushed the feature/pe-7568-create-a-cloudwatch-centaur-tool branch from cb351f8 to 0441523 Compare May 29, 2026 02:00
@0xdiid 0xdiid changed the title feat(tools): add read-only CloudWatch tool feat(tools): add read-only CloudWatch tool via iron-proxy aws_auth May 29, 2026
Add a `cloudwatch` infra tool mirroring the AWS CloudWatch MCP's read-only
surface: log groups, filter log events, Logs Insights queries, metrics, and
alarms (boto3-backed, JSON-safe responses, lazy client so discovery needs no
credentials or network).

AWS auth rides iron-proxy's `aws_auth` transform rather than holding real
credentials in the tool process. SigV4 can't be swapped on the wire like a
bearer token, but iron-proxy re-signs: boto3 signs each request with throwaway
placeholder credentials, and iron-proxy reads the region/service from the
signature scope and re-signs with the real read-only IAM keys it resolves from
the secrets backend. The keys never enter the workload — the SigV4 analogue of
the `secrets` placeholder swap. (aws_auth landed in iron-proxy v0.40.0; Centaur
pins 0.42.0-rc.2, which includes it.)

- tool_manager: AwsAuthSecret type + parser (access_key_id/secret_access_key/
  session_token refs, allowed_regions/services, hosts)
- proxy_config: render the aws_auth transform; add to _MANAGED_TRANSFORMS
- iron-proxy base configs: allowlist x-amz-* so x-amz-target (the CloudWatch
  operation header) survives egress filtering
- cloudwatch tool: declare the aws_auth secret; sign with placeholders; region
  is the only real value (non-secret, read from env, defaults us-east-1)
- kubernetes: expose only AWS_REGION (non-secret, optional) to the tool-server
  sidecar — no AWS credentials in-process
- tests: cloudwatch client, aws_auth parser + renderer, sidecar (creds absent)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@0xdiid 0xdiid force-pushed the feature/pe-7568-create-a-cloudwatch-centaur-tool branch from 0441523 to 39cd278 Compare May 29, 2026 02:48
0xdiid and others added 4 commits May 29, 2026 04:20
aws_auth re-signs CloudWatch requests with the AWS SDK v4 signer, whose
signed-headers set includes the SDK's amz-sdk-request, amz-sdk-invocation-id,
and (for CloudWatch's query-JSON protocol) x-amzn-query-mode headers.
header_allowlist runs after aws_auth and was stripping them, so AWS rebuilt
the canonical request without them and rejected every call with
InvalidSignatureException.

Allow /^amz-sdk-.*$/ and /^x-amzn-.*$/ so the signed headers reach AWS. Pairs
with the /^x-amz-.*$/ allowance already added for the SigV4 headers.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…NECT fix

0.42.0-rc.4 is the first release containing ironsh/iron-proxy#167, which lets
the synthetic CONNECT through the tunnel transform-policy check so aws_auth
signs the post-MITM inner request instead of rejecting the CONNECT. Required
for the CloudWatch tool's aws_auth path.
@0xdiid 0xdiid marked this pull request as ready for review May 29, 2026 16:52
@0xdiid

0xdiid commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

@mslipper would you be able to take a look at this and make sure it is sound?

@mslipper mslipper merged commit 253a380 into paradigmxyz:main Jun 3, 2026
6 checks passed
0xdiid added a commit to 0xSplits/centaur that referenced this pull request Jun 8, 2026
…aradigmxyz#287)

* feat(tools): add read-only CloudWatch tool via iron-proxy aws_auth

Add a `cloudwatch` infra tool mirroring the AWS CloudWatch MCP's read-only
surface: log groups, filter log events, Logs Insights queries, metrics, and
alarms (boto3-backed, JSON-safe responses, lazy client so discovery needs no
credentials or network).

AWS auth rides iron-proxy's `aws_auth` transform rather than holding real
credentials in the tool process. SigV4 can't be swapped on the wire like a
bearer token, but iron-proxy re-signs: boto3 signs each request with throwaway
placeholder credentials, and iron-proxy reads the region/service from the
signature scope and re-signs with the real read-only IAM keys it resolves from
the secrets backend. The keys never enter the workload — the SigV4 analogue of
the `secrets` placeholder swap. (aws_auth landed in iron-proxy v0.40.0; Centaur
pins 0.42.0-rc.2, which includes it.)

- tool_manager: AwsAuthSecret type + parser (access_key_id/secret_access_key/
  session_token refs, allowed_regions/services, hosts)
- proxy_config: render the aws_auth transform; add to _MANAGED_TRANSFORMS
- iron-proxy base configs: allowlist x-amz-* so x-amz-target (the CloudWatch
  operation header) survives egress filtering
- cloudwatch tool: declare the aws_auth secret; sign with placeholders; region
  is the only real value (non-secret, read from env, defaults us-east-1)
- kubernetes: expose only AWS_REGION (non-secret, optional) to the tool-server
  sidecar — no AWS credentials in-process
- tests: cloudwatch client, aws_auth parser + renderer, sidecar (creds absent)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(cloudwatch): allow AWS SDK signed headers through the egress filter

aws_auth re-signs CloudWatch requests with the AWS SDK v4 signer, whose
signed-headers set includes the SDK's amz-sdk-request, amz-sdk-invocation-id,
and (for CloudWatch's query-JSON protocol) x-amzn-query-mode headers.
header_allowlist runs after aws_auth and was stripping them, so AWS rebuilt
the canonical request without them and rejected every call with
InvalidSignatureException.

Allow /^amz-sdk-.*$/ and /^x-amzn-.*$/ so the signed headers reach AWS. Pairs
with the /^x-amz-.*$/ allowance already added for the SigV4 headers.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(iron-proxy): bump base image to 0.42.0-rc.4 for the awsauth CONNECT fix

0.42.0-rc.4 is the first release containing ironsh/iron-proxy#167, which lets
the synthetic CONNECT through the tunnel transform-policy check so aws_auth
signs the post-MITM inner request instead of rejecting the CONNECT. Required
for the CloudWatch tool's aws_auth path.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0xdiid added a commit to 0xSplits/centaur that referenced this pull request Jun 8, 2026
The CloudWatch tool shipped (paradigmxyz#287) with only client.py and `_client()`, so it
works via the tool-server's `call <tool> <method>` (Python api) but is invisible
on the shim-based path (api-rs / Discord): `install_tool_shims.py` only installs
a CLI for tools that declare `[project.scripts]`, so agents there saw grafana and
vlogs but no `cloudwatch` command.

Add a Typer `cli.py` wrapping the read-only CloudWatchClient methods (log groups,
filter events, Logs Insights queries, metrics, alarms) plus the `[project.scripts]`
entry and hatch wheel packaging, mirroring the grafana/vlogs tools. Verified the
exact shim chain with `uvx --from tools/infra/cloudwatch cloudwatch --help`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

2 participants