diff --git a/puppet/zulip/files/sasl2/memcached.conf b/puppet/zulip/files/sasl2/memcached.conf new file mode 100644 index 0000000000..907a745fa0 --- /dev/null +++ b/puppet/zulip/files/sasl2/memcached.conf @@ -0,0 +1,2 @@ +mech_list: plain +sasldb_path: /etc/sasl2/memcached-sasldb2 diff --git a/puppet/zulip/manifests/memcached.pp b/puppet/zulip/manifests/memcached.pp index 1bb73f1b80..8542569e71 100644 --- a/puppet/zulip/manifests/memcached.pp +++ b/puppet/zulip/manifests/memcached.pp @@ -1,11 +1,58 @@ class zulip::memcached { - $memcached_packages = ['memcached'] + include zulip::sasl_modules + + $memcached_packages = $::osfamily ? { + 'debian' => [ 'memcached', 'sasl2-bin' ], + 'redhat' => [ 'memcached' ], + } package { $memcached_packages: ensure => 'installed' } $memcached_memory = zulipconf('memcached', 'memory', $zulip::base::total_memory_mb / 8) + file { '/etc/sasl2': + ensure => directory, + } + file { '/etc/sasl2/memcached-zulip-password': + # We cache the password in this file so we can check whether it + # changed and avoid running saslpasswd2 if it didn't. + require => File['/etc/sasl2'], + owner => 'root', + group => 'root', + mode => '0600', + content => zulipsecret('secrets', 'memcached_password', ''), + notify => Exec[generate_memcached_sasldb2], + } + exec { 'generate_memcached_sasldb2': + creates => '/etc/sasl2/memcached-sasldb2', + require => [ + Package[$memcached_packages], + Package[$zulip::sasl_modules::sasl_module_packages], + File['/etc/sasl2/memcached-zulip-password'], + ], + # Pass the hostname explicitly because otherwise saslpasswd2 + # lowercases it and memcached does not. + command => "bash -c 'saslpasswd2 -p -f /etc/sasl2/memcached-sasldb2 \ +-a memcached -u \"\$HOSTNAME\" zulip < /etc/sasl2/memcached-zulip-password'", + } + file { '/etc/sasl2/memcached-sasldb2': + require => Exec[generate_memcached_sasldb2], + owner => 'memcache', + group => 'memcache', + mode => '0600', + } + file { '/etc/sasl2/memcached.conf': + require => File['/etc/sasl2'], + owner => 'root', + group => 'root', + mode => '0644', + source => 'puppet:///modules/zulip/sasl2/memcached.conf', + notify => Service[memcached], + } file { '/etc/memcached.conf': ensure => file, - require => Package[memcached], + require => [ + Package[$memcached_packages], + Package[$zulip::sasl_modules::sasl_module_packages] + ], owner => 'root', group => 'root', mode => '0644', diff --git a/puppet/zulip/templates/memcached.conf.template.erb b/puppet/zulip/templates/memcached.conf.template.erb index 066f2de110..075c20f819 100644 --- a/puppet/zulip/templates/memcached.conf.template.erb +++ b/puppet/zulip/templates/memcached.conf.template.erb @@ -27,7 +27,7 @@ logfile /var/log/memcached.log # Run the daemon as root. The start-memcached will default to running as root if no # -u command is present in this config file --u nobody +-u memcache # Specify which IP address to listen on. The default is to listen on all IP addresses # This parameter is one of the only security measures that memcached has, so make sure @@ -50,3 +50,6 @@ logfile /var/log/memcached.log # Maximize core file limit # -r + +# Enable SASL authentication +-S diff --git a/scripts/lib/install b/scripts/lib/install index 2a1abdd3df..0b7dbe1197 100755 --- a/scripts/lib/install +++ b/scripts/lib/install @@ -293,6 +293,16 @@ EOF case ",$PUPPET_CLASSES," in *,zulip::voyager,* | *,zulip::dockervoyager,* | *,zulip::app_frontend,*) + if [ -z "$NO_OVERWRITE_SETTINGS" ] || ! [ -e "/etc/zulip/settings.py" ]; then + cp -a "$ZULIP_PATH"/zproject/prod_settings_template.py /etc/zulip/settings.py + if [ -n "$EXTERNAL_HOST" ]; then + sed -i "s/^EXTERNAL_HOST =.*/EXTERNAL_HOST = '$EXTERNAL_HOST'/" /etc/zulip/settings.py + fi + if [ -n "$ZULIP_ADMINISTRATOR" ]; then + sed -i "s/^ZULIP_ADMINISTRATOR =.*/ZULIP_ADMINISTRATOR = '$ZULIP_ADMINISTRATOR'/" /etc/zulip/settings.py + fi + fi + ln -nsf /etc/zulip/settings.py "$ZULIP_PATH"/zproject/prod_settings.py "$ZULIP_PATH"/scripts/setup/generate_secrets.py --production ;; esac @@ -353,19 +363,6 @@ EOF service nginx restart fi -if [ "$has_appserver" = 0 ]; then - if [ -z "$NO_OVERWRITE_SETTINGS" ] || ! [ -e "/etc/zulip/settings.py" ]; then - cp -a "$ZULIP_PATH"/zproject/prod_settings_template.py /etc/zulip/settings.py - if [ -n "$EXTERNAL_HOST" ]; then - sed -i "s/^EXTERNAL_HOST =.*/EXTERNAL_HOST = '$EXTERNAL_HOST'/" /etc/zulip/settings.py - fi - if [ -n "$ZULIP_ADMINISTRATOR" ]; then - sed -i "s/^ZULIP_ADMINISTRATOR =.*/ZULIP_ADMINISTRATOR = '$ZULIP_ADMINISTRATOR'/" /etc/zulip/settings.py - fi - fi - ln -nsf /etc/zulip/settings.py "$ZULIP_PATH"/zproject/prod_settings.py -fi - if [ "$has_rabbit" = 0 ]; then if ! rabbitmqctl status >/dev/null; then set +x diff --git a/scripts/setup/generate_secrets.py b/scripts/setup/generate_secrets.py index 6acd192b58..2a714bbfad 100755 --- a/scripts/setup/generate_secrets.py +++ b/scripts/setup/generate_secrets.py @@ -17,6 +17,7 @@ import argparse import uuid import configparser from zerver.lib.utils import generate_random_token +from zproject import settings os.chdir(os.path.join(os.path.dirname(__file__), '..', '..')) @@ -80,6 +81,13 @@ def generate_secrets(development=False): if need_secret('camo_key'): add_secret('camo_key', get_random_string(64)) + if ( + not development + and settings.MEMCACHED_LOCATION == "127.0.0.1:11211" + and need_secret("memcached_password") + ): + add_secret("memcached_password", generate_random_token(64)) + # zulip_org_key is generated using os.urandom(). # zulip_org_id does not require a secure CPRNG, # it only needs to be unique.