feat: remote signing server and signature generalization #278
No reviewers
Labels
No labels
bug
dependency
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
review-next
security
stub
tool
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: raito/lanzaboote#278
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "signing-client"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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.
Replaces #228, I need to fix more conflicts and it should be good.
I converted this to a draft since it depends on your fork.
@ -200,3 +223,4 @@
checks =
let
nixosLib = import (pkgs.path + "/nixos/lib") { };
lanzaLib = import ./nix/tests/lib.nix {
We should have at least some rudimentary unit/integration tests for the server as well.
These options will need a
defaultText
again otherwise the manual generation will cry again.@ -0,0 +16,4 @@
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"):
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.
We don't need these dependencies here as we don't have tests, right?
Wouldn't
/sign/stub
and/sign/store-path
be cleaner?This should be an optional depedency guarded by a compile time flag.
I'd argue for keeping the future design parts to a minimum as they don't age well.
@ -0,0 +1,12 @@
# Signatures capabilities of Lanzaboote
Currently, lanzaboote can perform signatures of PE binaries based on local keypairs present on disk.
Isn't the whole point of the PR that we can now also use keys from the remote server? ^^
These belong at the very top of the file.
@ -0,0 +19,4 @@
/// 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>;
It's a little odd that the
Signer
trait can also verify.@ -0,0 +16,4 @@
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"):
Hm, why wouldn't it scale well?
@ -0,0 +1,12 @@
# Signatures capabilities of Lanzaboote
Currently, lanzaboote can perform signatures of PE binaries based on local keypairs present on disk.
Yes, this is the whole point. But this is in addition to the old capabilities?
@ -0,0 +19,4 @@
/// 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>;
I can make it like
signature
and derive aVerifyingKey
handle and you can call verify on that but it seems like overengineering to me.True!
Right.
@ -0,0 +19,4 @@
/// 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>;
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.
@ -0,0 +16,4 @@
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"):
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.
@ -0,0 +19,4 @@
/// 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>;
A notary?
Ack
@ -200,3 +223,4 @@
checks =
let
nixosLib = import (pkgs.path + "/nixos/lib") { };
lanzaLib = import ./nix/tests/lib.nix {
Ack
@ -0,0 +16,4 @@
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"):
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.
Yep
Right, let's do that.
This is not dependent on a fork anymore, now.
I did something, let me know how you like it.
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!
Pull request closed