Skip to content
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

add option lanzaboote.generateKeysIfNotExist #384

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

kuflierl
Copy link
Contributor

@kuflierl kuflierl commented Jul 31, 2024

generateKeysIfNotExist generates the PKI bundle if it doesn't already exist.

This is useful for single command setups by eliminating the need for running imperative commands before a reinstall or first-install.

Potential things to work on:

  • Ensuring certain access privileges on generated files
  • Adding a pretty loud warning into the description about the potential dangers
  • Adding a pretty loud warning into a read-me file that is copied into the keys folder about the potential dangers of messing with it without a backup
  • Switch to lib.getExe to find the executable (depends on Minor coding style fix: lib.getExe instead of ${bin}/bin/bin #391)

generateKeysIfNotExist generates the PKI bundle if it doesn't already exist
@kuflierl
Copy link
Contributor Author

I suspect the 2 failed checks are unrelated to my change...

Copy link

@Pandapip1 Pandapip1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple nits

nix/modules/lanzaboote.nix Outdated Show resolved Hide resolved
${optionalString cfg.generateKeysIfNotExist ''
if [ ! -f "${cfg.privateKeyFile}" ]; then
mkdir -p ${cfg.pkiBundle}
${sbctlWithPki}/bin/sbctl create-keys \

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
${sbctlWithPki}/bin/sbctl create-keys \
${getExe sbctlWithPki} create-keys \

Copy link
Contributor Author

@kuflierl kuflierl Aug 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking up lib.getExe and verifying that sbctl does provide mainProgram I do believe that your change makes sense.

I am unsure if I should forego the precedent coding style in this file. May need an extra PR to fix.
Opinions?

@RaitoBezarius
Copy link
Member

This method of key generation should really not be used and be replaced by #229.

@kuflierl
Copy link
Contributor Author

kuflierl commented Aug 21, 2024

This method of key generation should really not be used and be replaced by #229.

Auto generation of secrets at first start is something many packages including openssh do. Most of the time a system administrator doesn't really have a need for the secrets outside of the machine that actually uses them. In those cases it is simply easier to let the server auto-generate the secrets.

Wait, how is this replaced by #229? #229 doesn't provide any key generation capabilities as far as i can see. Please Elaborate @RaitoBezarius

@RaitoBezarius
Copy link
Member

This method of key generation should really not be used and be replaced by #229.

Auto generation of secrets at first start is something many packages including openssh do. Most of the time a system administrator doesn't really have a need for the secrets outside of the machine that actually uses them. In those cases it is simply easier to let the server auto-generate the secrets.

Wait, how is this replaced by #229? #229 doesn't provide any key generation capabilities as far as i can see. Please Elaborate @RaitoBezarius

Apologies, I conflated two things, indeed. Key generation should not be automated as part of the Lanzaboote process, as this is private key material stored in insecure locations.

In terms of system recovery, this can have annoying consequences as well, if you automatically enroll a system with a private key that you lost, and you cannot disable Secure Boot, the system cannot receive any further updates and is in an precarious state.

In the future, Lanzaboote will only support automatic safe enrollment and leave key generation to the user. Automating key generation is out of scope and should probably be done externally to this project as there's no one-size-fits-all solution, and we probably do not want to handle all the scenarios that people may desire to come up with.

(Plus, it's a convergent option, so NixOS/nixpkgs#206467 applies.)

@kuflierl
Copy link
Contributor Author

kuflierl commented Aug 21, 2024

Like i said before: it isn't new that private keys are autogenerated if they don't exist (see openssh). If you believe that stricter permissions should be set for the keys that's a different issue that can be fixed.

I don't really get your point about not being able to disable Secure Boot. Simply going into the bios and wiping the keys or temporarily disabling secure boot is always an option. Also how are you expecting the user to "loose their keys". The keys will be saved on the filesystem and the user should have no reason to mess with the keys (imperative). If the user is messing with his keys without making a backup that's wholly his fault. I don't see anyone annoyed at sshd key auto generation when they screw up their own keys without a backup and have to trust the key everywhere again.

I don't think automatic safe enrollment really conflicts with key auto generation as they are 2 different steps of the process. (It's not like i used YOLO enrollment myself)

I also think that generating keys if they not exist is a form of keeping the system predictable, since i would need to keep in mind that i need to generate and place the keys in the correct places (imperative) before a rebuild or switch if i have enabled lanzaboote. This makes the config not reproducible from one file.

I could see the option being renamed to something like ensureKeysExist if you want to conform to your RFC.

Lastly i do understand that different people might have different needs in regards to key generation like external signing. Though the default way (local signing with pre-generated keys) is the only option exclusively managed by lanzaboote. All external key signing systems either have their own systems for this or don't require it. The default way doesn't rely on any external packages and in my opinion its completely overkill to create a module/package with the only function of ensuring a key exists for Lanzaboot to use.

On a different note: I think Lanzaboote should provide shell hooks for different programs to take part in the lanzaboote process.

@RaitoBezarius
Copy link
Member

Like i said before: it isn't new that private keys are autogenerated if they don't exist (see openssh). If you believe that stricter permissions should be set for the keys that's a different issue that can be fixed.

Yes, but a private SSH host key is not the private key of a certificate to sign bootables blobs. The private key of a certificate should not be accessible on the machine that it signs. If this is something someone needs to do, for e.g. VM testing or whatever, this should be handled out of tree.

I don't really get your point about not being able to disable Secure Boot. Simply going into the bios and wiping the keys or temporarily disabling secure boot is always an option. Also how are you expecting the user to "loose their keys". The keys will be saved on the filesystem and the user should have no reason to mess with the keys (imperative). If the user is messing with his keys without making a backup that's wholly his fault.

No, it's not always an option. BIOS may be locked either via user password or sealed after first enrollment. The user can lose their key as sometimes people lose their data, etc.

The process of making the key creation manual is for the user to be conscious about the existence of these keys and handle them appropriately. Auto-generation removes this ; this is fine for people who know what they are doing, but for our project, this is something to deal with and consider if people starts using this option, it becomes part of the public API.

I could see the option being renamed to something like ensureKeysExist if you want to conform to your RFC.

The RFC is not really about naming… It's about how these options are non-declarative.

Lastly i do understand that different people might have different needs in regards to key generation like external signing. Though the default way (local signing with pre-generated keys) is the only option exclusively managed by lanzaboote. All external key signing systems either have their own systems for this or don't require it. The default way doesn't rely on any external packages and in my opinion its completely overkill to create a module/package with the only function of ensuring a key exists for Lanzaboot to use.

The default way is already problematic because that private key material should be stored somewhere securely, by default, e.g. TPM2 with a fallback backup somewhere or on an external hardware token.

I agree this is overkill to create a module just for this, but,

On a different note: I think Lanzaboote should provide shell hooks for different programs to take part in the lanzaboote process.

Yes, I agree with this and I think it makes more sense to provide the functionality you are seeking ultimately.

@max06
Copy link

max06 commented Aug 21, 2024

Let's say I want to deploy nixos to several hundreds of physical servers in datacenters. SB enabled, system disks encrypted with auto-unlock via tpm2, bios protected.

Local keys would be encrypted at rest. Lost keys require reinstallation, no issue with that. You also need to reinstall if your system disks break. For reinstallation, I need to disable SB anyways since the installers are not signed at all. The installation process itself should be fully automated.

So far I don't see the need for central key management. Data is protected against leakage and/or manipulation.

Did I miss anything?

@kuflierl
Copy link
Contributor Author

Let's say I want to deploy nixos to several hundreds of physical servers in datacenters. SB enabled, system disks encrypted with auto-unlock via tpm2, bios protected.

Local keys would be encrypted at rest. Lost keys require reinstallation, no issue with that. You also need to reinstall if your system disks break. For reinstallation, I need to disable SB anyways since the installers are not signed at all. The installation process itself should be fully automated.

So far I don't see the need for central key management. Data is protected against leakage and/or manipulation.

Did I miss anything?

Well yes, that's also the scenario that i and most others would think of. But we do have to remember that secure-boot doesn't always come with disk encryption. My former schools server also used secureboot without using disk encryption. For those machines the whole update package including signed kernel, initramfs and boot loader is distributed via an OTA update.

Those cases do require external signing, though i personally think it isn't that useful anyway since the kernel (and initramfs) would actually need to verify the integrity of the whole fs to make sure nothing was tampered with. Especially if you plan to keep the keys on tpm.

It would be nearly impossible due to non static files also needing to be verified.

@RaitoBezarius
Copy link
Member

Let's say I want to deploy nixos to several hundreds of physical servers in datacenters. SB enabled, system disks encrypted with auto-unlock via tpm2, bios protected.

Local keys would be encrypted at rest. Lost keys require reinstallation, no issue with that. You also need to reinstall if your system disks break. For reinstallation, I need to disable SB anyways since the installers are not signed at all. The installation process itself should be fully automated.

So far I don't see the need for central key management. Data is protected against leakage and/or manipulation.

Did I miss anything?

The only thing Secure Boot brings you is that a physical attacker cannot change the bootables. You already get this with Measured Boot via TPM2 and encrypted unlock, Secure Boot is redundant in this scenario, because you can measure the right PCRs for your bootables and you don't have to deal with private key material.

In your scenario, a root attacker can change the bootable because they can read the private key material, which is why people tend to deploy hundreds of physical servers in datacenters without having the Secure Boot private key material on the same machine but centralized.

@RaitoBezarius
Copy link
Member

Those cases do require external signing, though i personally think it isn't that useful anyway since the kernel (and initramfs) would actually need to verify the integrity of the whole fs to make sure nothing was tampered with. Especially if you plan to keep the keys on tpm.

It would be nearly impossible due to non static files also needing to be verified

I'm not sure what this means, to be honest. But there's a PR in lanzaboote to enable remote signing, aka, a very simple CSR system at nixos-rebuild switch time.

There are a bunch of actual NixOS systems in production making use of these, it's not particularly difficult.

@kuflierl
Copy link
Contributor Author

Yes, but a private SSH host key is not the private key of a certificate to sign bootables blobs. The private key of a certificate should not be accessible on the machine that it signs. If this is something someone needs to do, for e.g. VM testing or whatever, this should be handled out of tree.

I don't see a reason to not have the private key on the machine itself as long as the integrity of the whole system can be verified and the keys stored encrypted. This is fulfilled by disk encryption.

I don't really get your point about not being able to disable Secure Boot. Simply going into the bios and wiping the keys or temporarily disabling secure boot is always an option. Also how are you expecting the user to "loose their keys". The keys will be saved on the filesystem and the user should have no reason to mess with the keys (imperative). If the user is messing with his keys without making a backup that's wholly his fault.

No, it's not always an option. BIOS may be locked either via user password or sealed after first enrollment. The user can lose their key as sometimes people lose their data, etc.

The process of making the key creation manual is for the user to be conscious about the existence of these keys and handle them appropriately. Auto-generation removes this ; this is fine for people who know what they are doing, but for our project, this is something to deal with and consider if people starts using this option, it becomes part of the public API.

If data-loss occurs without backup, the only option would be to salvage the usable data and reinstall anyway. Like @max06 said, the installation media isn't signed anyway so secure boot does need to be turned off.
If the user enables this option they are already making a conscious decision to let the system take over. We could add a warning into the description if necessary.

I could see the option being renamed to something like ensureKeysExist if you want to conform to your RFC.

The RFC is not really about naming… It's about how these options are non-declarative.

Sorry about that, i reread it again. I don't believe that its an ensure* option. Ensure options act upon configuration files and do cause a divergence. Cryptographic keys aren't config files and don't diverge the behavior from the nix configuration.

Lastly i do understand that different people might have different needs in regards to key generation like external signing. Though the default way (local signing with pre-generated keys) is the only option exclusively managed by lanzaboote. All external key signing systems either have their own systems for this or don't require it. The default way doesn't rely on any external packages and in my opinion its completely overkill to create a module/package with the only function of ensuring a key exists for Lanzaboot to use.

The default way is already problematic because that private key material should be stored somewhere securely, by default, e.g. TPM2 with a fallback backup somewhere or on an external hardware token.

Like mentioned before: if i use full disk encryption to ensure the integrity of the whole system and safety of the keys there shouldn't be any major security issues.

@kuflierl
Copy link
Contributor Author

The only thing Secure Boot brings you is that a physical attacker cannot change the bootables. You already get this with Measured Boot via TPM2 and encrypted unlock, Secure Boot is redundant in this scenario, because you can measure the right PCRs for your bootables and you don't have to deal with private key material.

No, it isn't. I want to ensure only the software "I" approve runs on my server. PCR's would only ensure that the system data isn't reviled if the kernel/boot-loader has been tampered with.

In your scenario, a root attacker can change the bootable because they can read the private key material, which is why people tend to deploy hundreds of physical servers in datacenters without having the Secure Boot private key material on the same machine but centralized.

How does the attacker read the private key material if its encrypted?

@RaitoBezarius
Copy link
Member

I am sorry, but this is started to become unpleasant to me because I feel like I'm arguing over and over the same things, or we are talking past each other.

Last attempt to clarify things up.

No, it isn't. I want to ensure only the software "I" approve runs on my server. PCR's would only ensure that the system data isn't reviled if the kernel/boot-loader has been tampered with.

For all practical purposes, running software that is approved can be achieved by protecting the desired userspace behind full disk encryption and TPM2 unlocking while verifying that the system is in the approved state. Yes, a user could boot a random Linux distro on your server, but I don't see what are the security consequences of this. If booting arbitrary code on your system without access to the disk is sufficient to compromise something further in your infrastructure, I would argue this is an unusual design choice made. If we are talking about attacks on the firmware, etc. Arguably, by having local signing, you are making the private key the new low-hanging fruit of your threat model.

How does the attacker read the private key material if its encrypted?

In general, a root attacker can do: cat /etc/secureboot/... to read the private key material.

@kuflierl
Copy link
Contributor Author

Those cases do require external signing, though i personally think it isn't that useful anyway since the kernel (and initramfs) would actually need to verify the integrity of the whole fs to make sure nothing was tampered with. Especially if you plan to keep the keys on tpm.
It would be nearly impossible due to non static files also needing to be verified

I'm not sure what this means, to be honest. But there's a PR in lanzaboote to enable remote signing, aka, a very simple CSR system at nixos-rebuild switch time.

There are a bunch of actual NixOS systems in production making use of these, it's not particularly difficult.

Since i as the system (that could be compromised, or is an attacker making a request on behalf of the system) am making the request, this system would be completely worthless unless the CSR server goes out of its way to:

  1. Make sure it's actually the correct system that is making this request and not just some random attacker.
  2. Verify that the nix configuration for the kernel and bootloader is not compromised by malicious patches and that the main source of the kernel and boot-loader isn't compromised.
  3. Build the kernel and bootloader to verify the hashes passed in the CSR request.

You might do this but it might just be simpler to pre-build the closures on a trusted system with the keys and then serve them up for the 1000s of servers that are going to need them.

Also if i am a single user that simply wants a laptop secure against evil maid attacks, that's simply not going to work for me.

@max06
Copy link

max06 commented Aug 21, 2024

Please let's not mix up physical and remote safety.

SecureBoot is about physical safety. It only starts kernels signed with a previously approved key. A local attacker needs to be kept from getting that key, eg. by FDE.

Remote safety is a different topic.

@kuflierl
Copy link
Contributor Author

kuflierl commented Aug 21, 2024

In general, a root attacker can do: cat /etc/secureboot/... to read the private key material.

I would honestly argue that if they are already root on your system you are already maximaly screwed since they can simply replace all of your user-space to their liking and steal all your data anyway.

they can also ask tpm to sign the compromised kernel for them.

@kuflierl
Copy link
Contributor Author

kuflierl commented Aug 21, 2024

Yes, a user could boot a random Linux distro on your server, but I don't see what are the security consequences of this.

Have have you ever heard of load balancing http servers? The web servers behind reverse Proxies tend to serve raw http sites to save resources. If one or multiple of those servers are compromised I would argue it's a problem. Isolated networks are treated as secure by default.

Also isn't that secureboots whole point? The only reason that secure boot exists is to make sure that you can trust that the software you put on the machine is the one you installed on it. Nothing more, nothing less

@fhilgers
Copy link

fhilgers commented Sep 29, 2024

Sorry if this is inappropriate, but currently the instructions users read in the doc, are to generate keys locally on their filesystem using sbctl (with a warning to need a bios password + full disk encryption).
I do not see why generateKeysIfNotExists is any different then instructing the user to install sbctl on their system and run it manually. Having the auto generate option does not prevent users to generate their keys if they want, neither does it prohibit them to have the keys on a remote system. It just makes in more convenient for the people already following docs and generating keys using sbctl anyway.
If having keys on the same filesystem is such a big risk, why does lanzaboote or sbctl have /etc/secureboot as default location only protected via file system permissions.

Also this does not conflict with remote signing via #278.

@alyraffauf
Copy link

Sorry if this is inappropriate, but currently the instructions users read in the doc, are to generate keys locally on their filesystem using sbctl (with a warning to need a bios password + full disk encryption). I do not see why generateKeysIfNotExists is any different then instructing the user to install sbctl on their system and run it manually. Having the auto generate option does not prevent users to generate their keys if they want, neither does it prohibit them to have the keys on a remote system. It just makes in more convenient for the people already following docs and generating keys using sbctl anyway. If having keys on the same filesystem is such a big risk, why does lanzaboote or sbctl have /etc/secureboot as default location only protected via file system permissions.

Also this does not conflict with remote signing via #278.

Seconding this. This also makes it a little annoying to use lanzaboote when deploying a fresh system--I basically have to manually edit my flake to disable lanzaboote, re-enable it, imperatively generate the keys, and so on. I'm also not sure this is any differant than autogenerating ssh keys, which is something that happens on basically every system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants