tcms-vault-key 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. #!/usr/bin/env perl
  2. use v5.36;
  3. use re '/aa';
  4. use FindBin::libs;
  5. use Crypt::Misc ();
  6. use Crypt::PRNG ();
  7. use Getopt::Long qw{GetOptions};
  8. use Trog::Vault ();
  9. =head1 SYNOPSIS
  10. Write a vault key into config/secrets.key, for an installation that is not run
  11. by systemd.
  12. =head2 USAGE
  13. bin/tcms-vault-key --file
  14. =head2 YOU PROBABLY DO NOT WANT THIS
  15. tPSGI's bin/build_service makes the key and puts it in systemd's credential
  16. store, sealed to this machine if it has a TPM to seal it to, and its unit hands
  17. it to tCMS before it chroots. That is the way to do this, and it needs nothing
  18. from here.
  19. This is the fallback for a machine with no systemd, and it is genuinely weaker:
  20. a key file beside the database it protects is a key file in the same backup as
  21. the database it protects. Take the trade knowingly or not at all.
  22. =head2 WHAT THE KEY IS
  23. Every secret a user stores through /secrets is encrypted under a key derived
  24. from this one. It is not in the database, which is the whole point: without it
  25. config/auth.db is ciphertext.
  26. There is one key per installation and it does not need rotating on a schedule.
  27. It is meant to live and die with the machine -- nothing backs it up, and
  28. trog-provisioner does not carry it onto a rebuilt guest -- so a rebuild loses
  29. every stored secret and each user stores theirs again. That is the intended
  30. cost of the key not being anywhere the database is.
  31. Replacing it has the same effect. Everything sealed under the old one stops
  32. opening and says so, on /secrets and wherever it was going to be used, rather
  33. than presenting as corruption or as a thing worth trying again.
  34. =cut
  35. my ( $file, $help );
  36. GetOptions(
  37. 'file' => \$file,
  38. 'help' => \$help,
  39. ) or exit 2;
  40. if ( $help || !$file ) {
  41. print "Usage: bin/tcms-vault-key --file\n\n";
  42. print "Writes $Trog::Vault::key_file for an installation with no systemd.\n";
  43. print "Under systemd, tPSGI's bin/build_service does this properly; see perldoc bin/tcms-vault-key.\n";
  44. exit( $help ? 0 : 2 );
  45. }
  46. # Printed and exited rather than died: Carp::Always is in the dependency chain,
  47. # and refusing to clobber a key is not a crash.
  48. if ( -e $Trog::Vault::key_file ) { ## no critic (ProhibitFiletest_e) -- refusing to overwrite the one thing that cannot be regenerated
  49. print STDERR "There is already a key at $Trog::Vault::key_file. Move it out of the way if you really mean to replace it, and read what that costs first: perldoc bin/tcms-vault-key\n";
  50. exit 2;
  51. }
  52. open( my $fh, '>', $Trog::Vault::key_file ) or die "Could not write $Trog::Vault::key_file: $!\n";
  53. print {$fh} Crypt::Misc::encode_b64( Crypt::PRNG::random_bytes(32) ) . "\n";
  54. close($fh);
  55. chmod( oct('600'), $Trog::Vault::key_file ) or die "Could not chmod $Trog::Vault::key_file: $!\n";
  56. print "Wrote $Trog::Vault::key_file. Restart tCMS to pick it up.\n";
  57. print "Back it up somewhere that is not where you back up config/auth.db, or do not back it up at all.\n";