Introduce cached-imds-client: cache static IMDS responses to improve robustness

I recently encountered IMDS (Instance Metadata Service) request failures with this error:

1"caller": "actor/actor.go:101",
2"error": "operation error ec2imds: GetMetadata, failed to get rate limit token, retry quota exceeded, x available, y requested

The root cause: the aws-sdk-go-v2 IMDS client exhausted its retry token bucket. The AWS SDK for Go v2 implements client-side rate limiting ("retry quotas") to prevent overwhelming services. The standard strategy works as follows:

  1. Initial attempt: Consumes no tokens, adds 1 token back on success
  2. Retry attempt: Deducts 5 tokens (10 for timeouts)
  3. If tokens available: Retry proceeds
  4. If tokens exhausted: Returns QuotaExceededError
  5. On success: Adds 1 token back (max capacity: 500)

When IMDS requests time out or retry frequently, they drain the token bucket quickly. But what causes the timeouts? Without explicit timeout logs, the IMDS service was likely reachable, suggesting throttling as the culprit.

IMDS runs locally on every EC2 instance at 169.254.169.254 (or [fd00:ec2::254]) with a 1,024 packets-per-second (PPS) throttle per ENI. This limit is shared across IMDS requests, Route 53 Resolver DNS queries, and Amazon Time Service (NTP) requests. Monitor throttling with ethtool -S ens5 | grep linklocal_allowance_exceeded. See Understanding linklocal_exceeded metric for details.

To address this, I created cached-imds-client—a drop-in replacement for aws-sdk-go-v2/feature/ec2/imds that caches immutable metadata values throughout a boot cycle.