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

Bug 1885709: Allow connecting to MySQL via SSL #109

Merged
merged 3 commits into from
Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Bugzilla/DB/Mysql.pm
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ sub BUILDARGS {

my %attrs = (mysql_enable_utf8 => 1);

# MySQL SSL options
my ($ssl_ca_file, $ssl_ca_path, $ssl_cert, $ssl_key, $ssl_pubkey) =
@$params{qw(db_mysql_ssl_ca_file db_mysql_ssl_ca_path
db_mysql_ssl_client_cert db_mysql_ssl_client_key db_mysql_ssl_get_pubkey)};
if ($ssl_ca_file || $ssl_ca_path || $ssl_cert || $ssl_key || $ssl_pubkey) {
$attrs{'mysql_ssl'} = 1;
$attrs{'mysql_ssl_ca_file'} = $ssl_ca_file if $ssl_ca_file;
$attrs{'mysql_ssl_ca_path'} = $ssl_ca_path if $ssl_ca_path;
$attrs{'mysql_ssl_client_cert'} = $ssl_cert if $ssl_cert;
$attrs{'mysql_ssl_client_key'} = $ssl_key if $ssl_key;
$attrs{'mysql_get_server_pubkey'} = $ssl_pubkey if $ssl_pubkey;
}

return {dsn => $dsn, user => $user, pass => $pass, attrs => \%attrs};
}

Expand Down
34 changes: 25 additions & 9 deletions Bugzilla/DaemonControl.pm
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use Bugzilla::Constants qw(bz_locations);
use Cwd qw(realpath);
use English qw(-no_match_vars $PROGRAM_NAME);
use File::Spec::Functions qw(catfile catdir);
use Future::Utils qw(repeat try_repeat);
use Future::Utils qw(repeat try_repeat_until_success);
use Future;
use IO::Async::Loop;
use IO::Async::Process;
Expand Down Expand Up @@ -222,6 +222,7 @@ sub assert_connect {
}

sub assert_database {
my $assert_dbierrstr = "";
my $loop = IO::Async::Loop->new;
my $lc = Bugzilla::Install::Localconfig::read_localconfig();

Expand All @@ -230,23 +231,38 @@ sub assert_database {
}

my $dsn = "dbi:mysql:database=$lc->{db_name};host=$lc->{db_host}";
my $repeat = repeat {
my $repeat = try_repeat_until_success {
$loop->delay_future(after => 0.25)->then(sub {
my $dbh
= DBI->connect($dsn, $lc->{db_user}, $lc->{db_pass},
{RaiseError => 0, PrintError => 0},
);
my $attrs = {RaiseError => 1, PrintError => 1};
my ($ssl_ca_file, $ssl_ca_path, $ssl_cert, $ssl_key, $ssl_pubkey) =
@$lc{qw(db_mysql_ssl_ca_file db_mysql_ssl_ca_path
db_mysql_ssl_client_cert db_mysql_ssl_client_key db_mysql_ssl_get_pubkey)};
if ($ssl_ca_file || $ssl_ca_path || $ssl_cert || $ssl_key || $ssl_pubkey) {
$attrs->{'mysql_ssl'} = 1;
$attrs->{'mysql_ssl_ca_file'} = $ssl_ca_file if $ssl_ca_file;
$attrs->{'mysql_ssl_ca_path'} = $ssl_ca_path if $ssl_ca_path;
$attrs->{'mysql_ssl_client_cert'} = $ssl_cert if $ssl_cert;
$attrs->{'mysql_ssl_client_key'} = $ssl_key if $ssl_key;
$attrs->{'mysql_get_server_pubkey'} = $ssl_pubkey if $ssl_pubkey;
}
my $dbh;
eval {
$dbh
= DBI->connect($dsn, $lc->{db_user}, $lc->{db_pass}, $attrs);
};
if ($!) { $assert_dbierrstr = $@; die $@; }
$assert_dbierrstr = DBI->errstr() || '';
die "$assert_dbierrstr" if $assert_dbierrstr;
Future->wrap($dbh);
});
}
until => sub { defined shift->get };
};

my $timeout
= $loop->timeout_future(after => 20)->else_fail('assert_database timeout');
my $any_f = Future->wait_any($repeat, $timeout);
return $any_f->transform(
done => sub {return},
fail => sub {"unable to connect to $dsn as $lc->{db_user}"},
fail => sub {"unable to connect to $dsn as $lc->{db_user}: $assert_dbierrstr"},
);
}

Expand Down
5 changes: 5 additions & 0 deletions Bugzilla/Install/Localconfig.pm
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ use constant LOCALCONFIG_VARS => (
{name => 'db_port', default => 0,},
{name => 'db_sock', default => '',},
{name => 'db_check', default => 1,},
{name => 'db_mysql_ssl_ca_file', default => '',},
{name => 'db_mysql_ssl_ca_path', default => '',},
{name => 'db_mysql_ssl_client_cert', default => '',},
{name => 'db_mysql_ssl_client_key', default => '',},
{name => 'db_mysql_ssl_get_pubkey', default => 0,},
{name => 'index_html', default => 0,},
{name => 'cvsbin', default => sub { bin_loc('cvs') },},
{name => 'interdiffbin', default => sub { bin_loc('interdiff') },},
Expand Down
1 change: 1 addition & 0 deletions conf/checksetup_answers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ $answer{'defaultpriority'} = '--';
$answer{'defaultseverity'} = 'normal';
$answer{'skin'} = 'Mozilla';
$answer{'docs_urlbase'} = 'https://bmo.readthedocs.io/en/latest/';
$answer{'db_mysql_ssl_get_pubkey'} = 1;
20 changes: 20 additions & 0 deletions template/en/default/setup/strings.txt.pl
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,26 @@ END
want that.
END
localconfig_db_user => "Who we connect to the database as.",
localconfig_db_mysql_ssl_ca_file => <<'END',
Path to a PEM file with a list of trusted SSL CA certificates.
The file must be readable by web server user.
END
localconfig_db_mysql_ssl_ca_path => <<'END',
Path to a directory containing trusted SSL CA certificates in PEM format.
Directory and files inside must be readable by the web server user.
END
localconfig_db_mysql_ssl_client_cert => <<'END',
Full path to the client SSL certificate in PEM format we will present to the DB server.
The file must be readable by web server user.
END
localconfig_db_mysql_ssl_client_key => <<'END',
Full path to the private key corresponding to the client SSL certificate.
The file must not be password-protected and must be readable by web server user.
END
localconfig_db_mysql_ssl_get_pubkey => <<'END',
Whether to have Bugzilla automatically fetch the public key from the server at connection time.
This is less secure than specifying the ca_file above.
END
localconfig_diffpath => <<'END',
For the "Difference Between Two Patches" feature to work, we need to know
what directory the "diff" bin is in. (You only need to set this if you
Expand Down
Loading