In this post I'm going to go over the design a bit and some of the implementation I did yesterday. But first some things of note:
Questionable requirements
I think I still got a bit too much into my idea of what a secure form processing service will look like in my requirements. Two important examples are:
- The service shall encrypt recipient data at rest.
- The service shall encrypt all communications.
There are two very important security requirements for anything you actually put out there as a service. That's my opinion anyway and I do believe these are also pretty much verbatim out of OWASP. But should this service be responsible for this?
The answer is actually a very certain, "Absolutely not!"
This should be done by the operating/init system in the first case and by a proxy like traefic, nginx, or caddy in the second.
I've actually seen this mistake happen before and I just repeated it. Requirements to encrypt this or that got written in stone and then the implementation ended up being an utterly stupid response just to fulfill a requirement that maybe should not have been there to begin with.
If I were only using all of my "Design Manual" to help myself in creating the design, and yes I find all that diagram nonsense helpful, then I wouldn't bother going back and fixing this. I need to though. These requirements cannot stand as is and I intend a complete, coherent work package or as close as I can get without being reviewed (though good review is desired).
In a real SDLC, and especially one that needs to be compliant with 62304, 13485 and others, I would need to make sure this was traced in some way. This means that the reason why I was making the change is documented, what the actual change was, and that this change was approved all needs to be somewhere. The best way to do this is actually with an issue managment system that tracks an issue from creation, through commenting, approval, and to final resolution and acceptance.
In my final goal for my own process around all this these tickets are in git with the code. This is so the whole project everything is in one database and multiple forms of documents can be produced from it. There are projects that could form the basis of this such as git-bug and radicle that could help here. I may go ahead and pick up git-bug today to fix this problem just to have that record to work with even if it's not in perfect form--because I don't even know that that is yet.
What I need for these requirements is not part of the implementation but part of the deployment and thus the documentation. So there needs to be something to include those things because THAT is what I actually want: a documented (and hopefully scripted) process to delpoy the thing in a secure manner that encrypts data at rest and encryts traffic in/out of system nodes. I also need to add these deployment components to my architecture design.
Design
I worked on documenting a design that responded to requirements. It's only the very upper layers of architecture and process description that would form the documentation needed for a non-safety critical piece of medical software. You are expected to create a more detailed design but it doesn't need to be documented and submitted.
That's the idea I have anyway. I've seen some of this process work and read a great deal about it but some of my involvement was further away and the certifications I actually saw completed were relatively easy to get and not "medical grade" such as a CE mark.
The design I have to date is here. You'll note it's missing a response to one of the two requirements I flagged. The response I did for the other is flawed I think and should instead do the decryption in init and then pass the decrypted data to the service. I did consider that this means the service can't load the config in protected memory or something (with a crypt library maybe) but I think maybe that level of security here is unwarranted and impractical and may not even do anything beneficial. Deployment can then use an encrypted partition and/or some other secret management like maybe agenix.
Planning
I made a set of diagrams to help me plan out the project. I hope it's fairly accurate and adequately covers the documentation requirements I have set for myself, but it's possible that part could push me over. The dependency relationships between tasks already broke down considerably when it came to implementing but I believe everything is accounted for. Time will tell.
I'm tracking progress in that page in the design document. This is a stupid and pointless way to do this but I wasn't going to use ticketing. I may have changed my mind though due to wanting to do the tracing of change reason and to experiment with git-bug (I have to be very weary here because I get distracted into these side things easily). With that in mind it could be easier and better to generate this sort of documentation out of that system. This is what the Tidepool Open Source QMS does for a lot of things--they generate many of their submitted documents from their JIRA issue system and you can see this in their SOPs.
The plan has me creating a bunch of test support code first and a skeleton service. The system includes a way to build a fake internet on the test system and perform automated tests with various environment and service setups. It's actually pretty amazing how easy this part is going to be through modern tooling. In the past this sort of thing would have been more difficult and maybe require a cluster of physical computers. I've already got a lot of it running in docker.
Next: Implementation
I've actually made some serious progress, but I don't like to have partial commits and I didn't quite finish yesterday. So you can't see it yet. But...
I did want to do this in nix or guix and may spend time on that if I have time, but decided to go with docker images for now. It's lighter and simple and I know a lot more about how to do it already. It might be better to use podman but I need to install it better in nix and don't want to mess with it right now. It makes little practical difference and will be easy to switch later.
What I have so far is a script that:
- creates a root CA key and self-signed certificate
- [temporary] creates a test server key and certifies it
- creates a docker image that includes the root CA cert in its ca-certificates
- creates a version of the nginx image that publishes to ssl and uses the test server key by default
I then have a couple compose setups that use dnsmasq and a private network with combinations of additional images that let me:
- verify I can make a private internet where I can lie about domain resolution.
- verify my base image correctly accepts server certificates signed by the CA root.
From here I intend to wire up my own ACME server to make dealing with the CA something I don't really have to think much about. This will be a fake Let's Encrypt to automatically get certificates.