From b38b925a5f153c6c2d16c6c94dc722376b286e74 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Tue, 10 May 2016 19:14:54 +0000 Subject: [PATCH] Tighten the access rules for galera Set a password for the 'root' db user and add an additional 'clustercheck' user to be used only by the resource agent. The password for this 'clustercheck' user is randomly generated via a heat parameter. Before this change the workflow to set up the database in the manifest is the following: - Step 1 -> Install all the basic galera packages and basic configuration - Step 2.a -> Create /etc/sysconfig/clustercheck with root and empty password - Step 2.b -> Start up galera-monitor xinetd service - Step 2.c -> Start pacemaker ocf resource (no root user has been created so there will be an empty password per default) - Step 2.d -> Wait for /bin/clustercheck to return success and then proceed with the other steps After this change the workflow is slightly more complex because there is a bit of a chicken and egg problem: - Step 1 -> Install all the basic galera packages and basic configuration - Step 2.a -> Create /etc/sysconfig/clustercheck with root and empty password unless the file does exists already and has a clustercheck user configured - Step 2.b -> Start up galera-monitor xinetd service - Step 2.c -> Start pacemaker ocf resource (no root user has been created yet, so there will be an empty password per default) - Step 2.d -> Wait for /bin/clustercheck to return success and then proceed with the other steps - Step 2.e -> Create clustercheck db user - Step 3/4 -> Create /etc/sysconfig/clustercheck with clustercheck user credentials - Step 5.a -> Update the sql root password on the each node (at this stage - Step 5.b -> Create /root/.my.cnf with proper credentials on all nodes Note that we cannot really create the root/clustercheck users right at step 1 because the db is not running yet (an approach that spawned mysqld on each node, created the users and shut it down, was tried but was much more complex and cannot work on updating existing setups) --- overcloud.yaml | 6 ++ puppet/controller.yaml | 6 ++ puppet/manifests/overcloud_controller_pacemaker.pp | 72 +++++++++++++++++++--- 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/overcloud.yaml b/overcloud.yaml index 2c34ad1c7df9..569d51d6c5ea 100644 --- a/overcloud.yaml +++ b/overcloud.yaml @@ -934,6 +934,7 @@ resources: InstanceNameTemplate: {get_param: InstanceNameTemplate} KeyName: {get_param: KeyName} MemcachedIPv6: {get_param: MemcachedIPv6} + MysqlClustercheckPassword: {get_attr: [MysqlClustercheckPassword, value]} MysqlClusterUniquePart: {get_attr: [MysqlClusterUniquePart, value]} MysqlInnodbBufferPoolSize: {get_param: MysqlInnodbBufferPoolSize} MysqlMaxConnections: {get_param: MysqlMaxConnections} @@ -1253,6 +1254,11 @@ resources: DeployIdentifier: {get_param: DeployIdentifier} UpdateIdentifier: {get_param: UpdateIdentifier} + MysqlClustercheckPassword: + type: OS::Heat::RandomString + properties: + length: 10 + MysqlRootPassword: type: OS::Heat::RandomString properties: diff --git a/puppet/controller.yaml b/puppet/controller.yaml index a08ed1bbf5ea..0a286822111b 100644 --- a/puppet/controller.yaml +++ b/puppet/controller.yaml @@ -310,6 +310,10 @@ parameters: description: Configures MySQL max_connections config setting type: number default: 4096 + MysqlClustercheckPassword: + type: string + hidden: true + default: '' # Has to be here because of the ignored empty value bug MysqlRootPassword: type: string hidden: true @@ -969,6 +973,7 @@ resources: mysql_innodb_buffer_pool_size: {get_param: MysqlInnodbBufferPoolSize} mysql_max_connections: {get_param: MysqlMaxConnections} mysql_root_password: {get_param: MysqlRootPassword} + mysql_clustercheck_password: {get_param: MysqlClustercheckPassword} mysql_cluster_name: str_replace: template: tripleo-CLUSTER @@ -1399,6 +1404,7 @@ resources: mysql_innodb_buffer_pool_size: {get_input: mysql_innodb_buffer_pool_size} mysql_max_connections: {get_input: mysql_max_connections} mysql::server::root_password: {get_input: mysql_root_password} + mysql_clustercheck_password: {get_input: mysql_clustercheck_password} mysql_cluster_name: {get_input: mysql_cluster_name} mysql_bind_host: {get_input: mysql_network} mysql_virtual_ip: {get_input: mysql_virtual_ip} diff --git a/puppet/manifests/overcloud_controller_pacemaker.pp b/puppet/manifests/overcloud_controller_pacemaker.pp index 0652a1c68980..2d2f17a334ab 100644 --- a/puppet/manifests/overcloud_controller_pacemaker.pp +++ b/puppet/manifests/overcloud_controller_pacemaker.pp @@ -345,6 +345,16 @@ if hiera('step') >= 2 { } } + $mysql_root_password = hiera('mysql::server::root_password') + $mysql_clustercheck_password = hiera('mysql_clustercheck_password') + # This step is to create a sysconfig clustercheck file with the root user and empty password + # on the first install only (because later on the clustercheck db user will be used) + # We are using exec and not file in order to not have duplicate definition errors in puppet + # when we later set the the file to contain the clustercheck data + exec { 'create-root-sysconfig-clustercheck': + command => "/bin/echo 'MYSQL_USERNAME=root\nMYSQL_PASSWORD=\'\'\nMYSQL_HOST=localhost\n' > /etc/sysconfig/clustercheck", + unless => "/bin/test -e /etc/sysconfig/clustercheck && grep clustercheck /etc/sysconfig/clustercheck", + } exec { 'galera-ready' : command => '/usr/bin/clustercheck >/dev/null', @@ -352,14 +362,7 @@ if hiera('step') >= 2 { tries => 180, try_sleep => 10, environment => ['AVAILABLE_WHEN_READONLY=0'], - require => File['/etc/sysconfig/clustercheck'], - } - - file { '/etc/sysconfig/clustercheck' : - ensure => file, - content => "MYSQL_USERNAME=root\n -MYSQL_PASSWORD=''\n -MYSQL_HOST=localhost\n", + require => Exec['create-root-sysconfig-clustercheck'], } xinetd::service { 'galera-monitor' : @@ -372,7 +375,24 @@ MYSQL_HOST=localhost\n", service_type => 'UNLISTED', user => 'root', group => 'root', - require => File['/etc/sysconfig/clustercheck'], + require => Exec['create-root-sysconfig-clustercheck'], + } + # We add a clustercheck db user and we will switch /etc/sysconfig/clustercheck + # to it in a later step. We do this only on one node as it will replicate on + # the other members. We also make sure that the permissions are the minimum necessary + if $pacemaker_master { + mysql_user { 'clustercheck@localhost': + ensure => 'present', + password_hash => mysql_password($mysql_clustercheck_password), + require => Exec['galera-ready'], + } + mysql_grant { 'clustercheck@localhost/*.*': + ensure => 'present', + options => ['GRANT'], + privileges => ['PROCESS'], + table => '*.*', + user => 'clustercheck@localhost', + } } # Create all the database schemas @@ -466,6 +486,17 @@ MYSQL_HOST=localhost\n", } #END STEP 2 if hiera('step') >= 4 or ( hiera('step') >= 3 and $sync_db ) { + # At this stage we are guaranteed that the clustercheck db user exists + # so we switch the resource agent to use it. + file { '/etc/sysconfig/clustercheck' : + ensure => file, + mode => 0600, + owner => 'root', + group => 'root', + content => "MYSQL_USERNAME=clustercheck\n +MYSQL_PASSWORD='$mysql_clustercheck_password'\n +MYSQL_HOST=localhost\n", + } $nova_ipv6 = hiera('nova::use_ipv6', false) if $nova_ipv6 { @@ -1022,6 +1053,29 @@ if hiera('step') >= 4 or ( hiera('step') >= 3 and $sync_db ) { } #END STEP 4 if hiera('step') >= 5 { + # We now make sure that the root db password is set to a random one + # At first installation /root/.my.cnf will be empty and we connect without a root + # password. On second runs or updates /root/.my.cnf will already be populated + # with proper credentials. This step happens to every node because this sql + # statement does not automatically replicate across nodes. + exec { 'galera-set-root-password': + command => "/bin/touch /root/.my.cnf && /bin/echo \"UPDATE mysql.user SET Password = PASSWORD('$mysql_root_password') WHERE user = 'root'; flush privileges;\" | /bin/mysql --defaults-extra-file=/root/.my.cnf -u root", + } + file { '/root/.my.cnf' : + ensure => file, + mode => 0600, + owner => 'root', + group => 'root', + content => "[client] +user=root +password=\"$mysql_root_password\" + +[mysql] +user=root +password=\"$mysql_root_password\"", + require => Exec['galera-set-root-password'], + } + $nova_enable_db_purge = hiera('nova_enable_db_purge', true) $cinder_enable_db_purge = hiera('cinder_enable_db_purge', true) $heat_enable_db_purge = hiera('heat_enable_db_purge', true) -- 1.8.3.1