-
-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: remote signing server and signature generalization #278
base: master
Are you sure you want to change the base?
Conversation
Replaces #228, I need to fix more conflicts and it should be good. |
80782c0
to
5dad068
Compare
I converted this to a draft since it depends on your fork. |
server.wait_for_open_port(9999) | ||
# Perform a switch to the remote configuration | ||
# and contact the server to get the right bootables. | ||
with subtest("Activation will request for remote signing"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means the server has to be available at the time re-building. This probably won't scale well but should be good enough for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, why wouldn't it scale well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the server is unavailable at the time of re-build? Does the re-building just fail? Do you want to add client-side retries? None of the solutions I can think of are super elegant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The normal person usecase would be:
I have a dozen of machines and they all have Secure Boot, I'd like to rebuild switch without all of them having access to the private key, I can just contact my secure server with TPM2 or HSM who has the machinery to perform secure signatures and send it my stuff its way.
If my secure server is down, I cannot sign my new binaries.
What is this really saying is that remote secure signing is load bearing and you need high availability if you don't want to fail rebuilding your system in those scenarios.
High availability can be facilitated on our side by having multiple fallbacks we can try in a certain order, e.g. remote secure signing (convenient, fast, secure!) and then the fallback is you pull your Yubikey and sign it on the "field recovery" certificate or whatever.
There will be, once those PRs land, a whole discussion on how do you seriously manage this at scale.
lanzasigndCrane = buildRustApp { | ||
pname = "lanzasignd"; | ||
src = craneLib.cleanCargoSource ./rust/tool; | ||
doCheck = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should have at least some rudimentary unit/integration tests for the server as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ack
|
||
/// Verify the signature of a PE binary, provided as bytes. | ||
/// Return true if the signature was verified. | ||
fn verify(&self, pe_binary: &[u8]) -> Result<bool>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a little odd that the Signer
trait can also verify.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can make it like signature
and derive a VerifyingKey
handle and you can call verify on that but it seems like overengineering to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that'd be overengineering. Is there a higher-level concept that encapsulates both verifying and signing? Not a big issue if we keep the Signer terminology and just add a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A notary?
…t packages Now, it is possible to build any package of the workspace in a fine grained fashion.
We want here to capture the required data to assemble a stub, here is a partial structure modulo ESP generation paths. Other pieces of code can consume this structure, validate it before passing it to the PE assembler and the signer. We convert everything into owned structures because we cannot really do deserialization in any context with lifetimes going around, but, allocations are generally very cheap in this context.
In order to offer more flexible signature mechanisms in lanzaboote, we need to take a step back and offer a general PE signature trait. After this, we will be able to plug various different implementations.
5dad068
to
1020a04
Compare
This is not dependent on a fork anymore, now. |
Remote signing enables a user to request for: - PE signature of a given store path, which is assumed to be available on the server side - PE signature oi a stub given by its parameters, which are assumed to be analyzable on the server side (i.e. computing hashes is possible.) - Verifying if a PE signature is correct according to PE signatures and Secure Boot policy
1020a04
to
d617150
Compare
It is now possible to use remote signature inside lzbt-systemd.
This is an example server to perform remote signatures based on stub parameters provided.
Our lanzaboote integration tests are getting more and more sophisticated and ambitious. Let's extract them into a "lanzalib", so they can be used with multiple backends.
We build lanzasignd now as part of the flake as an additional software we provide.
Introduces the Secure Boot remote signing server for NixOS.
Lanzaboote boot module now supports using a potential remote signer server, but this support is limited to the lanzaboote bootables and not the fwupd ones.
A simple test harness for remote signatures with lanzasignd.
We didn't test if there *was* a signature, idempotency of removal of signatures (i.e. removing an non-existent signature is the identity operation) could fool us into believing we had a signed thing then not signed.
This is relevant for a remote signer who relies on the existence of store paths remotely, for example.
We fabricated a lot of initrds which were exactly the same as the one in our store when we had no initrd secrets. This ends this practice.
personal todo: - returns stub parameters in the toplevel setup - verify paths for local keypair - build and sign a stub, verify it using the API, verify it locally (?) - build a stub, sign a "store path" (actually a temporary location on the same system), verify it using the API - sign a random file, verify it using the API
d617150
to
8d18d19
Compare
Personal TODO and expectations for reviewers:
@nikstur Do you have anything else you would like me to address for this? |
Given that this PR is currently gigantic and you say it consists of four distinct parts, can we possibly split it in multiple PRs for review? From my perspective we are also missing overview documentation here. |
Sure! |
This PR is composed of ~four changes:
This enables moving the local signature to another server… or even maybe a hardware security token!
In the future, the server can ask for attestations or any kind of things to give the signed stub.
Note
Initrd secrets are not supported by the remote signer
This is out of scope for this PR and will probably not supported as I plan to bring systemd credentials
first inside of NixOS and remove the legacy initrd secrets which are a broken feature.
What were alternatives?
Therefore, initrd secrets will NOT work with the remote signer.