u/Ok-Cold-3354

Genuine question first; product disclosure at the bottom. We've been running Claude / GPT agents wired into real workflows (billing, document signing, internal tooling) and ran into a problem that doesn't seem widely-discussed yet: the audit log can't tell us *which* agent session performed a key operation?

The standard setup is:

agent → tool call → AWS KMS / Vault → CloudTrail entry.

The CloudTrail entry says role X did the call. But role X is shared across every agent and every human. There's no agent_id, no session_id, no parent-human pointer. So when you need to answer "did agent_claude-7a3, spawned by alice@org at 14:22, call sign() on this key?" — you can't, from the audit alone. You can sometimes reconstruct it from app logs, but the chain of custody is brittle.

How is your team handling this? Specifically interested in: - Are you propagating agent IDs through to the KMS audit somehow? (Custom claims in JWTs? Headers passed to a sidecar? Tags?) - Have you given up and just instrumented at the framework layer? - Has your security team flagged this as a problem yet, or is it still "we'll address it later"?

Disclosure: I'm building Aegis-KMS, an open-source agent-aware KMS that records agent_id / session_id / parent on every audit row by

Design. v0.1.1 just shipped (lifecycle + crypto ops; agent-aware audit fields populate end-to-end in v0.2.0).

But I'm genuinely curious how others are solving this in the meantime — the problem space is bigger than any one product.

reddit.com
u/Ok-Cold-3354 — 14 days ago
▲ 7 r/scala

Hi r/scala — disclosure up front: I the maintainer of Aegis-KMS, an
open-source key manager we just shipped v0.1.1 of. This post is *not*
about the product, it's about the language/stack choice. The product
choice is in a different post next week.

Most "we picked Scala for X" posts age badly because they're aesthetic
arguments. The four properties we actually needed from the language
were:

  1. Total case analysis on every security decision (sealed traits +
    -Wunused, so a forgotten principal kind doesn't compile)
  2. Composable invariants without inheritance — the same KeyService
    algebra is wrapped by Authorizing, Auditing, ActorBacked
    decorators, each adding one orthogonal concern.
  3. Single-writer state with deterministic event-sourced replay
    (Pekko Typed actor + journal — the actor IS the user guardian,
    no Promise/Await dance).
  4. A clean fallback when the type system runs out (Cats Effect 3).

The full write-up with code from the actual repo is here:

https://medium.com/@sharma.b6/why-we-built-aegis-kms-in-scala-3-pekko-and-why-its-a-security-argument-not-an-aesthetic-one-5064a351fc08

Where the stack cost us:

  - Pekko version pinning hell — Tapir transitively pulls a different

pekko-stream and ManifestInfo refused to start; we had to

dependencyOverride across all artifacts.

  - sbt-dynver vs. Pekko user-guardian — the original

Promise/Await pattern hung on cold start on JDK 21 + sbt's

classloader. The fix was making the ActorSystem itself the actor

(`ActorSystem[T] <: ActorRef[T]` in Pekko Typed).

  - Scala 3 + Doobie 1.0.x had codec quirks we worked around.

GitHub: https://github.com/sharma-bhaskar/aegis-kms

v0.1.1 has 160 tests, scalafmt + scalafix clean, library tier

explicitly Pekko-free for embeddability.

Happy to take pushback in comments — especially from anyone who

considered Scala for a similar control-plane shape and went a

different way.

u/Ok-Cold-3354 — 14 days ago