tcms-vault-key 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #!/usr/bin/env perl
  2. use 5.040;
  3. use re '/aasx';
  4. use warnings FATAL => 'all';
  5. use FindBin::libs;
  6. use Crypt::Misc ();
  7. use Crypt::PRNG ();
  8. use Getopt::Long qw{GetOptions};
  9. use Trog::Vault ();
  10. =head1 SYNOPSIS
  11. Write a vault key into config/secrets.key, for a tCMS that is not being handed
  12. one by the service that starts it.
  13. =head2 USAGE
  14. bin/tcms-vault-key --file
  15. =head2 WHEN YOU WANT THIS
  16. Developing, mostly. Running tPSGI by hand -- HOME=. bin/tpsgi -p 5001, in a
  17. tmux, so you can watch it and restart it -- is the ordinary way to work on tCMS,
  18. and nothing in that path hands over a vault key: there is no unit importing a
  19. systemd credential, and service/tpsgi.sh, which is what would have put it in the
  20. environment, never ran. So /secrets does not work until you put a key where
  21. Trog::Vault can find one, and this is how.
  22. The other time is a machine with no systemd at all, and there it is a compromise
  23. rather than a convenience.
  24. =head2 WHEN YOU DO NOT
  25. On a production host. tPSGI's bin/build_service makes the key and puts it in
  26. systemd's credential store, sealed to this machine if it has a TPM to seal it to,
  27. and its unit hands it to tCMS before it chroots -- so the key is never on a disk
  28. that tCMS can see, and never in a backup of tCMS.
  29. A key file in the checkout gives up exactly that. It sits next to the database
  30. it protects, so whatever copies one copies the other, and the encryption stops
  31. being worth anything the moment both are somewhere they should not be.
  32. .gitignore keeps it out of the repository; keeping it out of your backups is on
  33. you.
  34. =head2 WHAT THE KEY IS
  35. Every secret a user stores through /secrets is encrypted under a key derived
  36. from this one. It is not in the database, which is the whole point: without it
  37. config/auth.db is ciphertext.
  38. There is one key per installation and it does not need rotating on a schedule.
  39. It is meant to live and die with the machine -- nothing backs it up, and
  40. trog-provisioner does not carry it onto a rebuilt guest -- so a rebuild loses
  41. every stored secret and each user stores theirs again. That is the intended
  42. cost of the key not being anywhere the database is.
  43. Replacing it has the same effect. Everything sealed under the old one stops
  44. opening and says so, on /secrets and wherever it was going to be used, rather
  45. than presenting as corruption or as a thing worth trying again.
  46. =cut
  47. my ( $file, $help );
  48. GetOptions(
  49. 'file' => \$file,
  50. 'help' => \$help,
  51. ) or exit 2;
  52. if ( $help || !$file ) {
  53. print <<"USAGE";
  54. Usage: bin/tcms-vault-key --file
  55. Writes $Trog::Vault::key_file, for a tCMS nothing is handing a vault key to:
  56. running tPSGI by hand while developing, or a machine with no systemd.
  57. On a production host tPSGI's bin/build_service does this properly, and better;
  58. see perldoc bin/tcms-vault-key.
  59. USAGE
  60. exit( $help ? 0 : 2 );
  61. }
  62. # Warned and exited rather than died, so that it exits 2: refusing to clobber a
  63. # key is not a crash.
  64. if ( -e $Trog::Vault::key_file ) { # Refusing to overwrite the one thing that cannot be regenerated
  65. warn "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";
  66. exit 2;
  67. }
  68. open( my $fh, '>', $Trog::Vault::key_file ) or die "Could not write $Trog::Vault::key_file: $!\n";
  69. print {$fh} Crypt::Misc::encode_b64( Crypt::PRNG::random_bytes(32) ) . "\n";
  70. close($fh);
  71. chmod( oct('600'), $Trog::Vault::key_file ) or die "Could not chmod $Trog::Vault::key_file: $!\n";
  72. print <<"SAID";
  73. Wrote $Trog::Vault::key_file. Restart tCMS to pick it up.
  74. Fine for development. On a production host, let tPSGI's bin/build_service hand one
  75. over instead, so the key is not sitting next to the database it protects.
  76. SAID