Over the years, I’ve borrowed and invented a number of design patterns for projects of all kinds. Most, if not all, were doubtlessly already invented and used, but mostly I didn’t know that then. Most of my uses of these patterns are at least 15 years ago, often 20, but I’m seeing more and more of them appear in modern frameworks and methodologies. So this is my way of saying, “I told you so”, which is vaguely satisfying. To me.
Forgive the names; I have a hard time coming up with suitable labels for them.
The Blackboard architecture is well-known. Or should be, except it seems I always need to explain it when it comes up. It has a lot of great aspects and results in effective and extremely decoupled designs. I’ll most certainly come back to it several times.
A blackboard is a shared data source. Some processes write messages there, while other processes read them. The different processes never need to talk to each other directly or even know of each other’s existence.
From this flows a number of advantages, a few of which are:
- Different cooperating services can be based on entirely different languages and platforms.
- The interaction is usually one way (compare to Facebook’s Flux and React), greatly simplifying interactions.
- If done right, the data structures are immutable, elimination contention problems.Receiving messages
Hop, skip, and jump
Let’s get to my first blackboard-based pattern, namely how to protect a front-end machine from compromise. In this design, the front-end machine is an Internet facing computer receiving medical documents from a number of clients around the net. The documents arrive individually encrypted using the server’s public key. The front-end machine is assumed to be hacked sooner or later and we don’t want such a hack to lead to the ability of the hacker to get at decrypted documents or other secrets.
So, what we do is we let the front-end machine take each received and encrypted message and store it in an SQL database located in its own network segment. The message ends up in a table that only holds encrypted messages, nothing else.
Another machine on that protected network segment picks up the encrypted messages from the database, decrypts them, and stores the decrypted messages in another table.
The “front-end” machine is exposed to the internet, so let’s assume it is completely compromised. In that case, the hacker has access to all the secrets that are kept on that machine and has root. This would allow the hacker to do anything on that machine that any of my programs are allowed to do.
The first role of the front-end machine is to authenticate clients that connect. We can safely assume that the hacker won’t need to authenticate anymore.
The second role of the front-end machine is to receive messages from the client. These messages are then sent on to the database through a firewall that only allows port 1433 to connect to the database. The login to the database for the front-end machine is kept on the front-end machine so the hacker can use that authentication. However, the only thing this user is permitted is access to a number of stored procedures tailored specifically to the needs of the front-end. Among these stored procedures, there are procedures to deliver messages to the database, but not much more. There is most definitely no right granted for direct table access. In other words, the hacker can deliver messages to the incoming message table, but nothing else.
Behind the firewall there is another machine that has no connection to anything except the database. That machine has access to a small number of stored procedures tailored for its use, among which are procedures to pick up new incoming messages and deliver decrypted messages back to the database.
These crypto servers first verify that the message it picks up from the database carries a valid digital signature from a registered user system, and only then does it decrypt the message with its private key. If the hacker on the front-end had delivered fake messages, these would be detected during signature verification and discarded.
With this design, the hacker on the front-end has just a very narrow channel through which to jump from the front-end to the database, namely through the port 1433 and the SQL server software itself. But let’s assume he succeeds, somehow. If we’re really paranoid, we’d split the database into two instances on different machines, completely isolated from each other and only bridged by the crypto servers as in the next image.
To get at the plain text content of the messages, the hacker in this case, if coming from the internet at least, needs to:
- compromise the front-end
- crawl through 1433 and compromise the database (or compromise the firewall, then the database server)
- via a tailored message, compromise the crypto routines on the crypto server
- get at the secure database
The crypto server does not have any communication to the internet whatsoever, so even if it ever got compromised, it could only be controlled through messages passing through the database, and would need to exfiltrate that same way. Not impossible, but hardly easy, either. The hacker would probably choose some other way to get at the secure database.
So, what about outgoing?
The outgoing messages follow the exact opposite path. Do I really have to draw you a picture?