| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 |
- #!/usr/bin/env perl
- use v5.36;
- use re '/aa';
- use FindBin::libs;
- use Crypt::Misc ();
- use Crypt::PRNG ();
- use Getopt::Long qw{GetOptions};
- use Trog::Vault ();
- =head1 SYNOPSIS
- Write a vault key into config/secrets.key, for an installation that is not run
- by systemd.
- =head2 USAGE
- bin/tcms-vault-key --file
- =head2 YOU PROBABLY DO NOT WANT THIS
- tPSGI's bin/build_service makes the key and puts it in systemd's credential
- store, sealed to this machine if it has a TPM to seal it to, and its unit hands
- it to tCMS before it chroots. That is the way to do this, and it needs nothing
- from here.
- This is the fallback for a machine with no systemd, and it is genuinely weaker:
- a key file beside the database it protects is a key file in the same backup as
- the database it protects. Take the trade knowingly or not at all.
- =head2 WHAT THE KEY IS
- Every secret a user stores through /secrets is encrypted under a key derived
- from this one. It is not in the database, which is the whole point: without it
- config/auth.db is ciphertext.
- There is one key per installation and it does not need rotating on a schedule.
- It is meant to live and die with the machine -- nothing backs it up, and
- trog-provisioner does not carry it onto a rebuilt guest -- so a rebuild loses
- every stored secret and each user stores theirs again. That is the intended
- cost of the key not being anywhere the database is.
- Replacing it has the same effect. Everything sealed under the old one stops
- opening and says so, on /secrets and wherever it was going to be used, rather
- than presenting as corruption or as a thing worth trying again.
- =cut
- my ( $file, $help );
- GetOptions(
- 'file' => \$file,
- 'help' => \$help,
- ) or exit 2;
- if ( $help || !$file ) {
- print "Usage: bin/tcms-vault-key --file\n\n";
- print "Writes $Trog::Vault::key_file for an installation with no systemd.\n";
- print "Under systemd, tPSGI's bin/build_service does this properly; see perldoc bin/tcms-vault-key.\n";
- exit( $help ? 0 : 2 );
- }
- # Printed and exited rather than died: Carp::Always is in the dependency chain,
- # and refusing to clobber a key is not a crash.
- if ( -e $Trog::Vault::key_file ) { ## no critic (ProhibitFiletest_e) -- refusing to overwrite the one thing that cannot be regenerated
- 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";
- exit 2;
- }
- open( my $fh, '>', $Trog::Vault::key_file ) or die "Could not write $Trog::Vault::key_file: $!\n";
- print {$fh} Crypt::Misc::encode_b64( Crypt::PRNG::random_bytes(32) ) . "\n";
- close($fh);
- chmod( oct('600'), $Trog::Vault::key_file ) or die "Could not chmod $Trog::Vault::key_file: $!\n";
- print "Wrote $Trog::Vault::key_file. Restart tCMS to pick it up.\n";
- print "Back it up somewhere that is not where you back up config/auth.db, or do not back it up at all.\n";
|