Add CLI task for rotating keys (#8466)
* If an Update is signed with known key, skip re-following procedure Because it means the remote actor did *not* lose their database * Add CLI method for rotating keys bin/tootctl accounts rotate [USERNAME] Generates a new RSA key per account and sends out an Update activity signed with the old key. * Key rotation: Space out Update fan-outs every 5 minutes per 1000 accounts * Skip suspended accounts in key rotationmaster
parent
8adf485c0f
commit
cabdbb7f9c
@ -0,0 +1,55 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
require 'rubygems/package' |
||||
require_relative '../../config/boot' |
||||
require_relative '../../config/environment' |
||||
require_relative 'cli_helper' |
||||
|
||||
module Mastodon |
||||
class AccountsCLI < Thor |
||||
option :all, type: :boolean |
||||
desc 'rotate [USERNAME]', 'Generate and broadcast new keys' |
||||
long_desc <<-LONG_DESC |
||||
Generate and broadcast new RSA keys as part of security |
||||
maintenance. |
||||
|
||||
With the --all option, all local accounts will be subject |
||||
to the rotation. Otherwise, and by default, only a single |
||||
account specified by the USERNAME argument will be |
||||
processed. |
||||
LONG_DESC |
||||
def rotate(username = nil) |
||||
if options[:all] |
||||
processed = 0 |
||||
delay = 0 |
||||
|
||||
Account.local.without_suspended.find_in_batches do |accounts| |
||||
accounts.each do |account| |
||||
rotate_keys_for_account(account, delay) |
||||
processed += 1 |
||||
say('.', :green, false) |
||||
end |
||||
|
||||
delay += 5.minutes |
||||
end |
||||
|
||||
say |
||||
say("OK, rotated keys for #{processed} accounts", :green) |
||||
elsif username.present? |
||||
rotate_keys_for_account(Account.find_local(username)) |
||||
say('OK', :green) |
||||
else |
||||
say('No account(s) given', :red) |
||||
end |
||||
end |
||||
|
||||
private |
||||
|
||||
def rotate_keys_for_account(account, delay = 0) |
||||
old_key = account.private_key |
||||
new_key = OpenSSL::PKey::RSA.new(2048).to_pem |
||||
account.update(private_key: new_key) |
||||
ActivityPub::UpdateDistributionWorker.perform_in(delay, account.id, sign_with: old_key) |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue