Nile is a transport-agnostic message integrity and security implementation. It is designed to act as the proving grounds for a protocol ensuring guaranteed message integrity between services in a micro-service environemnt, regardless of communication method. The name refers to the Nile river as a singluar shipping lane, representing this protocol's use of a singular message channel.
This project is still under development and brainstorming, and is likely to change dramatically. Constructive input is welcome and appreciated!
In a microservice environment, many services are likely not exposed to the public internet. Communication between those services and the public services is not always handled over https, due to the common practive of terminating https connections at the load balancer. However, there is still a need for trust between these services. The goal here is to establish a protocol for trusted communication which can be sent and received over http, https, grpc, ipc, websockets, etc. The current method for doing so using JSON Web standards, via the jose
library.
- Two or more services are running in a cluster, and each has been assigned an
id
and a keypair (current implementation uses ECDSA, but RSA support is planned as well) - Both services register their public key in
JWK
format with aPhonebookService
. By default, this is running alongside the first service, but it can also be run as a separate service, and use shared storage (like redis), or some decentralized consensus service. Registration is described in detail later. - When service
Alice
wishes to send a message to serviceBob
,Alice
calls the phonebook service to getBob
's public key. Alice
serializes her message, and encrypts it in JWE format using that public key.- The resulting
JWE
string is treated as the body of aJWS
, which is then signed usingAlice
's private key. - The
JWS
string returned from that process is sent toBob
over the communication protocol of choice. This can be nearly anything which allows strings to be sent, but MUST also allow includingAlice
's id alongside the signed message. Bob
receives the message fromAlice
with her id included.Bob
looks up the public key registered to her id.Bob
uses that public key to verify the signed message is in-fact sent byAlice
- The message is decoded and the internal
JWE
is decrypted usingBob
's private key.
By using both Signing and Encrypting, Bob
can be sure the message is from a trusted sender, and unmodified before decrypting. By using asymmetric encryption on the body, Bob can be sure no other listeners could read the message in-flight. These combined allow complete trust between services.
note: there is debate on whether the message should be signed before or after encryption. It is possible the order will be reversed in the near future
The phonebook service provides truly public listings of registered keys. Acceptance into the phonebook requires proof-of-ownership of both keys in the keypair. This helps to prevent impersonators or man-in-the-middle attacks.
To register a public key, you must provide to the phonebook an id
representing your service, and a JWS
containing your public key and thumbprint, signed using the corresponding private key. The phonebook will decode the JWS
in an untrusted manner, by base64 decoding the payload portion of the string. From that untrusted payload, it will read the public key, and attempt to use it to verify the original JWS
. If the signature is valid, the service knows the sender controls both that public key, and the corresponding private key. The key and a calculated thumbprint are stored in the phonebook for retrieval by other services.
In the base library (this repo), two implementations of the phonebook service are planned:
- The
InMemoryPhonebook
- This is the default phonebook implementation, and it stores all its known keys in-memory on the running host. This host-service could then be used by other services. FileSystemPhonebook
- Similar to theInMemoryPhonebook
, this runs on the local host, but saves and loads its data to the filesystem via a configurable filepath. This allows registered keys and known hosts to persist across service restarts.
Other libraries will be created to add additional implementations. a RemoteHttpPhonebook
(which gets data from another running phonebook via http), and RedisPhonebook
(which utilizes a shared redis store for keystorage) are already in the works.
- Create method for generating
JWK
s - Create methods for computing signatures
- Create methods for encrypting data
- Add a manager for a service's own keypair
- Define models for messages
- Define dataflow
-
InMemoryPhonebookService
-
FileSystemPhonebookService
- Create express/node middleware
- Write tests for various services
- Evaluate security of approach