diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 64934e59e..4326dd0b0 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -65,7 +65,7 @@ valuable, listed roughly from most to least severe: - **Snapshot integrity and confidentiality**: reading another actor's suspend/resume snapshot, or resuming an actor from a tampered snapshot. - **Routing**: traffic intended for one actor delivered to another. -- **Identity**: forging session identity (for example session JWTs). +- **Identity**: forging actor identity (for example actor JWTs). - **Control-plane authentication and authorization bypass**: reaching `ateapi` RPCs without valid credentials (mTLS or JWT auth modes), misusing workerpool client certificates, or acting beyond what valid diff --git a/README.md b/README.md index 1cedd0697..91729720d 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,11 @@ agents, but rather a system for running them at scale. [![Agent Substrate Demo](https://img.youtube.com/vi/ZEzkCFJkzjY/hq1.jpg)](https://www.youtube.com/watch?v=ZEzkCFJkzjY) -*Watch the Agent Substrate cluster multiplex ~250 stateful actor sessions across just 8 physical pods.* +*Watch the Agent Substrate cluster multiplex ~250 stateful actors across just 8 physical pods.* This demo highlights the core developer experience and "Agentic Infrastructure" capabilities of Substrate: -1. **Instant Session Teleport:** High-performance suspend and resume of actors onto any available worker in the pool with sub-second activation. +1. **Instant Actor Teleport:** High-performance suspend and resume of actors onto any available worker in the pool with sub-second activation. 2. **State Persistence:** Persistent working memory (volatile RAM) and filesystem state preserved perfectly across hibernation cycles via full-state snapshots. 3. **Agent Swarm Multiplexing:** Demonstrates 30x+ oversubscription by "juggling" a large registry of stateful actors onto a small pool of shared physical pods. @@ -50,7 +50,7 @@ For more videos and walkthroughs, visit our YouTube channel: **[agent-substrate] Agent Substrate is designed to be **framework and agent harness agnostic**. Because it manages standard OCI containers at the kernel level (via gVisor), it can host agents built on any stack. -* **Agent Development Kit (ADK):** Native support for ADK-compatible session identity and persistent working memory. +* **Agent Development Kit (ADK):** Native support for ADK-compatible actor identity and persistent working memory. * **LangChain:** Ideal execution environment for long-running, stateful LangChain agents and sandboxed tool-calling. * **Claude Code & CodeX:** Support for high-density, stateful coding environments that preserve terminal and filesystem state across sessions. * **Model Context Protocol (MCP):** Deploy secure, sandboxed MCP servers as Substrate Actors to provide durable tools for any LLM. diff --git a/benchmarking/locust/common/ateapi_pb2.py b/benchmarking/locust/common/ateapi_pb2.py index 8363ccf5c..bfa6d5e49 100644 --- a/benchmarking/locust/common/ateapi_pb2.py +++ b/benchmarking/locust/common/ateapi_pb2.py @@ -39,7 +39,7 @@ from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x61teapi.proto\x12\x06\x61teapi\x1a\x1fgoogle/protobuf/timestamp.proto\"3\n\x14\x45xternalSnapshotInfo\x12\x1b\n\x13snapshot_uri_prefix\x18\x01 \x01(\t\"S\n\x11LocalSnapshotInfo\x12\x17\n\x0fsnapshot_prefix\x18\x01 \x01(\t\x12%\n\x1dnode_vms_with_local_snapshots\x18\x02 \x03(\t\"\x80\x01\n\x0cSnapshotInfo\x12\x30\n\x08\x65xternal\x18\x02 \x01(\x0b\x32\x1c.ateapi.ExternalSnapshotInfoH\x00\x12*\n\x05local\x18\x03 \x01(\x0b\x32\x19.ateapi.LocalSnapshotInfoH\x00\x42\x06\n\x04\x64\x61taJ\x04\x08\x01\x10\x02R\x04type\"w\n\x08Selector\x12\x37\n\x0cmatch_labels\x18\x01 \x03(\x0b\x32!.ateapi.Selector.MatchLabelsEntry\x1a\x32\n\x10MatchLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xb2\x01\n\x10ResourceMetadata\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0b\n\x03uid\x18\x03 \x01(\t\x12\x0f\n\x07version\x18\x04 \x01(\x03\x12/\n\x0b\x63reate_time\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12/\n\x0bupdate_time\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xc5\x04\n\x05\x41\x63tor\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12 \n\x18\x61\x63tor_template_namespace\x18\x02 \x01(\t\x12\x1b\n\x13\x61\x63tor_template_name\x18\x03 \x01(\t\x12$\n\x06status\x18\x04 \x01(\x0e\x32\x14.ateapi.Actor.Status\x12\x1b\n\x13\x61teom_pod_namespace\x18\x05 \x01(\t\x12\x16\n\x0e\x61teom_pod_name\x18\x06 \x01(\t\x12\x14\n\x0c\x61teom_pod_ip\x18\x07 \x01(\t\x12\x1c\n\x14in_progress_snapshot\x18\x08 \x01(\t\x12\x15\n\rateom_pod_uid\x18\t \x01(\t\x12\x32\n\x14latest_snapshot_info\x18\n \x01(\x0b\x32\x14.ateapi.SnapshotInfo\x12)\n\x0fworker_selector\x18\x0b \x01(\x0b\x32\x10.ateapi.Selector\x12\x18\n\x10worker_pool_name\x18\x0c \x01(\t\"\xb1\x01\n\x06Status\x12\x16\n\x12STATUS_UNSPECIFIED\x10\x00\x12\x13\n\x0fSTATUS_RESUMING\x10\x01\x12\x12\n\x0eSTATUS_RUNNING\x10\x02\x12\x15\n\x11STATUS_SUSPENDING\x10\x03\x12\x14\n\x10STATUS_SUSPENDED\x10\x04\x12\x12\n\x0eSTATUS_PAUSING\x10\x05\x12\x11\n\rSTATUS_PAUSED\x10\x06\x12\x12\n\x0eSTATUS_CRASHED\x10\x07\"6\n\x08\x41tespace\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\"+\n\tObjectRef\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\";\n\x15\x43reateAtespaceRequest\x12\"\n\x08\x61tespace\x18\x01 \x01(\x0b\x32\x10.ateapi.Atespace\"9\n\x12GetAtespaceRequest\x12#\n\x08\x61tespace\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"\x16\n\x14ListAtespacesRequest\"<\n\x15ListAtespacesResponse\x12#\n\tatespaces\x18\x01 \x03(\x0b\x32\x10.ateapi.Atespace\"<\n\x15\x44\x65leteAtespaceRequest\x12#\n\x08\x61tespace\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"3\n\x0fGetActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"2\n\x12\x43reateActorRequest\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"a\n\x12UpdateActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12)\n\x0fworker_selector\x18\x02 \x01(\x0b\x32\x10.ateapi.Selector\"3\n\x13UpdateActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"7\n\x13SuspendActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"4\n\x14SuspendActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"5\n\x11PauseActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"2\n\x12PauseActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"D\n\x12ResumeActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x0c\n\x04\x62oot\x18\x02 \x01(\x08\"3\n\x13ResumeActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"6\n\x12\x44\x65leteActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"\x14\n\x12ListWorkersRequest\"6\n\x13ListWorkersResponse\x12\x1f\n\x07workers\x18\x01 \x03(\x0b\x32\x0e.ateapi.Worker\"L\n\x11ListActorsRequest\x12\x11\n\tpage_size\x18\x01 \x01(\x05\x12\x12\n\npage_token\x18\x02 \x01(\t\x12\x10\n\x08\x61tespace\x18\x03 \x01(\t\"L\n\x12ListActorsResponse\x12\x1d\n\x06\x61\x63tors\x18\x01 \x03(\x0b\x32\r.ateapi.Actor\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"\xad\x02\n\x06Worker\x12\x18\n\x10worker_namespace\x18\x01 \x01(\t\x12\x13\n\x0bworker_pool\x18\x02 \x01(\t\x12\x12\n\nworker_pod\x18\x03 \x01(\t\x12&\n\nassignment\x18\x04 \x01(\x0b\x32\x12.ateapi.Assignment\x12\n\n\x02ip\x18\x05 \x01(\t\x12\x0f\n\x07version\x18\x06 \x01(\x03\x12\x16\n\x0eworker_pod_uid\x18\x07 \x01(\t\x12\x11\n\tnode_name\x18\x08 \x01(\t\x12\x15\n\rsandbox_class\x18\t \x01(\t\x12*\n\x06labels\x18\n \x03(\x0b\x32\x1a.ateapi.Worker.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"g\n\nAssignment\x12\x37\n\x0e\x61\x63tor_template\x18\x01 \x01(\x0b\x32\x1f.ateapi.KubeNamespacedObjectRef\x12 \n\x05\x61\x63tor\x18\x02 \x01(\x0b\x32\x11.ateapi.ObjectRef\":\n\x17KubeNamespacedObjectRef\x12\x11\n\tnamespace\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"\x13\n\x11\x44\x65\x62ugClearRequest\"\x14\n\x12\x44\x65\x62ugClearResponse\"W\n\x0eMintJWTRequest\x12\x10\n\x08\x61udience\x18\x01 \x03(\t\x12\x0e\n\x06\x61pp_id\x18\x02 \x01(\t\x12\x0f\n\x07user_id\x18\x03 \x01(\t\x12\x12\n\nsession_id\x18\x04 \x01(\t\"&\n\x0fMintJWTResponse\x12\x13\n\x0bsession_jwt\x18\x01 \x01(\t\"k\n\x0fMintCertRequest\x12\x0e\n\x06\x61pp_id\x18\x01 \x01(\t\x12\x0f\n\x07user_id\x18\x02 \x01(\t\x12\x12\n\nsession_id\x18\x03 \x01(\t\x12#\n\x1b\x63\x65rtificate_signing_request\x18\x04 \x01(\x0c\"0\n\x10MintCertResponse\x12\x1c\n\x14session_certificates\x18\x01 \x03(\x0c\x32\x89\x07\n\x07\x43ontrol\x12\x34\n\x08GetActor\x12\x17.ateapi.GetActorRequest\x1a\r.ateapi.Actor\"\x00\x12:\n\x0b\x43reateActor\x12\x1a.ateapi.CreateActorRequest\x1a\r.ateapi.Actor\"\x00\x12H\n\x0bUpdateActor\x12\x1a.ateapi.UpdateActorRequest\x1a\x1b.ateapi.UpdateActorResponse\"\x00\x12K\n\x0cSuspendActor\x12\x1b.ateapi.SuspendActorRequest\x1a\x1c.ateapi.SuspendActorResponse\"\x00\x12\x45\n\nPauseActor\x12\x19.ateapi.PauseActorRequest\x1a\x1a.ateapi.PauseActorResponse\"\x00\x12H\n\x0bResumeActor\x12\x1a.ateapi.ResumeActorRequest\x1a\x1b.ateapi.ResumeActorResponse\"\x00\x12:\n\x0b\x44\x65leteActor\x12\x1a.ateapi.DeleteActorRequest\x1a\r.ateapi.Actor\"\x00\x12H\n\x0bListWorkers\x12\x1a.ateapi.ListWorkersRequest\x1a\x1b.ateapi.ListWorkersResponse\"\x00\x12\x45\n\nListActors\x12\x19.ateapi.ListActorsRequest\x1a\x1a.ateapi.ListActorsResponse\"\x00\x12\x43\n\x0e\x43reateAtespace\x12\x1d.ateapi.CreateAtespaceRequest\x1a\x10.ateapi.Atespace\"\x00\x12=\n\x0bGetAtespace\x12\x1a.ateapi.GetAtespaceRequest\x1a\x10.ateapi.Atespace\"\x00\x12N\n\rListAtespaces\x12\x1c.ateapi.ListAtespacesRequest\x1a\x1d.ateapi.ListAtespacesResponse\"\x00\x12\x43\n\x0e\x44\x65leteAtespace\x12\x1d.ateapi.DeleteAtespaceRequest\x1a\x10.ateapi.Atespace\"\x00\x32N\n\x05\x44\x65\x62ug\x12\x45\n\nDebugClear\x12\x19.ateapi.DebugClearRequest\x1a\x1a.ateapi.DebugClearResponse\"\x00\x32\x8c\x01\n\x0fSessionIdentity\x12:\n\x07MintJWT\x12\x16.ateapi.MintJWTRequest\x1a\x17.ateapi.MintJWTResponse\x12=\n\x08MintCert\x12\x17.ateapi.MintCertRequest\x1a\x18.ateapi.MintCertResponseB9Z7github.com/agent-substrate/substrate/pkg/proto/ateapipbb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x61teapi.proto\x12\x06\x61teapi\x1a\x1fgoogle/protobuf/timestamp.proto\"3\n\x14\x45xternalSnapshotInfo\x12\x1b\n\x13snapshot_uri_prefix\x18\x01 \x01(\t\"S\n\x11LocalSnapshotInfo\x12\x17\n\x0fsnapshot_prefix\x18\x01 \x01(\t\x12%\n\x1dnode_vms_with_local_snapshots\x18\x02 \x03(\t\"\x80\x01\n\x0cSnapshotInfo\x12\x30\n\x08\x65xternal\x18\x02 \x01(\x0b\x32\x1c.ateapi.ExternalSnapshotInfoH\x00\x12*\n\x05local\x18\x03 \x01(\x0b\x32\x19.ateapi.LocalSnapshotInfoH\x00\x42\x06\n\x04\x64\x61taJ\x04\x08\x01\x10\x02R\x04type\"w\n\x08Selector\x12\x37\n\x0cmatch_labels\x18\x01 \x03(\x0b\x32!.ateapi.Selector.MatchLabelsEntry\x1a\x32\n\x10MatchLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xb2\x01\n\x10ResourceMetadata\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0b\n\x03uid\x18\x03 \x01(\t\x12\x0f\n\x07version\x18\x04 \x01(\x03\x12/\n\x0b\x63reate_time\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12/\n\x0bupdate_time\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xbf\x01\n\x0e\x45xternalVolume\x12\x17\n\x0f\x61\x63tor_volume_id\x18\x01 \x01(\t\x12\x19\n\x11storage_volume_id\x18\x02 \x01(\t\x12\x13\n\x0bvolume_type\x18\x03 \x01(\t\x12-\n\x06status\x18\x04 \x01(\x0e\x32\x1d.ateapi.ExternalVolume.Status\"5\n\x06Status\x12\x10\n\x0cPROVISIONING\x10\x00\x12\x0b\n\x07\x43REATED\x10\x01\x12\x0c\n\x08\x44\x45LETING\x10\x02\"\xf4\x04\n\x05\x41\x63tor\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12 \n\x18\x61\x63tor_template_namespace\x18\x02 \x01(\t\x12\x1b\n\x13\x61\x63tor_template_name\x18\x03 \x01(\t\x12$\n\x06status\x18\x04 \x01(\x0e\x32\x14.ateapi.Actor.Status\x12\x1b\n\x13\x61teom_pod_namespace\x18\x05 \x01(\t\x12\x16\n\x0e\x61teom_pod_name\x18\x06 \x01(\t\x12\x14\n\x0c\x61teom_pod_ip\x18\x07 \x01(\t\x12\x1c\n\x14in_progress_snapshot\x18\x08 \x01(\t\x12\x15\n\rateom_pod_uid\x18\t \x01(\t\x12\x32\n\x14latest_snapshot_info\x18\n \x01(\x0b\x32\x14.ateapi.SnapshotInfo\x12)\n\x0fworker_selector\x18\x0b \x01(\x0b\x32\x10.ateapi.Selector\x12\x18\n\x10worker_pool_name\x18\x0c \x01(\t\x12-\n\ractor_volumes\x18\x10 \x03(\x0b\x32\x16.ateapi.ExternalVolume\"\xb1\x01\n\x06Status\x12\x16\n\x12STATUS_UNSPECIFIED\x10\x00\x12\x13\n\x0fSTATUS_RESUMING\x10\x01\x12\x12\n\x0eSTATUS_RUNNING\x10\x02\x12\x15\n\x11STATUS_SUSPENDING\x10\x03\x12\x14\n\x10STATUS_SUSPENDED\x10\x04\x12\x12\n\x0eSTATUS_PAUSING\x10\x05\x12\x11\n\rSTATUS_PAUSED\x10\x06\x12\x12\n\x0eSTATUS_CRASHED\x10\x07\"6\n\x08\x41tespace\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\"+\n\tObjectRef\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\";\n\x15\x43reateAtespaceRequest\x12\"\n\x08\x61tespace\x18\x01 \x01(\x0b\x32\x10.ateapi.Atespace\"9\n\x12GetAtespaceRequest\x12#\n\x08\x61tespace\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"=\n\x14ListAtespacesRequest\x12\x11\n\tpage_size\x18\x01 \x01(\x05\x12\x12\n\npage_token\x18\x02 \x01(\t\"U\n\x15ListAtespacesResponse\x12#\n\tatespaces\x18\x01 \x03(\x0b\x32\x10.ateapi.Atespace\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"<\n\x15\x44\x65leteAtespaceRequest\x12#\n\x08\x61tespace\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"3\n\x0fGetActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"2\n\x12\x43reateActorRequest\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"a\n\x12UpdateActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12)\n\x0fworker_selector\x18\x02 \x01(\x0b\x32\x10.ateapi.Selector\"3\n\x13UpdateActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"7\n\x13SuspendActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"4\n\x14SuspendActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"5\n\x11PauseActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"2\n\x12PauseActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"D\n\x12ResumeActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x0c\n\x04\x62oot\x18\x02 \x01(\x08\"3\n\x13ResumeActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"6\n\x12\x44\x65leteActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\";\n\x12ListWorkersRequest\x12\x11\n\tpage_size\x18\x01 \x01(\x05\x12\x12\n\npage_token\x18\x02 \x01(\t\"O\n\x13ListWorkersResponse\x12\x1f\n\x07workers\x18\x01 \x03(\x0b\x32\x0e.ateapi.Worker\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"L\n\x11ListActorsRequest\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\"L\n\x12ListActorsResponse\x12\x1d\n\x06\x61\x63tors\x18\x01 \x03(\x0b\x32\r.ateapi.Actor\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"\x98\x03\n\x06Worker\x12\x18\n\x10worker_namespace\x18\x01 \x01(\t\x12\x13\n\x0bworker_pool\x18\x02 \x01(\t\x12\x12\n\nworker_pod\x18\x03 \x01(\t\x12&\n\nassignment\x18\x04 \x01(\x0b\x32\x12.ateapi.Assignment\x12\n\n\x02ip\x18\x05 \x01(\t\x12\x0f\n\x07version\x18\x06 \x01(\x03\x12\x16\n\x0eworker_pod_uid\x18\x07 \x01(\t\x12\x11\n\tnode_name\x18\x08 \x01(\t\x12\x15\n\rsandbox_class\x18\t \x01(\t\x12*\n\x06labels\x18\n \x03(\x0b\x32\x1a.ateapi.Worker.LabelsEntry\x12#\n\x05state\x18\x0b \x01(\x0e\x32\x14.ateapi.Worker.State\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"D\n\x05State\x12\x15\n\x11STATE_UNSPECIFIED\x10\x00\x12\x10\n\x0cSTATE_ACTIVE\x10\x01\x12\x12\n\x0eSTATE_DRAINING\x10\x02\"g\n\nAssignment\x12\x37\n\x0e\x61\x63tor_template\x18\x01 \x01(\x0b\x32\x1f.ateapi.KubeNamespacedObjectRef\x12 \n\x05\x61\x63tor\x18\x02 \x01(\x0b\x32\x11.ateapi.ObjectRef\":\n\x17KubeNamespacedObjectRef\x12\x11\n\tnamespace\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"\x13\n\x11\x44\x65\x62ugClearRequest\"\x14\n\x12\x44\x65\x62ugClearResponse\"U\n\x0eMintJWTRequest\x12\x10\n\x08\x61udience\x18\x01 \x03(\t\x12\x0e\n\x06\x61pp_id\x18\x02 \x01(\t\x12\x0f\n\x07user_id\x18\x03 \x01(\t\x12\x10\n\x08\x61\x63tor_id\x18\x04 \x01(\t\"$\n\x0fMintJWTResponse\x12\x11\n\tactor_jwt\x18\x01 \x01(\t\"i\n\x0fMintCertRequest\x12\x0e\n\x06\x61pp_id\x18\x01 \x01(\t\x12\x0f\n\x07user_id\x18\x02 \x01(\t\x12\x10\n\x08\x61\x63tor_id\x18\x03 \x01(\t\x12#\n\x1b\x63\x65rtificate_signing_request\x18\x04 \x01(\x0c\".\n\x10MintCertResponse\x12\x1a\n\x12\x61\x63tor_certificates\x18\x01 \x03(\x0c\x32\x89\x07\n\x07\x43ontrol\x12\x34\n\x08GetActor\x12\x17.ateapi.GetActorRequest\x1a\r.ateapi.Actor\"\x00\x12:\n\x0b\x43reateActor\x12\x1a.ateapi.CreateActorRequest\x1a\r.ateapi.Actor\"\x00\x12H\n\x0bUpdateActor\x12\x1a.ateapi.UpdateActorRequest\x1a\x1b.ateapi.UpdateActorResponse\"\x00\x12K\n\x0cSuspendActor\x12\x1b.ateapi.SuspendActorRequest\x1a\x1c.ateapi.SuspendActorResponse\"\x00\x12\x45\n\nPauseActor\x12\x19.ateapi.PauseActorRequest\x1a\x1a.ateapi.PauseActorResponse\"\x00\x12H\n\x0bResumeActor\x12\x1a.ateapi.ResumeActorRequest\x1a\x1b.ateapi.ResumeActorResponse\"\x00\x12:\n\x0b\x44\x65leteActor\x12\x1a.ateapi.DeleteActorRequest\x1a\r.ateapi.Actor\"\x00\x12H\n\x0bListWorkers\x12\x1a.ateapi.ListWorkersRequest\x1a\x1b.ateapi.ListWorkersResponse\"\x00\x12\x45\n\nListActors\x12\x19.ateapi.ListActorsRequest\x1a\x1a.ateapi.ListActorsResponse\"\x00\x12\x43\n\x0e\x43reateAtespace\x12\x1d.ateapi.CreateAtespaceRequest\x1a\x10.ateapi.Atespace\"\x00\x12=\n\x0bGetAtespace\x12\x1a.ateapi.GetAtespaceRequest\x1a\x10.ateapi.Atespace\"\x00\x12N\n\rListAtespaces\x12\x1c.ateapi.ListAtespacesRequest\x1a\x1d.ateapi.ListAtespacesResponse\"\x00\x12\x43\n\x0e\x44\x65leteAtespace\x12\x1d.ateapi.DeleteAtespaceRequest\x1a\x10.ateapi.Atespace\"\x00\x32N\n\x05\x44\x65\x62ug\x12\x45\n\nDebugClear\x12\x19.ateapi.DebugClearRequest\x1a\x1a.ateapi.DebugClearResponse\"\x00\x32\x8a\x01\n\rActorIdentity\x12:\n\x07MintJWT\x12\x16.ateapi.MintJWTRequest\x1a\x17.ateapi.MintJWTResponse\x12=\n\x08MintCert\x12\x17.ateapi.MintCertRequest\x1a\x18.ateapi.MintCertResponseB9Z7github.com/agent-substrate/substrate/pkg/proto/ateapipbb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -63,78 +63,84 @@ _globals['_SELECTOR_MATCHLABELSENTRY']._serialized_end=445 _globals['_RESOURCEMETADATA']._serialized_start=448 _globals['_RESOURCEMETADATA']._serialized_end=626 - _globals['_ACTOR']._serialized_start=629 - _globals['_ACTOR']._serialized_end=1210 - _globals['_ACTOR_STATUS']._serialized_start=1033 - _globals['_ACTOR_STATUS']._serialized_end=1210 - _globals['_ATESPACE']._serialized_start=1212 - _globals['_ATESPACE']._serialized_end=1266 - _globals['_OBJECTREF']._serialized_start=1268 - _globals['_OBJECTREF']._serialized_end=1311 - _globals['_CREATEATESPACEREQUEST']._serialized_start=1313 - _globals['_CREATEATESPACEREQUEST']._serialized_end=1372 - _globals['_GETATESPACEREQUEST']._serialized_start=1374 - _globals['_GETATESPACEREQUEST']._serialized_end=1431 - _globals['_LISTATESPACESREQUEST']._serialized_start=1433 - _globals['_LISTATESPACESREQUEST']._serialized_end=1455 - _globals['_LISTATESPACESRESPONSE']._serialized_start=1457 - _globals['_LISTATESPACESRESPONSE']._serialized_end=1517 - _globals['_DELETEATESPACEREQUEST']._serialized_start=1519 - _globals['_DELETEATESPACEREQUEST']._serialized_end=1579 - _globals['_GETACTORREQUEST']._serialized_start=1581 - _globals['_GETACTORREQUEST']._serialized_end=1632 - _globals['_CREATEACTORREQUEST']._serialized_start=1634 - _globals['_CREATEACTORREQUEST']._serialized_end=1684 - _globals['_UPDATEACTORREQUEST']._serialized_start=1686 - _globals['_UPDATEACTORREQUEST']._serialized_end=1783 - _globals['_UPDATEACTORRESPONSE']._serialized_start=1785 - _globals['_UPDATEACTORRESPONSE']._serialized_end=1836 - _globals['_SUSPENDACTORREQUEST']._serialized_start=1838 - _globals['_SUSPENDACTORREQUEST']._serialized_end=1893 - _globals['_SUSPENDACTORRESPONSE']._serialized_start=1895 - _globals['_SUSPENDACTORRESPONSE']._serialized_end=1947 - _globals['_PAUSEACTORREQUEST']._serialized_start=1949 - _globals['_PAUSEACTORREQUEST']._serialized_end=2002 - _globals['_PAUSEACTORRESPONSE']._serialized_start=2004 - _globals['_PAUSEACTORRESPONSE']._serialized_end=2054 - _globals['_RESUMEACTORREQUEST']._serialized_start=2056 - _globals['_RESUMEACTORREQUEST']._serialized_end=2124 - _globals['_RESUMEACTORRESPONSE']._serialized_start=2126 - _globals['_RESUMEACTORRESPONSE']._serialized_end=2177 - _globals['_DELETEACTORREQUEST']._serialized_start=2179 - _globals['_DELETEACTORREQUEST']._serialized_end=2233 - _globals['_LISTWORKERSREQUEST']._serialized_start=2235 - _globals['_LISTWORKERSREQUEST']._serialized_end=2255 - _globals['_LISTWORKERSRESPONSE']._serialized_start=2257 - _globals['_LISTWORKERSRESPONSE']._serialized_end=2311 - _globals['_LISTACTORSREQUEST']._serialized_start=2313 - _globals['_LISTACTORSREQUEST']._serialized_end=2389 - _globals['_LISTACTORSRESPONSE']._serialized_start=2391 - _globals['_LISTACTORSRESPONSE']._serialized_end=2467 - _globals['_WORKER']._serialized_start=2470 - _globals['_WORKER']._serialized_end=2771 - _globals['_WORKER_LABELSENTRY']._serialized_start=2726 - _globals['_WORKER_LABELSENTRY']._serialized_end=2771 - _globals['_ASSIGNMENT']._serialized_start=2773 - _globals['_ASSIGNMENT']._serialized_end=2876 - _globals['_KUBENAMESPACEDOBJECTREF']._serialized_start=2878 - _globals['_KUBENAMESPACEDOBJECTREF']._serialized_end=2936 - _globals['_DEBUGCLEARREQUEST']._serialized_start=2938 - _globals['_DEBUGCLEARREQUEST']._serialized_end=2957 - _globals['_DEBUGCLEARRESPONSE']._serialized_start=2959 - _globals['_DEBUGCLEARRESPONSE']._serialized_end=2979 - _globals['_MINTJWTREQUEST']._serialized_start=2981 - _globals['_MINTJWTREQUEST']._serialized_end=3068 - _globals['_MINTJWTRESPONSE']._serialized_start=3070 - _globals['_MINTJWTRESPONSE']._serialized_end=3108 - _globals['_MINTCERTREQUEST']._serialized_start=3110 - _globals['_MINTCERTREQUEST']._serialized_end=3217 - _globals['_MINTCERTRESPONSE']._serialized_start=3219 - _globals['_MINTCERTRESPONSE']._serialized_end=3267 - _globals['_CONTROL']._serialized_start=3270 - _globals['_CONTROL']._serialized_end=4175 - _globals['_DEBUG']._serialized_start=4177 - _globals['_DEBUG']._serialized_end=4255 - _globals['_SESSIONIDENTITY']._serialized_start=4258 - _globals['_SESSIONIDENTITY']._serialized_end=4398 + _globals['_EXTERNALVOLUME']._serialized_start=629 + _globals['_EXTERNALVOLUME']._serialized_end=820 + _globals['_EXTERNALVOLUME_STATUS']._serialized_start=767 + _globals['_EXTERNALVOLUME_STATUS']._serialized_end=820 + _globals['_ACTOR']._serialized_start=823 + _globals['_ACTOR']._serialized_end=1451 + _globals['_ACTOR_STATUS']._serialized_start=1274 + _globals['_ACTOR_STATUS']._serialized_end=1451 + _globals['_ATESPACE']._serialized_start=1453 + _globals['_ATESPACE']._serialized_end=1507 + _globals['_OBJECTREF']._serialized_start=1509 + _globals['_OBJECTREF']._serialized_end=1552 + _globals['_CREATEATESPACEREQUEST']._serialized_start=1554 + _globals['_CREATEATESPACEREQUEST']._serialized_end=1613 + _globals['_GETATESPACEREQUEST']._serialized_start=1615 + _globals['_GETATESPACEREQUEST']._serialized_end=1672 + _globals['_LISTATESPACESREQUEST']._serialized_start=1674 + _globals['_LISTATESPACESREQUEST']._serialized_end=1735 + _globals['_LISTATESPACESRESPONSE']._serialized_start=1737 + _globals['_LISTATESPACESRESPONSE']._serialized_end=1822 + _globals['_DELETEATESPACEREQUEST']._serialized_start=1824 + _globals['_DELETEATESPACEREQUEST']._serialized_end=1884 + _globals['_GETACTORREQUEST']._serialized_start=1886 + _globals['_GETACTORREQUEST']._serialized_end=1937 + _globals['_CREATEACTORREQUEST']._serialized_start=1939 + _globals['_CREATEACTORREQUEST']._serialized_end=1989 + _globals['_UPDATEACTORREQUEST']._serialized_start=1991 + _globals['_UPDATEACTORREQUEST']._serialized_end=2088 + _globals['_UPDATEACTORRESPONSE']._serialized_start=2090 + _globals['_UPDATEACTORRESPONSE']._serialized_end=2141 + _globals['_SUSPENDACTORREQUEST']._serialized_start=2143 + _globals['_SUSPENDACTORREQUEST']._serialized_end=2198 + _globals['_SUSPENDACTORRESPONSE']._serialized_start=2200 + _globals['_SUSPENDACTORRESPONSE']._serialized_end=2252 + _globals['_PAUSEACTORREQUEST']._serialized_start=2254 + _globals['_PAUSEACTORREQUEST']._serialized_end=2307 + _globals['_PAUSEACTORRESPONSE']._serialized_start=2309 + _globals['_PAUSEACTORRESPONSE']._serialized_end=2359 + _globals['_RESUMEACTORREQUEST']._serialized_start=2361 + _globals['_RESUMEACTORREQUEST']._serialized_end=2429 + _globals['_RESUMEACTORRESPONSE']._serialized_start=2431 + _globals['_RESUMEACTORRESPONSE']._serialized_end=2482 + _globals['_DELETEACTORREQUEST']._serialized_start=2484 + _globals['_DELETEACTORREQUEST']._serialized_end=2538 + _globals['_LISTWORKERSREQUEST']._serialized_start=2540 + _globals['_LISTWORKERSREQUEST']._serialized_end=2599 + _globals['_LISTWORKERSRESPONSE']._serialized_start=2601 + _globals['_LISTWORKERSRESPONSE']._serialized_end=2680 + _globals['_LISTACTORSREQUEST']._serialized_start=2682 + _globals['_LISTACTORSREQUEST']._serialized_end=2758 + _globals['_LISTACTORSRESPONSE']._serialized_start=2760 + _globals['_LISTACTORSRESPONSE']._serialized_end=2836 + _globals['_WORKER']._serialized_start=2839 + _globals['_WORKER']._serialized_end=3247 + _globals['_WORKER_LABELSENTRY']._serialized_start=3132 + _globals['_WORKER_LABELSENTRY']._serialized_end=3177 + _globals['_WORKER_STATE']._serialized_start=3179 + _globals['_WORKER_STATE']._serialized_end=3247 + _globals['_ASSIGNMENT']._serialized_start=3249 + _globals['_ASSIGNMENT']._serialized_end=3352 + _globals['_KUBENAMESPACEDOBJECTREF']._serialized_start=3354 + _globals['_KUBENAMESPACEDOBJECTREF']._serialized_end=3412 + _globals['_DEBUGCLEARREQUEST']._serialized_start=3414 + _globals['_DEBUGCLEARREQUEST']._serialized_end=3433 + _globals['_DEBUGCLEARRESPONSE']._serialized_start=3435 + _globals['_DEBUGCLEARRESPONSE']._serialized_end=3455 + _globals['_MINTJWTREQUEST']._serialized_start=3457 + _globals['_MINTJWTREQUEST']._serialized_end=3542 + _globals['_MINTJWTRESPONSE']._serialized_start=3544 + _globals['_MINTJWTRESPONSE']._serialized_end=3580 + _globals['_MINTCERTREQUEST']._serialized_start=3582 + _globals['_MINTCERTREQUEST']._serialized_end=3687 + _globals['_MINTCERTRESPONSE']._serialized_start=3689 + _globals['_MINTCERTRESPONSE']._serialized_end=3735 + _globals['_CONTROL']._serialized_start=3738 + _globals['_CONTROL']._serialized_end=4643 + _globals['_DEBUG']._serialized_start=4645 + _globals['_DEBUG']._serialized_end=4723 + _globals['_ACTORIDENTITY']._serialized_start=4726 + _globals['_ACTORIDENTITY']._serialized_end=4864 # @@protoc_insertion_point(module_scope) diff --git a/benchmarking/locust/common/ateapi_pb2_grpc.py b/benchmarking/locust/common/ateapi_pb2_grpc.py index ba4dc5919..8ded3fa82 100644 --- a/benchmarking/locust/common/ateapi_pb2_grpc.py +++ b/benchmarking/locust/common/ateapi_pb2_grpc.py @@ -170,14 +170,14 @@ def DeleteActor(self, request, context): raise NotImplementedError('Method not implemented!') def ListWorkers(self, request, context): - """List all workers currently reflected in redis. + """List Workers. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def ListActors(self, request, context): - """List all actors currently reflected in redis. + """List Actors. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -198,7 +198,7 @@ def GetAtespace(self, request, context): raise NotImplementedError('Method not implemented!') def ListAtespaces(self, request, context): - """List all Atespaces. + """List Atespaces. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -722,13 +722,13 @@ def DebugClear(request, _registered_method=True) -class SessionIdentityStub: - """SessionIdentity allows substrate workloads to exchange their +class ActorIdentityStub: + """ActorIdentity allows substrate workloads to exchange their infrastructure-level credentials (k8s service account token, etc.) for a - substrate session-level credential. A given substrate session might migrate + substrate actor-level credential. A given substrate actor might migrate between many different physical workers over the course of its lifecycle, - whereas the session credential's identity will be stable for the life of the - session. + whereas the actor credential's identity will be stable for the life of the + actor. This service requires authentication. You can authenticate with a Kubernetes service account token in an `Authorization: Bearer` header, or you can @@ -737,8 +737,8 @@ class SessionIdentityStub: upstream, but we will provide a polyfill based on Pod Certificates). The broker will check that the service credentials you authenticated with - belong to a Pod that is currently mapped to the requested session in the - session database. + belong to a Pod that is currently mapped to the requested actor in the + actor database. """ def __init__(self, channel): @@ -748,24 +748,24 @@ def __init__(self, channel): channel: A grpc.Channel. """ self.MintJWT = channel.unary_unary( - '/ateapi.SessionIdentity/MintJWT', + '/ateapi.ActorIdentity/MintJWT', request_serializer=ateapi__pb2.MintJWTRequest.SerializeToString, response_deserializer=ateapi__pb2.MintJWTResponse.FromString, _registered_method=True) self.MintCert = channel.unary_unary( - '/ateapi.SessionIdentity/MintCert', + '/ateapi.ActorIdentity/MintCert', request_serializer=ateapi__pb2.MintCertRequest.SerializeToString, response_deserializer=ateapi__pb2.MintCertResponse.FromString, _registered_method=True) -class SessionIdentityServicer: - """SessionIdentity allows substrate workloads to exchange their +class ActorIdentityServicer: + """ActorIdentity allows substrate workloads to exchange their infrastructure-level credentials (k8s service account token, etc.) for a - substrate session-level credential. A given substrate session might migrate + substrate actor-level credential. A given substrate actor might migrate between many different physical workers over the course of its lifecycle, - whereas the session credential's identity will be stable for the life of the - session. + whereas the actor credential's identity will be stable for the life of the + actor. This service requires authentication. You can authenticate with a Kubernetes service account token in an `Authorization: Bearer` header, or you can @@ -774,22 +774,22 @@ class SessionIdentityServicer: upstream, but we will provide a polyfill based on Pod Certificates). The broker will check that the service credentials you authenticated with - belong to a Pod that is currently mapped to the requested session in the - session database. + belong to a Pod that is currently mapped to the requested actor in the + actor database. """ def MintJWT(self, request, context): - """Request a Session Identity JWT. + """Request an Actor Identity JWT. To call this RPC, you must be authenticated as the Kubernetes Pod that is - currently running the requested session. + currently running the requested actor. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def MintCert(self, request, context): - """Request a Session Identity Certificate. To call this RPC, you must have + """Request an Actor Identity Certificate. To call this RPC, you must have authenticated with a client certificate, not a bearer token. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) @@ -797,7 +797,7 @@ def MintCert(self, request, context): raise NotImplementedError('Method not implemented!') -def add_SessionIdentityServicer_to_server(servicer, server): +def add_ActorIdentityServicer_to_server(servicer, server): rpc_method_handlers = { 'MintJWT': grpc.unary_unary_rpc_method_handler( servicer.MintJWT, @@ -811,19 +811,19 @@ def add_SessionIdentityServicer_to_server(servicer, server): ), } generic_handler = grpc.method_handlers_generic_handler( - 'ateapi.SessionIdentity', rpc_method_handlers) + 'ateapi.ActorIdentity', rpc_method_handlers) server.add_generic_rpc_handlers((generic_handler,)) - server.add_registered_method_handlers('ateapi.SessionIdentity', rpc_method_handlers) + server.add_registered_method_handlers('ateapi.ActorIdentity', rpc_method_handlers) # This class is part of an EXPERIMENTAL API. -class SessionIdentity: - """SessionIdentity allows substrate workloads to exchange their +class ActorIdentity: + """ActorIdentity allows substrate workloads to exchange their infrastructure-level credentials (k8s service account token, etc.) for a - substrate session-level credential. A given substrate session might migrate + substrate actor-level credential. A given substrate actor might migrate between many different physical workers over the course of its lifecycle, - whereas the session credential's identity will be stable for the life of the - session. + whereas the actor credential's identity will be stable for the life of the + actor. This service requires authentication. You can authenticate with a Kubernetes service account token in an `Authorization: Bearer` header, or you can @@ -832,8 +832,8 @@ class SessionIdentity: upstream, but we will provide a polyfill based on Pod Certificates). The broker will check that the service credentials you authenticated with - belong to a Pod that is currently mapped to the requested session in the - session database. + belong to a Pod that is currently mapped to the requested actor in the + actor database. """ @staticmethod @@ -850,7 +850,7 @@ def MintJWT(request, return grpc.experimental.unary_unary( request, target, - '/ateapi.SessionIdentity/MintJWT', + '/ateapi.ActorIdentity/MintJWT', ateapi__pb2.MintJWTRequest.SerializeToString, ateapi__pb2.MintJWTResponse.FromString, options, @@ -877,7 +877,7 @@ def MintCert(request, return grpc.experimental.unary_unary( request, target, - '/ateapi.SessionIdentity/MintCert', + '/ateapi.ActorIdentity/MintCert', ateapi__pb2.MintCertRequest.SerializeToString, ateapi__pb2.MintCertResponse.FromString, options, diff --git a/cmd/ateapi/internal/sessionidentity/sessionidentity.go b/cmd/ateapi/internal/actoridentity/actoridentity.go similarity index 69% rename from cmd/ateapi/internal/sessionidentity/sessionidentity.go rename to cmd/ateapi/internal/actoridentity/actoridentity.go index a9a581271..1a5a7cbd6 100644 --- a/cmd/ateapi/internal/sessionidentity/sessionidentity.go +++ b/cmd/ateapi/internal/actoridentity/actoridentity.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package sessionidentity +package actoridentity import ( "context" @@ -28,8 +28,8 @@ import ( "strings" "time" + "github.com/agent-substrate/substrate/cmd/ateapi/internal/actoridjwt" "github.com/agent-substrate/substrate/cmd/ateapi/internal/k8sjwt" - "github.com/agent-substrate/substrate/cmd/ateapi/internal/sessionidjwt" "github.com/agent-substrate/substrate/internal/localca" "github.com/agent-substrate/substrate/internal/localjwtauthority" "github.com/agent-substrate/substrate/pkg/proto/ateapipb" @@ -40,31 +40,31 @@ import ( "google.golang.org/grpc/status" ) -// Server implements ateapipb.SessionIdentityServer +// Server implements ateapipb.ActorIdentityServer type Server struct { - ateapipb.UnimplementedSessionIdentityServer + ateapipb.UnimplementedActorIdentityServer clientJWTIssuer string clientJWTAudience string // TODO: Cache the signing keys in memory, so we don't read from a file every time. - sessionIDJWTPoolFile string - sessionIDCAPoolFile string + actorIDJWTPoolFile string + actorIDCAPoolFile string workerCACerts string httpClient *http.Client } -var _ ateapipb.SessionIdentityServer = (*Server)(nil) +var _ ateapipb.ActorIdentityServer = (*Server)(nil) -func New(clientJWTIssuer, clientJWTAudience, sessionIDJWTPoolFile, sessionIDCAPoolFile, workerCACerts string, httpClient *http.Client) *Server { +func New(clientJWTIssuer, clientJWTAudience, actorIDJWTPoolFile, actorIDCAPoolFile, workerCACerts string, httpClient *http.Client) *Server { return &Server{ - clientJWTIssuer: clientJWTIssuer, - clientJWTAudience: clientJWTAudience, - sessionIDJWTPoolFile: sessionIDJWTPoolFile, - sessionIDCAPoolFile: sessionIDCAPoolFile, - workerCACerts: workerCACerts, - httpClient: httpClient, + clientJWTIssuer: clientJWTIssuer, + clientJWTAudience: clientJWTAudience, + actorIDJWTPoolFile: actorIDJWTPoolFile, + actorIDCAPoolFile: actorIDCAPoolFile, + workerCACerts: workerCACerts, + httpClient: httpClient, } } @@ -91,10 +91,10 @@ func (s *Server) MintJWT(ctx context.Context, req *ateapipb.MintJWTRequest) (*at // TODO: Extract K8s identity from incoming JWT - // TODO: Cross-check requested session and user claims against the session database. + // TODO: Cross-check requested actor and user claims against the actor database. // TODO: Cache signing keys in memory, so we don't read from disk every time. - signingPoolBytes, err := os.ReadFile(s.sessionIDJWTPoolFile) + signingPoolBytes, err := os.ReadFile(s.actorIDJWTPoolFile) if err != nil { return nil, fmt.Errorf("while reading signing pool bytes: %w", err) } @@ -109,35 +109,35 @@ func (s *Server) MintJWT(ctx context.Context, req *ateapipb.MintJWTRequest) (*at return nil, fmt.Errorf("at least one audience must be requested") } - sessionClaims := &sessionidjwt.Claims{ - Issuer: "https://broker.agentic-substrate-session-id-broker.svc", // TODO: This needs to be globally unique. - Subject: fmt.Sprintf("apps/%s/users/%s/sessions/%s", req.GetAppId(), req.GetUserId(), req.GetSessionId()), + actorClaims := &actoridjwt.Claims{ + Issuer: "https://broker.agentic-substrate-actor-id-broker.svc", // TODO: This needs to be globally unique. + Subject: fmt.Sprintf("apps/%s/users/%s/actors/%s", req.GetAppId(), req.GetUserId(), req.GetActorId()), Audiences: req.GetAudience(), Expiration: time.Now().Add(15 * time.Minute), NotBefore: time.Now().Add(-5 * time.Minute), IssuedAt: time.Now(), JTI: rand.Text(), - Substrate: sessionidjwt.SubstrateClaims{ - AppID: req.GetAppId(), - UserID: req.GetUserId(), - SessionID: req.GetSessionId(), + Substrate: actoridjwt.SubstrateClaims{ + AppID: req.GetAppId(), + UserID: req.GetUserId(), + ActorID: req.GetActorId(), }, } - sessionWireClaims, err := sessionidjwt.ClaimsToWire(sessionClaims) + actorWireClaims, err := actoridjwt.ClaimsToWire(actorClaims) if err != nil { - return nil, fmt.Errorf("while making session JWT claims: %w", err) + return nil, fmt.Errorf("while making actor JWT claims: %w", err) } // Assume the first authority is the one to use for signing. - sessionJWT, err := sessionidjwt.Sign(sessionWireClaims, signingPool.Authorities[0].SigningKey, signingPool.Authorities[0].Algorithm, signingPool.Authorities[0].ID) + actorJWT, err := actoridjwt.Sign(actorWireClaims, signingPool.Authorities[0].SigningKey, signingPool.Authorities[0].Algorithm, signingPool.Authorities[0].ID) if err != nil { - return nil, fmt.Errorf("while signing session JWT: %w", err) + return nil, fmt.Errorf("while signing actor JWT: %w", err) } return &ateapipb.MintJWTResponse{ - SessionJwt: sessionJWT, + ActorJwt: actorJWT, }, nil } @@ -156,25 +156,25 @@ func (s *Server) MintCert(ctx context.Context, req *ateapipb.MintCertRequest) (* return nil, status.Errorf(codes.Unauthenticated, "could not verify peer certificate") } - // TODO: How to verify pod cert <-> session mapping? + // TODO: How to verify pod cert <-> actor mapping? appID := req.GetAppId() userID := req.GetUserId() - sessionID := req.GetSessionId() + actorID := req.GetActorId() - if appID == "" || userID == "" || sessionID == "" { - return nil, status.Errorf(codes.InvalidArgument, "app_id, user_id, and session_id are required") + if appID == "" || userID == "" || actorID == "" { + return nil, status.Errorf(codes.InvalidArgument, "app_id, user_id, and actor_id are required") } // Load the CA pool for signing - poolBytes, err := os.ReadFile(s.sessionIDCAPoolFile) + poolBytes, err := os.ReadFile(s.actorIDCAPoolFile) if err != nil { - slog.ErrorContext(ctx, "Failed to read session CA pool file", slog.Any("err", err)) - return nil, status.Errorf(codes.Internal, "Failed to load session CA") + slog.ErrorContext(ctx, "Failed to read actor CA pool file", slog.Any("err", err)) + return nil, status.Errorf(codes.Internal, "Failed to load actor CA") } caPool, err := localca.Unmarshal(poolBytes) if err != nil || len(caPool.CAs) == 0 { - slog.ErrorContext(ctx, "Failed to load session CA", slog.Any("err", err)) - return nil, status.Errorf(codes.Internal, "Failed to load session CA") + slog.ErrorContext(ctx, "Failed to load actor CA", slog.Any("err", err)) + return nil, status.Errorf(codes.Internal, "Failed to load actor CA") } // Parse the CSR @@ -190,8 +190,8 @@ func (s *Server) MintCert(ctx context.Context, req *ateapipb.MintCertRequest) (* spiffeURI := &url.URL{ Scheme: "spiffe", - Host: "substrate-session.local", - Path: path.Join("app", appID, "user", userID, "session", sessionID), + Host: "substrate-actor.local", + Path: path.Join("app", appID, "user", userID, "actor", actorID), } template := &x509.Certificate{ URIs: []*url.URL{spiffeURI}, @@ -206,7 +206,7 @@ func (s *Server) MintCert(ctx context.Context, req *ateapipb.MintCertRequest) (* }, } - // Sign and return the session cert. + // Sign and return the actor cert. ca := caPool.CAs[0] derBytes, err := x509.CreateCertificate(rand.Reader, template, ca.RootCertificate, csr.PublicKey, ca.SigningKey) if err != nil { @@ -220,6 +220,6 @@ func (s *Server) MintCert(ctx context.Context, req *ateapipb.MintCertRequest) (* } return &ateapipb.MintCertResponse{ - SessionCertificates: certificates, + ActorCertificates: certificates, }, nil } diff --git a/cmd/ateapi/internal/sessionidjwt/sessionidjwt.go b/cmd/ateapi/internal/actoridjwt/actoridjwt.go similarity index 95% rename from cmd/ateapi/internal/sessionidjwt/sessionidjwt.go rename to cmd/ateapi/internal/actoridjwt/actoridjwt.go index ebd52fb91..980269d6c 100644 --- a/cmd/ateapi/internal/sessionidjwt/sessionidjwt.go +++ b/cmd/ateapi/internal/actoridjwt/actoridjwt.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package sessionidjwt +package actoridjwt import ( "crypto" @@ -42,9 +42,9 @@ type Claims struct { } type SubstrateClaims struct { - AppID string - UserID string - SessionID string + AppID string + UserID string + ActorID string } type wireHeader struct { @@ -68,9 +68,9 @@ type WireClaims struct { } type WireSubstrateClaims struct { - AppID string `json:"appID,omitempty"` - UserID string `json:"userID,omitempty"` - SessionID string `json:"sessionID,omitempty"` + AppID string `json:"appID,omitempty"` + UserID string `json:"userID,omitempty"` + ActorID string `json:"actorID,omitempty"` } func ClaimsToWire(claims *Claims) (*WireClaims, error) { @@ -90,7 +90,7 @@ func ClaimsToWire(claims *Claims) (*WireClaims, error) { Substrate: WireSubstrateClaims{ claims.Substrate.AppID, claims.Substrate.UserID, - claims.Substrate.SessionID, + claims.Substrate.ActorID, }, } diff --git a/cmd/ateapi/internal/store/ateredis/ateredis_test.go b/cmd/ateapi/internal/store/ateredis/ateredis_test.go index 931949f94..87959a153 100644 --- a/cmd/ateapi/internal/store/ateredis/ateredis_test.go +++ b/cmd/ateapi/internal/store/ateredis/ateredis_test.go @@ -76,7 +76,7 @@ func TestCreateActor_Success(t *testing.T) { _, s, ctx := setupTest(t) actor := &ateapipb.Actor{ - Metadata: &ateapipb.ResourceMetadata{Name: "session-1", Atespace: testAtespace}, + Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: testAtespace}, ActorTemplateNamespace: "default", ActorTemplateName: "test-template", Status: ateapipb.Actor_STATUS_SUSPENDED, @@ -124,7 +124,7 @@ func TestCreateActor_AlreadyExists(t *testing.T) { _, s, ctx := setupTest(t) actor := &ateapipb.Actor{ - Metadata: &ateapipb.ResourceMetadata{Name: "session-1", Atespace: testAtespace}, + Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: testAtespace}, ActorTemplateNamespace: "default", ActorTemplateName: "test-template", Status: ateapipb.Actor_STATUS_SUSPENDED, @@ -145,7 +145,7 @@ func TestUpdateActor_Success(t *testing.T) { _, s, ctx := setupTest(t) actor := &ateapipb.Actor{ - Metadata: &ateapipb.ResourceMetadata{Name: "session-1", Atespace: testAtespace}, + Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: testAtespace}, ActorTemplateNamespace: "default", ActorTemplateName: "test-template", Status: ateapipb.Actor_STATUS_SUSPENDED, @@ -197,7 +197,7 @@ func TestUpdateActor_Conflict(t *testing.T) { _, s, ctx := setupTest(t) actor := &ateapipb.Actor{ - Metadata: &ateapipb.ResourceMetadata{Name: "session-1", Atespace: testAtespace}, + Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: testAtespace}, ActorTemplateNamespace: "default", ActorTemplateName: "test-template", Status: ateapipb.Actor_STATUS_SUSPENDED, @@ -339,7 +339,7 @@ func TestUpdateWorker_Success(t *testing.T) { Name: "test-template", }, Actor: &ateapipb.ObjectRef{ - Name: "session-1", + Name: "actor-1", }, } @@ -425,7 +425,7 @@ func TestDeleteActor(t *testing.T) { _, s, ctx := setupTest(t) actor := &ateapipb.Actor{ - Metadata: &ateapipb.ResourceMetadata{Name: "session-1", Atespace: testAtespace}, + Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: testAtespace}, ActorTemplateNamespace: "default", ActorTemplateName: "test-template", Status: tt.status, @@ -435,7 +435,7 @@ func TestDeleteActor(t *testing.T) { t.Fatalf("CreateActor failed: %v", err) } - deleted, err := s.DeleteActor(ctx, resources.ActorRef{Atespace: testAtespace, Name: "session-1"}) + deleted, err := s.DeleteActor(ctx, resources.ActorRef{Atespace: testAtespace, Name: "actor-1"}) if tt.wantErr != nil { if !errors.Is(err, tt.wantErr) { t.Errorf("DeleteActor: expected %v, got %v", tt.wantErr, err) @@ -446,11 +446,11 @@ func TestDeleteActor(t *testing.T) { t.Fatalf("DeleteActor failed: %v", err) } // DeleteActor returns the deleted resource. - if got := deleted.GetMetadata().GetName(); got != "session-1" { - t.Errorf("deleted actor name = %q, want session-1", got) + if got := deleted.GetMetadata().GetName(); got != "actor-1" { + t.Errorf("deleted actor name = %q, want actor-1", got) } - if _, err := s.GetActor(ctx, resources.ActorRef{Atespace: testAtespace, Name: "session-1"}); !errors.Is(err, store.ErrNotFound) { + if _, err := s.GetActor(ctx, resources.ActorRef{Atespace: testAtespace, Name: "actor-1"}); !errors.Is(err, store.ErrNotFound) { t.Errorf("expected ErrNotFound after delete, got %v", err) } }) @@ -599,14 +599,14 @@ func TestUpdateWorker_Conflict(t *testing.T) { } // Update instance 1 - worker1.Assignment = &ateapipb.Assignment{Actor: &ateapipb.ObjectRef{Name: "session-1"}} + worker1.Assignment = &ateapipb.Assignment{Actor: &ateapipb.ObjectRef{Name: "actor-1"}} err = s.UpdateWorker(ctx, worker1, worker1.Version) if err != nil { t.Fatalf("UpdateWorker failed: %v", err) } // Try to update instance 2 - worker2.Assignment = &ateapipb.Assignment{Actor: &ateapipb.ObjectRef{Name: "session-2"}} + worker2.Assignment = &ateapipb.Assignment{Actor: &ateapipb.ObjectRef{Name: "actor-2"}} err = s.UpdateWorker(ctx, worker2, worker2.Version) if !errors.Is(err, store.ErrVersionConflict) { t.Errorf("expected ErrVersionConflict, got %v", err) diff --git a/cmd/ateapi/main.go b/cmd/ateapi/main.go index b7bc65472..0db329e1f 100644 --- a/cmd/ateapi/main.go +++ b/cmd/ateapi/main.go @@ -29,10 +29,10 @@ import ( "syscall" "time" + "github.com/agent-substrate/substrate/cmd/ateapi/internal/actoridentity" "github.com/agent-substrate/substrate/cmd/ateapi/internal/controlapi" "github.com/agent-substrate/substrate/cmd/ateapi/internal/debugapi" "github.com/agent-substrate/substrate/cmd/ateapi/internal/k8sjwt" - "github.com/agent-substrate/substrate/cmd/ateapi/internal/sessionidentity" "github.com/agent-substrate/substrate/cmd/ateapi/internal/store/ateredis" "github.com/agent-substrate/substrate/cmd/ateapi/internal/workercache" "github.com/agent-substrate/substrate/internal/ateapiauth" @@ -71,11 +71,11 @@ var ( redisTLSServerName = pflag.String("redis-tls-server-name", "", "The ServerName to use for Redis TLS hostname verification.") redisClientCert = pflag.String("redis-client-cert", "", "The file containing client TLS certificate/key credential bundle for Redis/Valkey.") - clientJWTIssuer = pflag.String("client-jwt-issuer", "", "The expected issuer URL for client JWTs.") - clientJWTAudience = pflag.String("client-jwt-audience", "", "The expected audience for client JWTs.") - sessionIDJWTPoolFile = pflag.String("session-id-jwt-pool", "", "The file that contains the serialized JWT authority pool for signing session JWTs") + clientJWTIssuer = pflag.String("client-jwt-issuer", "", "The expected issuer URL for client JWTs.") + clientJWTAudience = pflag.String("client-jwt-audience", "", "The expected audience for client JWTs.") + actorIDJWTPoolFile = pflag.String("actor-id-jwt-pool", "", "The file that contains the serialized JWT authority pool for signing actor JWTs") - sessionIDCAPoolFile = pflag.String("session-id-ca-pool", "", "The file that contains the CA pool for signing session JWTs") + actorIDCAPoolFile = pflag.String("actor-id-ca-pool", "", "The file that contains the CA pool for signing actor JWTs") podIdentityCACerts = pflag.String("pod-identity-ca-certs", "", "The file that contains the pod-identity CA bundle, used both for verifying client certificates presented to the gRPC server and for verifying atelet serving certificates when dialing atelet. If empty, client-cert verification is disabled and atelet dials will fail.") ateletClientCredBundle = pflag.String("atelet-client-cred-bundle", "", "Credential bundle presented as the client certificate when dialing atelet.") @@ -171,7 +171,7 @@ func main() { jwtIssuerDiscoveryClient := buildK8sServiceAccountIssuerDiscoveryClient(ctx, *clientJWTCAFile, *clientJWTIssuer) - sessionIdentitySrv := sessionidentity.New(*clientJWTIssuer, *clientJWTAudience, *sessionIDJWTPoolFile, *sessionIDCAPoolFile, *podIdentityCACerts, jwtIssuerDiscoveryClient) + actorIdentitySrv := actoridentity.New(*clientJWTIssuer, *clientJWTAudience, *actorIDJWTPoolFile, *actorIDCAPoolFile, *podIdentityCACerts, jwtIssuerDiscoveryClient) debugSrv := debugapi.NewService(redisPersistence) lisCfg := &net.ListenConfig{} @@ -220,7 +220,7 @@ func main() { ) reflection.Register(mux) ateapipb.RegisterControlServer(mux, sm) - ateapipb.RegisterSessionIdentityServer(mux, sessionIdentitySrv) + ateapipb.RegisterActorIdentityServer(mux, actorIdentitySrv) ateapipb.RegisterDebugServer(mux, debugSrv) readiness := &serverboot.Readiness{} @@ -297,8 +297,8 @@ func logFlagValues(ctx context.Context) { slog.String("redis-client-cert", *redisClientCert), slog.String("client-jwt-issuer", *clientJWTIssuer), slog.String("client-jwt-audience", *clientJWTAudience), - slog.String("session-id-jwt-pool", *sessionIDJWTPoolFile), - slog.String("session-id-ca-pool", *sessionIDCAPoolFile), + slog.String("actor-id-jwt-pool", *actorIDJWTPoolFile), + slog.String("actor-id-ca-pool", *actorIDCAPoolFile), slog.String("pod-identity-ca-certs", *podIdentityCACerts), slog.String("atelet-client-cred-bundle", *ateletClientCredBundle), slog.Duration("drain-delay", *drainDelay), diff --git a/cmd/atenet/internal/router/README.md b/cmd/atenet/internal/router/README.md index d8e72f8ae..71854a86a 100644 --- a/cmd/atenet/internal/router/README.md +++ b/cmd/atenet/internal/router/README.md @@ -12,7 +12,7 @@ Router has several responsibilities: * Make sure the interface with ATE API is pluggable so that we can test with a mock ATE API. * Runs an xDS server for the Envoy deployment that defines the Cluster information for the ATEs. * the xDS configuration will configure Envoy to send traffic to ext_proc -* Watches the ActorTemplates to get out the definitions for how to route the session IDs. +* Watches the ActorTemplates to get out the definitions for how to route the actor IDs. * Parks requests whose actor cannot be served immediately due to transient worker-pool saturation, retrying the resume until the actor is routable or a bounded wait elapses, instead of failing fast. See diff --git a/cmd/kubectl-ate/README.md b/cmd/kubectl-ate/README.md index af69c8a63..b25b39573 100644 --- a/cmd/kubectl-ate/README.md +++ b/cmd/kubectl-ate/README.md @@ -191,15 +191,15 @@ Logs are streamable only while the actor is bound to a worker (i.e., `STATUS_RUN Commands for bootstrapping the Substrate control plane and debugging local environments. ```bash -# Generate a new Session ID CA pool and push it directly to a Kubernetes Secret +# Generate a new Actor ID CA pool and push it directly to a Kubernetes Secret kubectl ate admin make-ca-pool \ - --name session-id-ca-pool \ + --name actor-id-ca-pool \ --secret-namespace ate-system \ --ca-id "1" # Generate a new JWT authority pool and push it to a Kubernetes Secret kubectl ate admin make-jwt-pool \ - --name session-id-jwt-pool \ + --name actor-id-jwt-pool \ --secret-namespace ate-system \ --key-id "1" diff --git a/cmd/kubectl-ate/internal/cmd/admin_make_jwt_pool.go b/cmd/kubectl-ate/internal/cmd/admin_make_jwt_pool.go index 1ee309ff6..659c3ca37 100644 --- a/cmd/kubectl-ate/internal/cmd/admin_make_jwt_pool.go +++ b/cmd/kubectl-ate/internal/cmd/admin_make_jwt_pool.go @@ -29,7 +29,7 @@ var keyID string var makeJwtPoolCmd = &cobra.Command{ Use: "make-jwt-pool", - Short: "Make a new secret that contains a JWT authority pool to be used by the session ID broker", + Short: "Make a new secret that contains a JWT authority pool to be used by the actor ID broker", RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() diff --git a/demos/autoscaled-workerpool/README.md b/demos/autoscaled-workerpool/README.md index d1652b86f..c3953417a 100644 --- a/demos/autoscaled-workerpool/README.md +++ b/demos/autoscaled-workerpool/README.md @@ -126,7 +126,7 @@ done kubectl port-forward -n ate-system svc/atenet-router 8000:80 & ``` -In a separate terminal, send requests in a retry loop across all hosts to activate the actors and keep sessions active while the pool scales up: +In a separate terminal, send requests in a retry loop across all hosts to activate the actors and keep them active while the pool scales up: ```sh for attempt in {1..10}; do diff --git a/docs/api-guide.md b/docs/api-guide.md index 5200dc4e1..fd2802448 100644 --- a/docs/api-guide.md +++ b/docs/api-guide.md @@ -294,11 +294,11 @@ Query the physical resource pool. --- -## 7. Advanced: Session Identity +## 7. Advanced: Actor Identity Credentials -Workloads can exchange their ephemeral Kubernetes credentials for stable **Session Identity** credentials that persist even as the process migrates between different physical workers. +Workloads can exchange their ephemeral Kubernetes credentials for stable **Actor Identity** credentials that persist even as the process migrates between different physical workers. This is distinct from the `/run/ate/actor-id` bind mount described under [Actor Identity](#actor-identity), which only tells an actor its own name. -### Service: `ateapi.SessionIdentity` +### Service: `ateapi.ActorIdentity` * **`MintJWT`:** Generates an OIDC-compatible JWT identifying the Substrate Actor. * **`MintCert`:** Signs a Certificate Signing Request (CSR) to provide an mTLS identity for the actor. @@ -309,7 +309,7 @@ Workloads can exchange their ephemeral Kubernetes credentials for stable **Sessi Agent Substrate is designed to be the foundational execution layer for any agentic framework. ### Agent Development Kit (ADK) -Substrate provides native support for ADK-compatible identities. Workloads can use the `SessionIdentity` service to mint JWTs that align with ADK's security model, ensuring seamless integration with ADK-managed tools and memory. +Substrate provides native support for ADK-compatible identities. Workloads can use the `ActorIdentity` service to mint JWTs that align with ADK's security model, ensuring seamless integration with ADK-managed tools and memory. ### LangChain Substrate is an ideal runtime for stateful LangChain agents. By defining a LangChain agent as an `ActorTemplate`, you can preserve the agent's internal "thought process" and conversation history in memory across hibernations, while sandboxing its tool execution for security. diff --git a/docs/architecture.md b/docs/architecture.md index 9a2a512cb..8c734dce6 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -342,11 +342,11 @@ A `WorkerPool` selects a **sandbox class** (`spec.sandboxClass`), and each class ### Networking Stack (`atenet` + Envoy) -Handles session-aware routing and automatic re-animation. +Handles actor-aware routing and automatic re-animation. * **Uniform DNS Mesh**: Substrate provides a location-transparent actor discovery scheme via a global DNS suffix (`..actors.resources.substrate.ate.dev`). - * **Routing**: The `atenet` router (powered by Envoy and an External Processing server) intercepts traffic destined for the mesh. It extracts the actor name from the `Host` header, queries the Control Plane to determine the actor's current location, and triggers a `ResumeActor` workflow if the session is currently suspended. + * **Routing**: The `atenet` router (powered by Envoy and an External Processing server) intercepts traffic destined for the mesh. It extracts the actor name from the `Host` header, queries the Control Plane to determine the actor's current location, and triggers a `ResumeActor` workflow if the actor is currently suspended. * **Latency**: The data plane is optimized for sub-100ms activation by bypassing Kubernetes' eventual consistency and performing atomic physical assignments. diff --git a/docs/roadmap.md b/docs/roadmap.md index 195a72492..5849428bc 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -70,7 +70,7 @@ Below is a collection of finer-grained efforts which we believe align with the a ### Observability -* Session-Aware Telemetry Correlation: Automated OTLP export where all logs, metrics, and traces are natively tagged with the Substrate actor name and worker ID. +* Actor-Aware Telemetry Correlation: Automated OTLP export where all logs, metrics, and traces are natively tagged with the Substrate actor name and worker ID. * Prometheus metrics ### Performance and Reliability diff --git a/docs/threat-model.md b/docs/threat-model.md index 7e3a0d1ac..9a8d3fb9a 100644 --- a/docs/threat-model.md +++ b/docs/threat-model.md @@ -109,7 +109,7 @@ While it's probably unlikely that Substrate, which is expected to be an internal | | Critical | Worker reuse enables malicious actor to escalate to other actors by persisting a threat across reuse, reading leftover state from a previous actor, or taking advantage of stale policy configuration. | All actor-specific worker state, including process state, filesystem, env vars, mounted config, network policy, and security policy, must be completely reset between actors that subsequently run on the same worker. | Ensure local policy updates are tightly synchronized with actor lifecycle to avoid race conditions. Test that the suspend/resume lifecycle for every supported sandbox technology properly cleans up state by exercising it and enumerating system state. Use "honeypots" on each side of the boundary to detect state leaks. Test policy behavior on both sides of suspend/resume to ensure policies are appropriately updated in-sync with actor lifecycle. | | | | Critical | Malicious actor tricks Substrate identity broker into returning identity credentials for a different actor. | Add defense-in-depth to ensure that credentials cannot be mis-issued, and that mis-issued credentials are unusable in practice. | Ensure that credential issuance checks actor-to-worker scheduling assignment. Ensure actor identities include claims tying them to the worker and node the actor is scheduled to. Ensure claims are validated against scheduling assignments during authz policy evaluation; when actors are rescheduled old credentials should be immediately invalidated. | | | | High | Agent leaks credentials exposed in sandbox, because LLMs are unreliable. Due to prompt injection or just agent silliness. | Credentials are not exposed in sandboxes by default. | Opt-in to credentials, none by default. Credential injecting proxy (injects tokens or terminates TLS and holds x509 private key on behalf of sandbox). Delegation to "drivers" rather than relying on sandboxed clients (like CSI). Encrypting credentials exposed in sandboxes, requiring them to be unwrapped by a network proxy to be usable. Consider supporting pluggable per-node or per-worker security sidecars that can interpose network, implement additional policy, add monitoring, etc. | May provide an option to expose in sandbox if there are other mitigating factors. For example, the process is NOT an AI agent, or the process limits agent access to env/filesystem. | -| | High | Malicious actor moves laterally to other nodes via suspend/resume, especially if self-suspend is allowed. | Suspend/resume is guaranteed to provide some acceptable locality with respect to lateral movement. TBD. | Maybe some kind of session pinning to specific groups of nodes, to contain the movement? Or statistical bias to resume on the same node? | Particularly useful in combination with a sandbox breakout vuln, or network or filesystem access vulns. | +| | High | Malicious actor moves laterally to other nodes via suspend/resume, especially if self-suspend is allowed. | Suspend/resume is guaranteed to provide some acceptable locality with respect to lateral movement. TBD. | Maybe some kind of actor pinning to specific groups of nodes, to contain the movement? Or statistical bias to resume on the same node? | Particularly useful in combination with a sandbox breakout vuln, or network or filesystem access vulns. | | | High | DoS/resource exhaustion via malicious container image | Enforce limits when pulling and extracting container images | Ensure limits on the uncompressed layers are enforced when untarring container images. Ensure a time limit is enforced when unpacking container images. | For example, image can contain a zip bomb. | | | Medium | Compromised process inside actor uses actor identity to write its own snapshot, enabling local privilege escalation (still in actor sandbox). | Issue separate credentials for accessing snapshots. | Even if actor identity is used to make snapshot access permissions granular, require an extra claim, audience, or dual-identity authorization to prove that it's atelet accessing the snapshot on behalf of the actor, rather than the actor itself. | Medium since it's still a local exploit within the application layer. Example: nonroot process with access to the actor credential rewrites a snapshot so that it can `su` to root after the next restore. | | | Medium | Attacker creates a large number of malicious actors to rapidly spread across the cluster or exhaust resources (via direct create or fork-bomb equivalent). | Limit resource consumption and number of child actors for each actor. | Direct ability to create actors should be considered a privileged permission. Use rate quotas and throttling to limit the speed of execution of this attack. Account for number of child actors and resource consumption by children so quotas can be enforced. Implement a namespace-like concept that quotas can be attached to. | | diff --git a/hack/install-ate.sh b/hack/install-ate.sh index b8c871020..871350a0e 100755 --- a/hack/install-ate.sh +++ b/hack/install-ate.sh @@ -76,7 +76,7 @@ function usage() { echo "called automatically by --deploy-ate-system):" echo "" echo " --create-jwt-authority-pool-secret Create JWT authority pool secret" - echo " --create-session-id-ca-pool-secret Create session ID CA pool secret" + echo " --create-actor-id-ca-pool-secret Create actor ID CA pool secret" echo " --create-podcertificate-controller-cas Create podcertificate controller CAs" echo " --create-valkey-ca-certs-secret Create Valkey CA certs secret" echo " --create-api-server-env-vars Create ate-api-server env vars" @@ -209,15 +209,15 @@ create_jwt_authority_pool_secret() { log_step "create_jwt_authority_pool_secret" run_kubectl_ate admin make-jwt-pool \ --key-id="1" \ - --name="session-id-jwt-pool" \ + --name="actor-id-jwt-pool" \ --secret-namespace=ate-system } -create_session_id_ca_pool_secret() { - log_step "create_session_id_ca_pool_secret" +create_actor_id_ca_pool_secret() { + log_step "create_actor_id_ca_pool_secret" run_kubectl_ate admin make-ca-pool \ --ca-id="1" \ - --name="session-id-ca-pool" \ + --name="actor-id-ca-pool" \ --secret-namespace=ate-system } @@ -334,10 +334,10 @@ deploy_ate_system() { # Ensure secrets and configmaps required by ate-apiserver ensure_apiserver_prerequisites() { log_step "ensure_apiserver_prerequisites" - run_kubectl get secret -n ate-system session-id-jwt-pool >/dev/null 2>&1 \ + run_kubectl get secret -n ate-system actor-id-jwt-pool >/dev/null 2>&1 \ || create_jwt_authority_pool_secret - run_kubectl get secret -n ate-system session-id-ca-pool >/dev/null 2>&1 \ - || create_session_id_ca_pool_secret + run_kubectl get secret -n ate-system actor-id-ca-pool >/dev/null 2>&1 \ + || create_actor_id_ca_pool_secret run_kubectl get secret -n podcertificate-controller-system service-dns-ca-pool >/dev/null 2>&1 \ || create_podcertificate_controller_cas run_kubectl get secret -n ate-system valkey-ca-certs >/dev/null 2>&1 \ @@ -613,7 +613,7 @@ while [[ "$#" -gt 0 ]]; do --benchmark-worker-count=*) ;; --create-jwt-authority-pool-secret) create_jwt_authority_pool_secret ;; - --create-session-id-ca-pool-secret) create_session_id_ca_pool_secret ;; + --create-actor-id-ca-pool-secret) create_actor_id_ca_pool_secret ;; --create-podcertificate-controller-cas) create_podcertificate_controller_cas ;; --create-valkey-ca-certs-secret) create_valkey_ca_certs_secret ;; --create-api-server-env-vars) create_api_server_env_vars ;; diff --git a/internal/localca/localca_test.go b/internal/localca/localca_test.go index c470a4d48..0cca4ef6f 100644 --- a/internal/localca/localca_test.go +++ b/internal/localca/localca_test.go @@ -209,7 +209,7 @@ func TestUnmarshalPEMPool(t *testing.T) { } template := &x509.Certificate{ SerialNumber: big.NewInt(1), - Subject: pkix.Name{CommonName: "session-id-ca"}, + Subject: pkix.Name{CommonName: "actor-id-ca"}, NotBefore: time.Now(), NotAfter: time.Now().Add(24 * time.Hour), IsCA: true, @@ -244,8 +244,8 @@ func TestUnmarshalPEMPool(t *testing.T) { if _, ok := pool.CAs[0].SigningKey.(*rsa.PrivateKey); !ok { t.Fatalf("SigningKey type = %T, want *rsa.PrivateKey", pool.CAs[0].SigningKey) } - if pool.CAs[0].RootCertificate.Subject.CommonName != "session-id-ca" { - t.Fatalf("RootCertificate CN = %q, want session-id-ca", pool.CAs[0].RootCertificate.Subject.CommonName) + if pool.CAs[0].RootCertificate.Subject.CommonName != "actor-id-ca" { + t.Fatalf("RootCertificate CN = %q, want actor-id-ca", pool.CAs[0].RootCertificate.Subject.CommonName) } } diff --git a/manifests/ate-install/ate-api-server.yaml b/manifests/ate-install/ate-api-server.yaml index 7a263faac..0bb913c86 100644 --- a/manifests/ate-install/ate-api-server.yaml +++ b/manifests/ate-install/ate-api-server.yaml @@ -98,8 +98,8 @@ spec: - --redis-client-cert=@env - --client-jwt-issuer=@env - --client-jwt-audience=api.ate-system.svc - - --session-id-jwt-pool=/run/session-id-jwt-pool/pool.json - - --session-id-ca-pool=/run/session-id-ca-pool/pool.json + - --actor-id-jwt-pool=/run/actor-id-jwt-pool/pool.json + - --actor-id-ca-pool=/run/actor-id-ca-pool/pool.json - --atelet-client-cred-bundle=/run/podidentity.podcert.ate.dev/credential-bundle.pem - --pod-identity-ca-certs=/run/podidentity.podcert.ate.dev/trust-bundle.pem # Graceful shutdown knobs. The sum must fit within terminationGracePeriodSeconds. @@ -139,14 +139,14 @@ spec: # serving certificate. - name: "podidentity" mountPath: "/run/podidentity.podcert.ate.dev" - - name: "session-id-jwt-pool" - mountPath: "/run/session-id-jwt-pool" + - name: "actor-id-jwt-pool" + mountPath: "/run/actor-id-jwt-pool" # Note: See README.md for how to generate this secret. - name: "valkey-ca-certs" mountPath: "/etc/valkey-ca" readOnly: true - - name: "session-id-ca-pool" - mountPath: "/run/session-id-ca-pool" + - name: "actor-id-ca-pool" + mountPath: "/run/actor-id-ca-pool" readOnly: true ports: - containerPort: 443 @@ -189,11 +189,11 @@ spec: matchLabels: podcert.ate.dev/canarying: live path: trust-bundle.pem - - name: "session-id-jwt-pool" + - name: "actor-id-jwt-pool" projected: sources: - secret: - name: "session-id-jwt-pool" + name: "actor-id-jwt-pool" items: - key: "pool" path: "pool.json" @@ -205,11 +205,11 @@ spec: items: - key: "ca.crt" path: "ca.crt" - - name: "session-id-ca-pool" + - name: "actor-id-ca-pool" projected: sources: - secret: - name: "session-id-ca-pool" + name: "actor-id-ca-pool" items: - key: "pool" path: "pool.json" @@ -227,7 +227,7 @@ spec: matchLabels: app: ate-api-server --- -# 6. Expose the Session Assigner +# 6. Expose the Actor Assigner apiVersion: v1 kind: Service metadata: diff --git a/pkg/proto/ateapipb/ateapi.pb.go b/pkg/proto/ateapipb/ateapi.pb.go index ae7c136a4..3beca313d 100644 --- a/pkg/proto/ateapipb/ateapi.pb.go +++ b/pkg/proto/ateapipb/ateapi.pb.go @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// TODO: Here and everywhere, s/Session/Actor to align with the glossary. - // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11-devel @@ -2136,7 +2134,7 @@ type MintJWTRequest struct { Audience []string `protobuf:"bytes,1,rep,name=audience,proto3" json:"audience,omitempty"` AppId string `protobuf:"bytes,2,opt,name=app_id,json=appId,proto3" json:"app_id,omitempty"` UserId string `protobuf:"bytes,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - SessionId string `protobuf:"bytes,4,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + ActorId string `protobuf:"bytes,4,opt,name=actor_id,json=actorId,proto3" json:"actor_id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -2192,16 +2190,16 @@ func (x *MintJWTRequest) GetUserId() string { return "" } -func (x *MintJWTRequest) GetSessionId() string { +func (x *MintJWTRequest) GetActorId() string { if x != nil { - return x.SessionId + return x.ActorId } return "" } type MintJWTResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - // Session JWT. An OIDC Discovery-compatible JWT + // Actor JWT. An OIDC Discovery-compatible JWT // // Claims: // @@ -2211,7 +2209,7 @@ type MintJWTResponse struct { // // credential. Format // - // `app/${appid}/user/${userid}/session/${sessionid}`. + // `app/${appid}/user/${userid}/actor/${actorid}`. // - aud: Audience - a string identifying the service this token will be used // to authenticate to. // - nbf: Not Before - a numeric unix timestamp @@ -2220,8 +2218,8 @@ type MintJWTResponse struct { // - `ate.dev`: Ate/Substrate Extension - JSON object // - appID: (string) The Substrate App ID // - userID: (string) The Substrate User ID - // - sessionID: (string) The Substrate Session ID - SessionJwt string `protobuf:"bytes,1,opt,name=session_jwt,json=sessionJwt,proto3" json:"session_jwt,omitempty"` + // - actorID: (string) The Substrate Actor ID + ActorJwt string `protobuf:"bytes,1,opt,name=actor_jwt,json=actorJwt,proto3" json:"actor_jwt,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -2256,18 +2254,18 @@ func (*MintJWTResponse) Descriptor() ([]byte, []int) { return file_ateapi_proto_rawDescGZIP(), []int{35} } -func (x *MintJWTResponse) GetSessionJwt() string { +func (x *MintJWTResponse) GetActorJwt() string { if x != nil { - return x.SessionJwt + return x.ActorJwt } return "" } type MintCertRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - AppId string `protobuf:"bytes,1,opt,name=app_id,json=appId,proto3" json:"app_id,omitempty"` - UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - SessionId string `protobuf:"bytes,3,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + AppId string `protobuf:"bytes,1,opt,name=app_id,json=appId,proto3" json:"app_id,omitempty"` + UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ActorId string `protobuf:"bytes,3,opt,name=actor_id,json=actorId,proto3" json:"actor_id,omitempty"` // Request contains DER encoded bytes of a x509 certificate signing request. // The signer will ignore the contents of the CSR except to extract the // subject public key. @@ -2320,9 +2318,9 @@ func (x *MintCertRequest) GetUserId() string { return "" } -func (x *MintCertRequest) GetSessionId() string { +func (x *MintCertRequest) GetActorId() string { if x != nil { - return x.SessionId + return x.ActorId } return "" } @@ -2339,9 +2337,9 @@ type MintCertResponse struct { // Response contains a list of DER encoded certificates. The first entry is the // leaf certificate, and any remaining entries are intermediates in // leaf-to-root order. - SessionCertificates [][]byte `protobuf:"bytes,1,rep,name=session_certificates,json=sessionCertificates,proto3" json:"session_certificates,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + ActorCertificates [][]byte `protobuf:"bytes,1,rep,name=actor_certificates,json=actorCertificates,proto3" json:"actor_certificates,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *MintCertResponse) Reset() { @@ -2374,9 +2372,9 @@ func (*MintCertResponse) Descriptor() ([]byte, []int) { return file_ateapi_proto_rawDescGZIP(), []int{37} } -func (x *MintCertResponse) GetSessionCertificates() [][]byte { +func (x *MintCertResponse) GetActorCertificates() [][]byte { if x != nil { - return x.SessionCertificates + return x.ActorCertificates } return nil } @@ -2533,24 +2531,21 @@ const file_ateapi_proto_rawDesc = "" + "\tnamespace\x18\x01 \x01(\tR\tnamespace\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\"\x13\n" + "\x11DebugClearRequest\"\x14\n" + - "\x12DebugClearResponse\"{\n" + + "\x12DebugClearResponse\"w\n" + "\x0eMintJWTRequest\x12\x1a\n" + "\baudience\x18\x01 \x03(\tR\baudience\x12\x15\n" + "\x06app_id\x18\x02 \x01(\tR\x05appId\x12\x17\n" + - "\auser_id\x18\x03 \x01(\tR\x06userId\x12\x1d\n" + - "\n" + - "session_id\x18\x04 \x01(\tR\tsessionId\"2\n" + - "\x0fMintJWTResponse\x12\x1f\n" + - "\vsession_jwt\x18\x01 \x01(\tR\n" + - "sessionJwt\"\xa0\x01\n" + + "\auser_id\x18\x03 \x01(\tR\x06userId\x12\x19\n" + + "\bactor_id\x18\x04 \x01(\tR\aactorId\".\n" + + "\x0fMintJWTResponse\x12\x1b\n" + + "\tactor_jwt\x18\x01 \x01(\tR\bactorJwt\"\x9c\x01\n" + "\x0fMintCertRequest\x12\x15\n" + "\x06app_id\x18\x01 \x01(\tR\x05appId\x12\x17\n" + - "\auser_id\x18\x02 \x01(\tR\x06userId\x12\x1d\n" + - "\n" + - "session_id\x18\x03 \x01(\tR\tsessionId\x12>\n" + - "\x1bcertificate_signing_request\x18\x04 \x01(\fR\x19certificateSigningRequest\"E\n" + - "\x10MintCertResponse\x121\n" + - "\x14session_certificates\x18\x01 \x03(\fR\x13sessionCertificates2\x89\a\n" + + "\auser_id\x18\x02 \x01(\tR\x06userId\x12\x19\n" + + "\bactor_id\x18\x03 \x01(\tR\aactorId\x12>\n" + + "\x1bcertificate_signing_request\x18\x04 \x01(\fR\x19certificateSigningRequest\"A\n" + + "\x10MintCertResponse\x12-\n" + + "\x12actor_certificates\x18\x01 \x03(\fR\x11actorCertificates2\x89\a\n" + "\aControl\x124\n" + "\bGetActor\x12\x17.ateapi.GetActorRequest\x1a\r.ateapi.Actor\"\x00\x12:\n" + "\vCreateActor\x12\x1a.ateapi.CreateActorRequest\x1a\r.ateapi.Actor\"\x00\x12H\n" + @@ -2569,8 +2564,8 @@ const file_ateapi_proto_rawDesc = "" + "\x0eDeleteAtespace\x12\x1d.ateapi.DeleteAtespaceRequest\x1a\x10.ateapi.Atespace\"\x002N\n" + "\x05Debug\x12E\n" + "\n" + - "DebugClear\x12\x19.ateapi.DebugClearRequest\x1a\x1a.ateapi.DebugClearResponse\"\x002\x8c\x01\n" + - "\x0fSessionIdentity\x12:\n" + + "DebugClear\x12\x19.ateapi.DebugClearRequest\x1a\x1a.ateapi.DebugClearResponse\"\x002\x8a\x01\n" + + "\rActorIdentity\x12:\n" + "\aMintJWT\x12\x16.ateapi.MintJWTRequest\x1a\x17.ateapi.MintJWTResponse\x12=\n" + "\bMintCert\x12\x17.ateapi.MintCertRequest\x1a\x18.ateapi.MintCertResponseB9Z7github.com/agent-substrate/substrate/pkg/proto/ateapipbb\x06proto3" @@ -2684,8 +2679,8 @@ var file_ateapi_proto_depIdxs = []int32{ 14, // 46: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest 16, // 47: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest 35, // 48: ateapi.Debug.DebugClear:input_type -> ateapi.DebugClearRequest - 37, // 49: ateapi.SessionIdentity.MintJWT:input_type -> ateapi.MintJWTRequest - 39, // 50: ateapi.SessionIdentity.MintCert:input_type -> ateapi.MintCertRequest + 37, // 49: ateapi.ActorIdentity.MintJWT:input_type -> ateapi.MintJWTRequest + 39, // 50: ateapi.ActorIdentity.MintCert:input_type -> ateapi.MintCertRequest 9, // 51: ateapi.Control.GetActor:output_type -> ateapi.Actor 9, // 52: ateapi.Control.CreateActor:output_type -> ateapi.Actor 20, // 53: ateapi.Control.UpdateActor:output_type -> ateapi.UpdateActorResponse @@ -2700,8 +2695,8 @@ var file_ateapi_proto_depIdxs = []int32{ 15, // 62: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse 10, // 63: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace 36, // 64: ateapi.Debug.DebugClear:output_type -> ateapi.DebugClearResponse - 38, // 65: ateapi.SessionIdentity.MintJWT:output_type -> ateapi.MintJWTResponse - 40, // 66: ateapi.SessionIdentity.MintCert:output_type -> ateapi.MintCertResponse + 38, // 65: ateapi.ActorIdentity.MintJWT:output_type -> ateapi.MintJWTResponse + 40, // 66: ateapi.ActorIdentity.MintCert:output_type -> ateapi.MintCertResponse 51, // [51:67] is the sub-list for method output_type 35, // [35:51] is the sub-list for method input_type 35, // [35:35] is the sub-list for extension type_name diff --git a/pkg/proto/ateapipb/ateapi.proto b/pkg/proto/ateapipb/ateapi.proto index 873f994e9..8547286c0 100644 --- a/pkg/proto/ateapipb/ateapi.proto +++ b/pkg/proto/ateapipb/ateapi.proto @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// TODO: Here and everywhere, s/Session/Actor to align with the glossary. - syntax = "proto3"; package ateapi; @@ -367,12 +365,12 @@ message DebugClearRequest {} message DebugClearResponse {} -// SessionIdentity allows substrate workloads to exchange their +// ActorIdentity allows substrate workloads to exchange their // infrastructure-level credentials (k8s service account token, etc.) for a -// substrate session-level credential. A given substrate session might migrate +// substrate actor-level credential. A given substrate actor might migrate // between many different physical workers over the course of its lifecycle, -// whereas the session credential's identity will be stable for the life of the -// session. +// whereas the actor credential's identity will be stable for the life of the +// actor. // // This service requires authentication. You can authenticate with a Kubernetes // service account token in an `Authorization: Bearer` header, or you can @@ -381,16 +379,16 @@ message DebugClearResponse {} // upstream, but we will provide a polyfill based on Pod Certificates). // // The broker will check that the service credentials you authenticated with -// belong to a Pod that is currently mapped to the requested session in the -// session database. -service SessionIdentity { - // Request a Session Identity JWT. +// belong to a Pod that is currently mapped to the requested actor in the +// actor database. +service ActorIdentity { + // Request an Actor Identity JWT. // // To call this RPC, you must be authenticated as the Kubernetes Pod that is - // currently running the requested session. + // currently running the requested actor. rpc MintJWT(MintJWTRequest) returns (MintJWTResponse); - // Request a Session Identity Certificate. To call this RPC, you must have + // Request an Actor Identity Certificate. To call this RPC, you must have // authenticated with a client certificate, not a bearer token. rpc MintCert(MintCertRequest) returns (MintCertResponse); } @@ -400,11 +398,11 @@ message MintJWTRequest { string app_id = 2; string user_id = 3; - string session_id = 4; + string actor_id = 4; } message MintJWTResponse { - // Session JWT. An OIDC Discovery-compatible JWT + // Actor JWT. An OIDC Discovery-compatible JWT // // Claims: // @@ -412,7 +410,7 @@ message MintJWTResponse { // discovery documents. // * sub: Subject - a string expressing the identity carried in the // credential. Format - // `app/${appid}/user/${userid}/session/${sessionid}`. + // `app/${appid}/user/${userid}/actor/${actorid}`. // * aud: Audience - a string identifying the service this token will be used // to authenticate to. // * nbf: Not Before - a numeric unix timestamp @@ -421,14 +419,14 @@ message MintJWTResponse { // * `ate.dev`: Ate/Substrate Extension - JSON object // * appID: (string) The Substrate App ID // * userID: (string) The Substrate User ID - // * sessionID: (string) The Substrate Session ID - string session_jwt = 1; + // * actorID: (string) The Substrate Actor ID + string actor_jwt = 1; } message MintCertRequest { string app_id = 1; string user_id = 2; - string session_id = 3; + string actor_id = 3; // Request contains DER encoded bytes of a x509 certificate signing request. // The signer will ignore the contents of the CSR except to extract the @@ -440,5 +438,5 @@ message MintCertResponse { // Response contains a list of DER encoded certificates. The first entry is the // leaf certificate, and any remaining entries are intermediates in // leaf-to-root order. - repeated bytes session_certificates = 1; + repeated bytes actor_certificates = 1; } diff --git a/pkg/proto/ateapipb/ateapi_grpc.pb.go b/pkg/proto/ateapipb/ateapi_grpc.pb.go index 80b80091a..58a03b383 100644 --- a/pkg/proto/ateapipb/ateapi_grpc.pb.go +++ b/pkg/proto/ateapipb/ateapi_grpc.pb.go @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// TODO: Here and everywhere, s/Session/Actor to align with the glossary. - // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.6.1 @@ -733,20 +731,20 @@ var Debug_ServiceDesc = grpc.ServiceDesc{ } const ( - SessionIdentity_MintJWT_FullMethodName = "/ateapi.SessionIdentity/MintJWT" - SessionIdentity_MintCert_FullMethodName = "/ateapi.SessionIdentity/MintCert" + ActorIdentity_MintJWT_FullMethodName = "/ateapi.ActorIdentity/MintJWT" + ActorIdentity_MintCert_FullMethodName = "/ateapi.ActorIdentity/MintCert" ) -// SessionIdentityClient is the client API for SessionIdentity service. +// ActorIdentityClient is the client API for ActorIdentity service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // -// SessionIdentity allows substrate workloads to exchange their +// ActorIdentity allows substrate workloads to exchange their // infrastructure-level credentials (k8s service account token, etc.) for a -// substrate session-level credential. A given substrate session might migrate +// substrate actor-level credential. A given substrate actor might migrate // between many different physical workers over the course of its lifecycle, -// whereas the session credential's identity will be stable for the life of the -// session. +// whereas the actor credential's identity will be stable for the life of the +// actor. // // This service requires authentication. You can authenticate with a Kubernetes // service account token in an `Authorization: Bearer` header, or you can @@ -755,57 +753,57 @@ const ( // upstream, but we will provide a polyfill based on Pod Certificates). // // The broker will check that the service credentials you authenticated with -// belong to a Pod that is currently mapped to the requested session in the -// session database. -type SessionIdentityClient interface { - // Request a Session Identity JWT. +// belong to a Pod that is currently mapped to the requested actor in the +// actor database. +type ActorIdentityClient interface { + // Request an Actor Identity JWT. // // To call this RPC, you must be authenticated as the Kubernetes Pod that is - // currently running the requested session. + // currently running the requested actor. MintJWT(ctx context.Context, in *MintJWTRequest, opts ...grpc.CallOption) (*MintJWTResponse, error) - // Request a Session Identity Certificate. To call this RPC, you must have + // Request an Actor Identity Certificate. To call this RPC, you must have // authenticated with a client certificate, not a bearer token. MintCert(ctx context.Context, in *MintCertRequest, opts ...grpc.CallOption) (*MintCertResponse, error) } -type sessionIdentityClient struct { +type actorIdentityClient struct { cc grpc.ClientConnInterface } -func NewSessionIdentityClient(cc grpc.ClientConnInterface) SessionIdentityClient { - return &sessionIdentityClient{cc} +func NewActorIdentityClient(cc grpc.ClientConnInterface) ActorIdentityClient { + return &actorIdentityClient{cc} } -func (c *sessionIdentityClient) MintJWT(ctx context.Context, in *MintJWTRequest, opts ...grpc.CallOption) (*MintJWTResponse, error) { +func (c *actorIdentityClient) MintJWT(ctx context.Context, in *MintJWTRequest, opts ...grpc.CallOption) (*MintJWTResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(MintJWTResponse) - err := c.cc.Invoke(ctx, SessionIdentity_MintJWT_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, ActorIdentity_MintJWT_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } -func (c *sessionIdentityClient) MintCert(ctx context.Context, in *MintCertRequest, opts ...grpc.CallOption) (*MintCertResponse, error) { +func (c *actorIdentityClient) MintCert(ctx context.Context, in *MintCertRequest, opts ...grpc.CallOption) (*MintCertResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(MintCertResponse) - err := c.cc.Invoke(ctx, SessionIdentity_MintCert_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, ActorIdentity_MintCert_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } -// SessionIdentityServer is the server API for SessionIdentity service. -// All implementations must embed UnimplementedSessionIdentityServer +// ActorIdentityServer is the server API for ActorIdentity service. +// All implementations must embed UnimplementedActorIdentityServer // for forward compatibility. // -// SessionIdentity allows substrate workloads to exchange their +// ActorIdentity allows substrate workloads to exchange their // infrastructure-level credentials (k8s service account token, etc.) for a -// substrate session-level credential. A given substrate session might migrate +// substrate actor-level credential. A given substrate actor might migrate // between many different physical workers over the course of its lifecycle, -// whereas the session credential's identity will be stable for the life of the -// session. +// whereas the actor credential's identity will be stable for the life of the +// actor. // // This service requires authentication. You can authenticate with a Kubernetes // service account token in an `Authorization: Bearer` header, or you can @@ -814,104 +812,104 @@ func (c *sessionIdentityClient) MintCert(ctx context.Context, in *MintCertReques // upstream, but we will provide a polyfill based on Pod Certificates). // // The broker will check that the service credentials you authenticated with -// belong to a Pod that is currently mapped to the requested session in the -// session database. -type SessionIdentityServer interface { - // Request a Session Identity JWT. +// belong to a Pod that is currently mapped to the requested actor in the +// actor database. +type ActorIdentityServer interface { + // Request an Actor Identity JWT. // // To call this RPC, you must be authenticated as the Kubernetes Pod that is - // currently running the requested session. + // currently running the requested actor. MintJWT(context.Context, *MintJWTRequest) (*MintJWTResponse, error) - // Request a Session Identity Certificate. To call this RPC, you must have + // Request an Actor Identity Certificate. To call this RPC, you must have // authenticated with a client certificate, not a bearer token. MintCert(context.Context, *MintCertRequest) (*MintCertResponse, error) - mustEmbedUnimplementedSessionIdentityServer() + mustEmbedUnimplementedActorIdentityServer() } -// UnimplementedSessionIdentityServer must be embedded to have +// UnimplementedActorIdentityServer must be embedded to have // forward compatible implementations. // // NOTE: this should be embedded by value instead of pointer to avoid a nil // pointer dereference when methods are called. -type UnimplementedSessionIdentityServer struct{} +type UnimplementedActorIdentityServer struct{} -func (UnimplementedSessionIdentityServer) MintJWT(context.Context, *MintJWTRequest) (*MintJWTResponse, error) { +func (UnimplementedActorIdentityServer) MintJWT(context.Context, *MintJWTRequest) (*MintJWTResponse, error) { return nil, status.Error(codes.Unimplemented, "method MintJWT not implemented") } -func (UnimplementedSessionIdentityServer) MintCert(context.Context, *MintCertRequest) (*MintCertResponse, error) { +func (UnimplementedActorIdentityServer) MintCert(context.Context, *MintCertRequest) (*MintCertResponse, error) { return nil, status.Error(codes.Unimplemented, "method MintCert not implemented") } -func (UnimplementedSessionIdentityServer) mustEmbedUnimplementedSessionIdentityServer() {} -func (UnimplementedSessionIdentityServer) testEmbeddedByValue() {} +func (UnimplementedActorIdentityServer) mustEmbedUnimplementedActorIdentityServer() {} +func (UnimplementedActorIdentityServer) testEmbeddedByValue() {} -// UnsafeSessionIdentityServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to SessionIdentityServer will +// UnsafeActorIdentityServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ActorIdentityServer will // result in compilation errors. -type UnsafeSessionIdentityServer interface { - mustEmbedUnimplementedSessionIdentityServer() +type UnsafeActorIdentityServer interface { + mustEmbedUnimplementedActorIdentityServer() } -func RegisterSessionIdentityServer(s grpc.ServiceRegistrar, srv SessionIdentityServer) { - // If the following call panics, it indicates UnimplementedSessionIdentityServer was +func RegisterActorIdentityServer(s grpc.ServiceRegistrar, srv ActorIdentityServer) { + // If the following call panics, it indicates UnimplementedActorIdentityServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { t.testEmbeddedByValue() } - s.RegisterService(&SessionIdentity_ServiceDesc, srv) + s.RegisterService(&ActorIdentity_ServiceDesc, srv) } -func _SessionIdentity_MintJWT_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _ActorIdentity_MintJWT_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MintJWTRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(SessionIdentityServer).MintJWT(ctx, in) + return srv.(ActorIdentityServer).MintJWT(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: SessionIdentity_MintJWT_FullMethodName, + FullMethod: ActorIdentity_MintJWT_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SessionIdentityServer).MintJWT(ctx, req.(*MintJWTRequest)) + return srv.(ActorIdentityServer).MintJWT(ctx, req.(*MintJWTRequest)) } return interceptor(ctx, in, info, handler) } -func _SessionIdentity_MintCert_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _ActorIdentity_MintCert_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MintCertRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(SessionIdentityServer).MintCert(ctx, in) + return srv.(ActorIdentityServer).MintCert(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: SessionIdentity_MintCert_FullMethodName, + FullMethod: ActorIdentity_MintCert_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SessionIdentityServer).MintCert(ctx, req.(*MintCertRequest)) + return srv.(ActorIdentityServer).MintCert(ctx, req.(*MintCertRequest)) } return interceptor(ctx, in, info, handler) } -// SessionIdentity_ServiceDesc is the grpc.ServiceDesc for SessionIdentity service. +// ActorIdentity_ServiceDesc is the grpc.ServiceDesc for ActorIdentity service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) -var SessionIdentity_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "ateapi.SessionIdentity", - HandlerType: (*SessionIdentityServer)(nil), +var ActorIdentity_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "ateapi.ActorIdentity", + HandlerType: (*ActorIdentityServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "MintJWT", - Handler: _SessionIdentity_MintJWT_Handler, + Handler: _ActorIdentity_MintJWT_Handler, }, { MethodName: "MintCert", - Handler: _SessionIdentity_MintCert_Handler, + Handler: _ActorIdentity_MintCert_Handler, }, }, Streams: []grpc.StreamDesc{},