github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/docs/content/adr/001/_index.md (about) 1 +++ 2 title = "V2 Network Protocol" 3 toc = true 4 weight = 10 5 pre = "<b>1. </b>" 6 +++ 7 8 ## Background 9 10 ### Current State 11 12 The Choria V1 protocol requires x509, there is no other option. 13 14 Experience with `mcollective` showed that companies had little appetite to understand or use esoteric security protocols, even those based on sound industry standard cryptographic methods. Further most companies already had mature x509 infrastructure either standalone or part of systems like Puppet which made for an easy adoption path. 15 16 Choria therefor is built on a protocol that requires x509 semantics and supports nothing else: 17 18 * Every message is signed by a x509 key 19 * Every client-initiated message contains the x509 public key 20 * Servers listen on TLS using x509 public and private keys 21 * User identities are tied to the properties of the certificates 22 * User permissions and roles are tied to the identity of the certificate, very limited support for fine-grained roles 23 * All JWT files are signed by x509 keys 24 * Generally only RSA is supported 25 * mTLS is used to create a private network - requiring a purpose specific CA or intermediate CA in practice 26 * A local cache of certificates is used like a kind of safety check to catch credentials being re-issued 27 * Any NATS client connecting to Choria broker requires a cert/key/ca and do full mTLS 28 29 Choria supports a mode combined with the AAA Server where a user does not need her own x509 certificate but holds a JWT instead obtained from an SSO service. In this scenario the AAA Server still holds a x509 cert (called a privileged certificate) and is allowed to sign and encode requests on behalf of others (holders of a JWT) by using its x509 key pair to sign on behalf of the user. 30 31 ### Problem Statement 32 33 In practice this works well for most users, but those with very large or complex networks can run into problems either with corporate Certificate Authority policies or corporate CA configuration making it very hard to achieve a secure network with the facilities available. General CA infrastructure is also just getting a bit old and better alternatives exist. JWTs are now used pervasively in modern IT and the user based are more likely to accept their use for our needs. 34 35 We would like to explore, and enable, other use cases outside of server management such as IoT, purpose built backplanes, Kubernetes side cars and more, integration into Certificate Authorities in those cases is really problematic. 36 37 * x509 signatures are big and slow 38 * x509 certificates are also huge and these go with every request 39 * x509 certificate management, especially across multiple client machines is very difficult 40 * Dealing with short-lived (minutes) x509 certificates can be really hard 41 * Not all CAs have sane enrollment, some requires private keys to be copied around making them useless 42 * Newer technologies like ed25519 is attractive as they use small keys and signatures and can also do things like DH Key exchange 43 * Using ed25519 opens the possibility of using ssh keys as signing keys, something many users have requested 44 * Obtaining private CAs or intermediate CAs is often impossible forcing CA reuse and nullifying the usefulness of the mTLS security 45 * Verification of certificates happen during caching rather than a separate check, more importantly the cache is used often as a means of retrieving privileged certs and more by id 46 * The local cert cache is deeply embedded in the v1 protocol, but it's proven to be useless and most people disable its enforcing features - it cannot be disabled entirely 47 * As Choria have evolved we need a much more granular role based permissions on each connection - can they use streams, can they admin streams, can they make rpc requests etc 48 * More and more servers need to be able to make request either when publishing signed registration payloads or when interacting with Choria Services from within autonomous agents. With v1 protocol this was not possible. 49 50 ### Solution Overview 51 52 We will support an additional protocol, while maintaining v1 protocol, that will be based on JWTs signed using ed25519 that embed their public component in the signed JWT. 53 54 We have already done the work to design and incorporate the JWTs for clients and servers at the transport level but now need to move that work into the Choria protocol so clients can communicate with Choria without x509 certificates. 55 56 #### Transport Security 57 58 Transport security is primarily about how the packets between Choria Broker and Choria Client/Server are secured but touches a bit on how users with access to the NATS Server are limited to just their traffic. 59 60 ##### mTLS optional Chain of Trust for transport security 61 62 In a mTLS secured network trust is established by way of the CA signing all certificates and all parties verifying this fact. Both sides of the TLS connection will verify the other side to ensure its certificate is signed by a cached local CA chain. 63 64 This way there can be no untrusted middlemen or session hijacking in the network path. 65 66 In practice, in enterprise networks, there are many challenges: 67 68 * it's often highly desirable to be able to hijack connections, for example to audit that PII doesn't leave the legal jurisdiction it belongs in, many companies wish to disable the full mTLS while still maintaining strong identification of entities. 69 * it's also desirable to deploy Choria Brokers using websocket protocol and offload the TLS work onto a load balancer - this would be quite complex with the current model. 70 * most enterprise have policies making CA rotation necessary and quite frequent, this makes mTLS completely unworkable at scale. 71 * dropping mTLS, or not being able to do mTLS, would impact the strength of identity since we combine the transport and identity in one cert 72 * certificate enrolment is done poorly, there are few protocols like ACME in use in Enterprises, often they would design their own enrollment, and mostly it involves moving keys between machines and are very slow 73 74 So we will support verified or unverified TLS to the brokers, but clients and servers all must present a signed JWT when not in mTLS mode. This will split the identity from transport security and give people the choice to pick one without compromising the other. 75 76 Servers and clients will have: 77 78 * An ed25519 seed file example `server.seed` kept private and never transmitted over the network 79 * A JWT file that holds: 80 * the public key of the ed25519 seed 81 * an identity 82 * a private network ID derived from the identity or seed 83 * Standard items like expiry times etc 84 * Additional permissions to control access to broker subjects 85 * The JWT will be signed by a trusted ed25519 key 86 87 The broker will only allow connections that holds a valid, signed JWT where the signature is made using a trusted ed25519 key. 88 89 ##### Organization and Chained Issuers 90 91 Conceptually Choria Broker can separate connections into something called "accounts" in NATS terms, for Choria we call this an Organization. Today we support just one Organization - `choria` - but we will look to support more in future. 92 93 We will add a concept called an Organization Issuer that is a ed25519 key that must, on a basic level, sign all tokens. To facilitate separation of concerns in our centralized AAA mode the Issuer can delegate JWT issuing in a chain to downstream issuers. The tokens will validate as being signed by the issuer essentially. 94 95 We support storing the Organization Issuer offline in something like Vault and at the "AAA Login Server" level that issuing key can also be stored in a Vault like system. 96 97  98 99 Thus, we achieve the following chain of trust: 100 101 * We know the JWT was issued by a trusted issuer 102 * We verify the connecting server or client has the ed25519 seed that match the JWT because the broker force a [NONCE](https://en.wikipedia.org/wiki/Cryptographic_nonce) to be signed using the seed, the seed never traverse the network since the public part is embedded in the signed JWT 103 * The JWT tokens are therefor not bearer tokens and if they are stolen in-flight (remember no mTLS), one cannot connect with them or make any requests using them 104 * We have an identity that isn't tied to the common name of a cert and so is more fluid and adaptable 105 * The broker should support [denying all clients without JWTs](https://github.com/choria-io/go-choria/issues/1837) 106 107 In this way we can pick full mTLS when needed or JWT+ed25519 mode when needed and even mix and match the modes. 108 109 #### Reply Security 110 111 Reply security is a quite difficult problem to solve since every reply would need to be individually encrypted and decrypted - unlike transport security - this is very CPU intensive, so we have never really done it at scale. 112 113 Still, its highly desirable to hide replies destined for a specific user from other users, even those with access to the broker using their own JWT tokens. 114 115 Using the callerID as key we calculate a private inbox using the hex encoded `md5(callerID)`, we use this to construct reply subjects for all uses, even access to other subjects like the Streams API. 116 117 The broker will set up permissions ensuring that only the callerID can access replies. This way as long as there are unique callerIDs the replies from all systems are private. 118 119 We still do not encrypt the traffic in-transit (see point about PII and desired man-in-the-middle in Enterprises), but the replies are private to the user. 120 121 ``` 122 % sudo choria jwt client.jwt 123 ... 124 Private Network ID: 7419405695a186147a0de38f7e31a509... 125 ... 126 127 % choria req choria_util info --debug 128 DEBU[0000] Publishing message with reply to choria.reply.7419405695a186147a0de38f7e31a509.4e27ca6493cb4576bb78e90ea35df38c component=client 129 ``` 130 131 Here we can see the reply is set to match `<collective>.reply.<private network id>.<request id>`, the broker ensures the holder of this JWT cannot subscribe to other users replies. 132 133 To facilitate debugging users with the `OrgAdmin` permission, default not granted, on their tokens can view all replies. 134 135 #### Submission and Registration Data Security 136 137 As each server will have a ed25519 seed and a JWT embedding the public key we will support, optionally, signing Choria Submission and Registration messages. Signatures and Tokens will be included in headers. 138 139 This way should a system need to be created where the node will ask in an async manner for operations to be done against it, think host-detected issues triggering auto remediation, these messages originating from Submission will be signed. 140 141 Recipients of these messages can be certain that the message originated from a place that had access to the nodes private key. 142 143 See [#1873](https://github.com/choria-io/go-choria/issues/1873) 144 145 #### Identity 146 147 Identity primarily concerns Choria Requests, this is who is the one making the request for the use by AAA. 148 149 Traditionally this is extracted from the x509 certificate common name and have some dumb rules like `x.choria` or `x.privileged.choria` since x509 certificates don't really have a strong concept of boolean permissions. 150 151 This is awful and arbitrary, in the new model callers should be whatever they like and a flag on the JWT would identify it as privileged or not ([#1836](https://github.com/choria-io/go-choria/issues/1836)). 152 153 #### Caller Identity 154 155 Identity would always be extracted from the JWT of the final client. In the case of the AAA Service we would need to have the ability to include the client JWT as well as the signer JWT and the signature: 156 157 * When the signer JWT isn't set we ensure the client signed it. 158 * When the signer JWT is set we ensure the JWT has the right permission to sign others requests ([#1836](https://github.com/choria-io/go-choria/issues/1836)) 159 * The identity of the client JWT is used for the request 160 * We should be able to issue JWTs that can only be used in conjunction with an AAA server who signs their requests ([#1840](https://github.com/choria-io/go-choria/issues/1840)) 161 162 This would be the identity used in things like RBAC, Audit logs and more. 163 164 The broker might set the NATS user to the identity to assist with debugging. 165 166 #### Request Signatures 167 168 Today requests are signed by the x509/RSA key, we'd just sign it with the ed25519 seed instead. We would not support any form of server side cache. 169 170 Client JWTs will gain permissions that state they have fleet management access and, optionally, that fleet management access requires signatures. 171 172 ### Issuing JWT tokens 173 174 Traditionally you would use whatever your CA does for enrolling certificates and `choria enroll` might help you out if you're lucky to have a system that supports that. 175 176 For others, it would be up to the user to deliver the key, cert and ca to the right locations. 177 178 Having Server enroll separate from Client enroll is good, since its conceivable that those will be done in very different places and with different auth mechanisms. 179 180 #### Servers 181 182 Servers would get their JWT token from the Choria Provisioner, this is supported today and that supports setting permissions and more. The Provisioner would hold a JWT that is a Chain Issuer allowing it to sign JWTs for servers. 183 184 #### Clients 185 186 The current AAA Server should be extended to allow client enrollment, essentially this is already supported but there is no allowance for the client seed and new behaviors. The signing request should be extended with a signature made using the seed and the service should verify it - essentially same as the NONCE in the broker. 187 188 The AAA Service would support marking a user as standalone - he can make his own requests without AAA and has his own seed - or as requiring AAA service ([#1840](https://github.com/choria-io/go-choria/issues/1840)). He might have his own seed for signing the broker NONCE but cannot make RPC requests that were not signed by AAA service. 189 190 The AAA Login handler would hold a JWT that is a Chain Issuer allow it to sign JWTs for the clients and set policies and permissions. 191 192 The `choria jwt` command must also be able to issue client credentials. 193 194 Non Choria clients - like lets say a random node nats client - would need to get their hands on a JWT and seed as well, and they will have to connect with that. So there will have to be a way to enroll them, probably `choria jwt` or `choria login` with their user marked as being long term valid. 195 196 A final class of client is one that needs a short-lived permission to make a very specific request. Imagine some external orchestrator wants to invoke `choria req` or `choria kv` for a particular use. Ideally this external Orchestrator would be able to issue a JWT that would allow this to happen on any unix user. In this scenario `choria login` should be able to take a bearer token and present that to AAA service during `choria login`. The bearer token would be signed by the orchestrator and trusted by the AAA, the bearer token would be very short-lived and essentially single use. It will be used to facilitate login, Choria JWT creation and more so that the unix user would still have an ed25519 seed, but the Choria Client JWT would be custom and short-lived and restricted to purpose. 197 198 ### Federation 199 200 The federation system allows for moving requests and replies between uncoupled networks - essentially it's a protocol converter and gateway. 201 202 We would not in the past create federation that would cross CA boundaries as resigning all the requests and replies was impossible. With the new system the Federation Broker should be able to have a token with Authentication Delegation set and just re-sign the request en-route. This will allow it to do translation between networks and ID schemes. 203 204 ## Implementation 205 206 The protocol in Choria largely defines the bytes that traverse the network and couples quite tightly with the security providers for encoding, signing etc. 207 208 In the work to support v2 protocol we are also revisiting the design of the security plugins to be more generic and support non x509 key data. 209 210 ### Protocol 211 212 Layered protocols are used widely and bring with them a lot of flexibility in replacing some layer with another, for example: Ethernet -> IP -> TCP -> HTTP -> REST. 213 214 Choria has a similar design: 215 216 ``` 217 ( Transport 218 ( Secure Request or Reply 219 ( Request or Reply 220 ( Any bytes, often: RPC Request or Reply ) 221 ) 222 ) 223 ) 224 ``` 225 226 The efforts with v2 protocol is to replace Transport, Secure and Request/Reply with a new design, still based on JSON, but with better choices internally. 227 228 #### Request 229 230 A request holds the actual bytes being moved around and various claims about who is making the request. 231 232 | Field | v1 | Description | 233 |--------------|--------------|--------------------------------------------------------------------------------------------| 234 | `protocol` | `protocol` | The protocol version for this request `io.choria.protocol.v2.request` | 235 | `message` | `payload` | The arbitrary data contained in the request - like a RPC request - as base64 encoded bytes | 236 | `id` | `requestid` | The unique ID for the request, logged in AAA etc | 237 | `sender` | `senderid` | Typically the host that the request was initiated from | 238 | `caller` | `callerid` | Who made the request in the form of `kind=name` | 239 | `collective` | `collective` | Collective this request is targeted at | 240 | `agent` | `agent` | The agent this request is targeted at | 241 | `ttl` | `ttl` | How long this request is valid for | 242 | `time` | `time` | The unix nano time the request was created (unix time in v1) | 243 | `filter` | `filter` | The request filter | 244 245 #### Secure Request 246 247 A secure request wraps a `Request`, signs it and prevents any tampering with its content. 248 249 The signature - having been made with a private key - also conveys identity and confirms the claimed identity in the Request matches what cryptographic keys are held. 250 251 The main purpose of the Secure Request is to verify what can be verified about the Request and make immutable the rest. For example, we can't exactly verify the request time and TTL, but we can prevent it from being changed by an attacker by signing it. The caller in the `Request` is not verified in the `Request` since it's just an arbitrary string, however the Secure Request being signed using something unique to the caller, private key, confirms the information in the request. 252 253 So the end result is immutable, or at least tamper evident, metadata about a request and likewise the request payload or message. 254 255 | Field | v1 | Description | 256 |-------------|-------------|-------------------------------------------------------------------------------------| 257 | `protocol` | `protocol` | The protocol version for this secure request `io.choria.protocol.v2.secure_request` | 258 | `request` | `message` | The request held in the Secure Request as base64 bytes | 259 | `signature` | `signature` | A signature made of the request using the ed25519 seed of the caller | 260 | `caller` | `pubcert` | The JWT of the caller | 261 | `signer` | n/a | The JWT of the delegated signer, present when the AAA server is used | 262 263 #### Reply 264 265 A reply is created in response from a request and holds the request id in its payload 266 267 | Field | v1 | Description | 268 |------------|-------------|-------------------------------------------------------------------| 269 | `protocol` | `protocol` | The protocol version for this reply `io.choria.protocol.v2.reply` | 270 | `message` | `payload` | The arbitrary data contained in the reply - like a RPC reply | 271 | `request` | `requestid` | The ID of the request this reply relates to | 272 | `sender` | `senderid` | The host sending the reply | 273 | `agent` | `agent` | The agent the reply originates from | 274 | `time` | `time` | The unix nano time the request was created (unix time in v1) | 275 276 #### Secure Reply 277 278 A secure reply wraps a `Reply`, signs it and prevents any tampering with its content. The hash is a fast way to test validity of the reply. 279 280 Like the Secure Request the Secure Reply wraps the Reply in a way that makes it tamper evident via signatures and hashes. 281 282 The v2 protocol includes a signature and sender JWT however in practice this is mostly not going to be used as too costly on the receiver, however might be used for registration payload verification. 283 284 Signatures add quite a bit to the payload here, as the JWT has to be sent with, so it can be disabled using `plugin.security.choria.sign_replies` in the new security provider. 285 286 | Field | v1 | Description | 287 |-------------|------------|---------------------------------------------------------------------------------| 288 | `protocol` | `protocol` | The protocol version for this secure reply `io.choria.protocol.v2.secure_reply` | 289 | `reply` | `message` | The reply held in the Secure Request as base64 bytes | 290 | `hash` | `hash` | A sha256 of the reply | 291 | `signature` | n/a | A signature made using the ed25519 seed of the sender | 292 | `sender` | n/a | The JWT of the sending host | 293 294 #### Transport 295 296 The transport packet is the last layer that gets sent over NATS, it holds no message specific data. 297 298 | Field | v1 | Description | 299 |--------------|--------------|------------------------------------------------------------------------------| 300 | `protocol` | `protocol` | The protocol version for this transport `io.choria.protocol.v2.transport` | 301 | `data` | `data` | The payload to be transport, a Secure Request or Secure Reply base64 encoded | 302 | `headers` | `headers` | Optional headers | 303 304 Headers: 305 306 | Field | v1 | Description | 307 |--------------|--------------|--------------------------------------------------------------------------| 308 | `reply` | `reply-to` | A transport specific response channel for this message, used in requests | 309 | `sender` | `mc_sender` | The host that sent this message | 310 | `trace` | `seen-by` | A trace of host/broker pairs that the message traversed | 311 | `federation` | `federation` | Headers to assist federation | 312 313 Federation: 314 315 | Field | v1 | Description | 316 |-----------|------------|-------------------------------------------------| 317 | `request` | `req` | The request ID a federated message belongs to | 318 | `reply` | `reply-to` | The original `reply` before federation | 319 | `targets` | `targets` | The identities who the federated message is for | 320 321 ### Chained Tokens Verification 322 323 We created a Chained Token system in [#1900](https://github.com/choria-io/go-choria/issues/1900) that allows a Organization Issuer to delegate Client and Server creation to Chained Issuers. 324 325 From a usage perspective you can say `tokens.ParseClientIDToken(t, pubk)` where the public key is the public part of the Organization Issuer, even when the token `t` is signed by a Chain Issuer. The intention is to make the configuration of a chain much easier, you only have to configure the issuer for an Organization. 326 327 Additionally the expiry of the Chain Issuer is encoded in the token, if the issuer expires first the issued token is also considered expired. 328 329 The way this is achieved is with a series of claims and signatures as described here: 330 331 The Organization Issuer for an Organization is simply an `ed25519` key for the moment. If that Org Issuer is just signing some client, server or provisioner nothing special is done, it's just signing a JWT like normal. 332 333 However if the Org Issuer wants to create a token that can sign other tokens additional information is added a Clent token, it's called the **Chain Issuer**: 334 335 ```json 336 { 337 "iss": "I-514969e316eb4a7146b8066feb6af5dbc05da0965ec57c9d3a7d3299d5d98fec", 338 "jti": "0ujsswThIGTUYm2K8FjOOfXtY1K", 339 "ou": "choria", 340 "public_key": "bd2588d3dc309d536461caa11c0d6f639e89d7a09dc43eae052f3fb32e2d8687", 341 "purpose": "choria_client_id", 342 "tcs": "3f815723734c78ceaba5fb506347565f85fe2a0334c038ba2370c7f53f35e6c7c75ed3e95b531b6049426638201c39639dbf9b711fba5d866e7e3e30be02b401" 343 } 344 ``` 345 346 * `jti` is a unique ID for this token. It's a [kskuid](https://github.com/segmentio/ksuid), the time component must match the issued at time 347 * `iss` field indicates it is signed by a Issuer with public key `514969e316eb4a7146b8066feb6af5dbc05da0965ec57c9d3a7d3299d5d98fec`. 348 * `public_key` is the public part of the ed25519 seed for the Chain Issuer `aaa_chain_delegator` 349 * `tcs` is a signature made of `[chain issuer id].[chain issuer public key]` using the Org Issuer private key, in other words `sig("0ujsswThIGTUYm2K8FjOOfXtY1K.bd2588d3dc309d536461caa11c0d6f639e89d7a09dc43eae052f3fb32e2d8687", orgIssuerPrik)` 350 * The Chain Issuer JWT is signed by the Organization Issuer 351 352 This way we can verify that the Chain Issuer comes from the Issuer both by verifying the signature but also we have a piece of information that cannot be changed down the line (the `tcs`, signed by the Org Issuer key) which we will see again later. 353 354 In code this information, signatures etc can all be added using `chainIssuer.AddOrgIssuerData(issuerPrik)`, with this added the token `chainIssuer` can issue other tokens. For a possible future integration with systems like Vault we would call out to the Vault API to sign the `tcs` plain text and then sign the token, hence the Organization Issuer private key never needs to leave Vault. 355 356 Now when the Chain Issuer wants to issue a new Client or Server token additional information is again added: 357 358 ```json 359 { 360 "callerid": "up=rip", 361 "iss": "C-0ujsswThIGTUYm2K8FjOOfXtY1K.bd2588d3dc309d536461caa11c0d6f639e89d7a09dc43eae052f3fb32e2d8687", 362 "issexp": 1700153647, 363 "jti": "b2375f965abe4bfbaf131b585cf5e1a1", 364 "ou": "choria", 365 "public_key": "676d07de6721ee396754d4e4d5fa4ee2b59a6f3b8208e760ca614bc66000e740", 366 "purpose": "choria_client_id", 367 "tcs": "3f815723734c78ceaba5fb506347565f85fe2a0334c038ba2370c7f53f35e6c7c75ed3e95b531b6049426638201c39639dbf9b711fba5d866e7e3e30be02b401.a9da5f3946c1b472f1c886912bfe5559f261e4663016846e231095bd2e16a8a253657196a5c17231fb095bc3a2d1e89e1edaddcec35dd050303e5d9cda968a04" 368 } 369 ``` 370 371 * `jti` is a unique id for this token 372 * `iss` indicates a Chain Issuer with token ID (`jti`) `0ujsswThIGTUYm2K8FjOOfXtY1K` issued this token and his public key is `bd2588d3dc309d536461caa11c0d6f639e89d7a09dc43eae052f3fb32e2d8687` (the one from the previous example) 373 * `issexp` indicates when the Chain Issuer expires 374 * `tcs` is made up of first creating `sigdata` `[client token jti].[chain issuer tcs]` and then combining that `[chain issuer tcs].[sig(sigdata, chainIssuerPrik)]` 375 376 This way we can, given the signed Client token and the Org Issuer Public key, validate by going backwards over these claims: 377 378 1. Extract the Chain Issuer `tcs`, `public key` and `id` from `iss` and `tcs` 379 2. Verify the Organization Issuer signed the `tcs` of the Chain Issuer in this token, which also verifies the public key in the issuer 380 3. Verify the `tcs` signature part of the Client using public key of the Chain Issuer 381 4. Verify the expiry of the Chain Issuer 382 383 ### General Improvements 384 385 The security plugins handle signing, encoding, extracting of IDs and validating signatures. The current security plugins are all implemented around x509. 386 387 We will make some general improvements, rename some functions and add a few bits to the interface, detail to be discovered during implementation. 388 389 * Move the API to `[]byte` based API [#1844](https://github.com/choria-io/go-choria/pull/1844) 390 * Remove some string orientated security apis [](https://github.com/choria-io/go-choria/pull/1843) 391 * Make the JWT authoritative for the secure channel name so we can stop using md5 392 * Develop a tool that can decode and dump/view network packets [#1484](https://github.com/choria-io/go-choria/pull/1848) 393 * The entire concept of the cache to be removed [#1842](https://github.com/choria-io/go-choria/pull/1842) 394 * Default collective when v2 is used will be `choria` [#1885](https://github.com/choria-io/go-choria/pull/1885) 395 * Submission can sign messages [#1873](https://github.com/choria-io/go-choria/issues/1873) 396 * The protocol code should be instances not a singleton so each can have unique contexts and logging 397 * Stronger AAA interactions by signing NONCE like data in login and sign requests 398 * Potentially entirely remove the concept of Trusted Signers that was a mid term stop gap till this work is complete, only used by 1 users as far as we are aware