diff --git a/CHANGELOG.md b/CHANGELOG.md index 4eb149f4..6f07865c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,20 @@ The **patch** part changes incrementally at each release. ### Security +## [9.8.0] - 2019-01-31 + +### Added +* filebeat: disable cloud_metadata processor by default +* metricbeat: disable cloud_metadata processor by default +* percona : new role to install Percona repositories and tools +* redis: add variable for configure unixsocketperm + +### Changed +* redmine: refactoring of redmine role with use of rbenv + +### Fixed +* ntpd: Update the restrictions to follow wiki.evolix.org/HowtoNTP client config + ## [9.7.0] - 2019-01-17 ### Added @@ -30,6 +44,7 @@ The **patch** part changes incrementally at each release. * redis: add a variable for renamed/disabled commands * redis: add a variable to disable the restart handler * redis: add a variable to force a restart (even with no change) +* proftpd: add FTPS and SFTP support ### Changed * redis: distinction between main and master password diff --git a/filebeat/defaults/main.yml b/filebeat/defaults/main.yml index 75c8ae0f..008daa27 100644 --- a/filebeat/defaults/main.yml +++ b/filebeat/defaults/main.yml @@ -2,3 +2,5 @@ elastic_stack_version: "6.x" filebeat_logstash_plugin: False + +filebeat_processors_cloud_metadata: False diff --git a/filebeat/handlers/main.yml b/filebeat/handlers/main.yml new file mode 100644 index 00000000..0a6d83f9 --- /dev/null +++ b/filebeat/handlers/main.yml @@ -0,0 +1,6 @@ +--- + +- name: restart filebeat + systemd: + name: filebeat + state: restarted diff --git a/filebeat/tasks/main.yml b/filebeat/tasks/main.yml index eebbd8ee..e02ff6ab 100644 --- a/filebeat/tasks/main.yml +++ b/filebeat/tasks/main.yml @@ -64,3 +64,19 @@ - filebeat_logstash_plugin - logstash_plugin.stat.exists - not logstash_plugin_installed | success + +- name: cloud_metadata processor is disabled + replace: + dest: /etc/filebeat/filebeat.yml + regexp: '^(\s+)(- add_cloud_metadata:)' + replace: '\1# \2' + notify: restart filebeat + when: not filebeat_processors_cloud_metadata + +- name: cloud_metadata processor is disabled + lineinfile: + dest: /etc/filebeat/filebeat.yml + line: " - add_cloud_metadata: ~" + insert_after: '^processors:' + notify: restart filebeat + when: filebeat_processors_cloud_metadata diff --git a/metricbeat/defaults/main.yml b/metricbeat/defaults/main.yml index ee4cee34..df2d9649 100644 --- a/metricbeat/defaults/main.yml +++ b/metricbeat/defaults/main.yml @@ -6,3 +6,5 @@ metricbeat_elasticsearch_hosts: - "localhost:9200" metricbeat_elasticsearch_auth_username: "" metricbeat_elasticsearch_auth_password: "" + +metricbeat_processors_cloud_metadata: False diff --git a/metricbeat/handlers/main.yml b/metricbeat/handlers/main.yml new file mode 100644 index 00000000..cd83ab5d --- /dev/null +++ b/metricbeat/handlers/main.yml @@ -0,0 +1,6 @@ +--- + +- name: restart metricbeat + systemd: + name: metricbeat + state: restarted diff --git a/metricbeat/tasks/main.yml b/metricbeat/tasks/main.yml index ed51dd1f..535037ec 100644 --- a/metricbeat/tasks/main.yml +++ b/metricbeat/tasks/main.yml @@ -72,3 +72,19 @@ when: - metricbeat_elasticsearch_auth_username != "" - metricbeat_elasticsearch_auth_password != "" + +- name: disable cloud_metadata + replace: + dest: /etc/metricbeat/metricbeat.yml + regexp: '^(\s+)(- add_cloud_metadata:)' + replace: '\1# \2' + notify: restart metricbeat + when: not metricbeat_processors_cloud_metadata + +- name: cloud_metadata processor is disabled + lineinfile: + dest: /etc/metricbeat/metricbeat.yml + line: " - add_cloud_metadata: ~" + insert_after: '^processors:' + notify: restart metricbeat + when: metricbeat_processors_cloud_metadata diff --git a/ntpd/defaults/main.yml b/ntpd/defaults/main.yml index 221a829c..88253844 100644 --- a/ntpd/defaults/main.yml +++ b/ntpd/defaults/main.yml @@ -2,7 +2,9 @@ ntpd_servers: - 'ntp.evolix.net iburst' ntpd_acls: -- '-4 default kod notrap nomodify nopeer noquery' -- '-6 default kod notrap nomodify nopeer noquery' +- '-4 default ignore' +- '-6 default ignore' +- 'source nomodify noquery notrap' # Debian 9 and later +- 'ntp.evolix.net nomodify noquery notrap' # Debian 8 - '127.0.0.1' - '::1' diff --git a/percona/defaults/main.yml b/percona/defaults/main.yml new file mode 100644 index 00000000..46a86904 --- /dev/null +++ b/percona/defaults/main.yml @@ -0,0 +1,4 @@ +--- + +percona__install_xtrabackup: True +percona__xtrabackup_package_name: percona-xtrabackup-24 diff --git a/percona/files/percona-release_latest.jessie_all.deb b/percona/files/percona-release_latest.jessie_all.deb new file mode 100644 index 00000000..a387f361 Binary files /dev/null and b/percona/files/percona-release_latest.jessie_all.deb differ diff --git a/percona/files/percona-release_latest.stretch_all.deb b/percona/files/percona-release_latest.stretch_all.deb new file mode 100644 index 00000000..5479137e Binary files /dev/null and b/percona/files/percona-release_latest.stretch_all.deb differ diff --git a/percona/files/percona.asc b/percona/files/percona.asc new file mode 100644 index 00000000..1c78566d --- /dev/null +++ b/percona/files/percona.asc @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.9 (GNU/Linux) + +mQGiBEsm3aERBACyB1E9ixebIMRGtmD45c6c/wi2IVIa6O3G1f6cyHH4ump6ejOi +AX63hhEs4MUCGO7KnON1hpjuNN7MQZtGTJC0iX97X2Mk+IwB1KmBYN9sS/OqhA5C +itj2RAkug4PFHR9dy21v0flj66KjBS3GpuOadpcrZ/k0g7Zi6t7kDWV0hwCgxCa2 +f/ESC2MN3q3j9hfMTBhhDCsD/3+iOxtDAUlPMIH50MdK5yqagdj8V/sxaHJ5u/zw +YQunRlhB9f9QUFfhfnjRn8wjeYasMARDctCde5nbx3Pc+nRIXoB4D1Z1ZxRzR/lb +7S4i8KRr9xhommFnDv/egkx+7X1aFp1f2wN2DQ4ecGF4EAAVHwFz8H4eQgsbLsa6 +7DV3BACj1cBwCf8tckWsvFtQfCP4CiBB50Ku49MU2Nfwq7durfIiePF4IIYRDZgg +kHKSfP3oUZBGJx00BujtTobERraaV7lIRIwETZao76MqGt9K1uIqw4NT/jAbi9ce +rFaOmAkaujbcB11HYIyjtkAGq9mXxaVqCC3RPWGr+fqAx/akBLQ2UGVyY29uYSBN +eVNRTCBEZXZlbG9wbWVudCBUZWFtIDxteXNxbC1kZXZAcGVyY29uYS5jb20+iGAE +ExECACAFAksm3aECGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRAcTL3NzS79 +Kpk/AKCQKSEgwX9r8jR+6tAnCVpzyUFOQwCfX+fw3OAoYeFZB3eu2oT8OBTiVYu5 +Ag0ESybdoRAIAKKUV8rbqlB8qwZdWlmrwQqg3o7OpoAJ53/QOIySDmqy5TmNEPLm +lHkwGqEqfbFYoTbOCEEJi2yFLg9UJCSBM/sfPaqb2jGP7fc0nZBgUBnFuA9USX72 +O0PzVAF7rCnWaIz76iY+AMI6xKeRy91TxYo/yenF1nRSJ+rExwlPcHgI685GNuFG +chAExMTgbnoPx1ka1Vqbe6iza+FnJq3f4p9luGbZdSParGdlKhGqvVUJ3FLeLTqt +caOn5cN2ZsdakE07GzdSktVtdYPT5BNMKgOAxhXKy11IPLj2Z5C33iVYSXjpTelJ +b2qHvcg9XDMhmYJyE3O4AWFh2no3Jf4ypIcABA0IAJO8ms9ov6bFqFTqA0UW2gWQ +cKFN4Q6NPV6IW0rV61ONLUc0VFXvYDtwsRbUmUYkB/L/R9fHj4lRUDbGEQrLCoE+ +/HyYvr2rxP94PT6Bkjk/aiCCPAKZRj5CFUKRpShfDIiow9qxtqv7yVd514Qqmjb4 +eEihtcjltGAoS54+6C3lbjrHUQhLwPGqlAh8uZKzfSZq0C06kTxiEqsG6VDDYWy6 +L7qaMwOqWdQtdekKiCk8w/FoovsMYED2qlWEt0i52G+0CjoRFx2zNsN3v4dWiIhk +ZSL00Mx+g3NA7pQ1Yo5Vhok034mP8L2fBLhhWaK3LG63jYvd0HLkUFhNG+xjkpeI +SQQYEQIACQUCSybdoQIbDAAKCRAcTL3NzS79KlacAJ0aAkBQapIaHNvmAhtVjLPN +wke4ZgCePe3sPPF49lBal7QaYPdjqapa1SQ= +=qcCk +-----END PGP PUBLIC KEY BLOCK----- diff --git a/percona/tasks/main.yml b/percona/tasks/main.yml new file mode 100644 index 00000000..cce78c3a --- /dev/null +++ b/percona/tasks/main.yml @@ -0,0 +1,45 @@ +--- + +- set_fact: + percona__apt_config_package_file: "percona-release_latest.{{ ansible_distribution_release }}_all.deb" + +- name: Add Percona's official GPG key + apt_key: + data: "{{ lookup('file', 'percona.asc') }}" + +- name: Check if percona-release is installed + command: "dpkg -l percona-release" + failed_when: False + changed_when: False + register: percona__apt_config_package_installed + +- name: Percona APT config package is available + copy: + src: "{{ percona__apt_config_package_file }}" + dest: "/root/{{ percona__apt_config_package_file }}" + when: not percona__apt_config_package_installed + +# - include_role: +# name: remount-usr + +- name: Percona APT config package is installed from deb file + apt: + deb: "/root/{{ percona__apt_config_package_file }}" + state: present + register: percona__apt_config_deb + when: not percona__apt_config_package_installed + +- name: Percona APT config package is installed from repository + apt: + name: percona-release + state: latest + register: percona__apt_config_deb + when: percona__apt_config_package_installed + +- name: APT cache is up-to-date + apt: + update_cache: yes + when: percona__apt_config_deb | changed + +- include: xtrabackup.yml + when: percona__install_xtrabackup diff --git a/percona/tasks/xtrabackup.yml b/percona/tasks/xtrabackup.yml new file mode 100644 index 00000000..8fe6a7c5 --- /dev/null +++ b/percona/tasks/xtrabackup.yml @@ -0,0 +1,16 @@ +--- + +- name: Percona Tools is enabled + command: percona-release enable tools release + # changed_when: + # register: percona__release_enable_tools + +- name: APT cache is up-to-date + apt: + update_cache: yes + # when: percona__release_enable_tools | changed + +- name: Percona XtraBackup package is installed + apt: + name: "{{ percona__xtrabackup_package_name }}" + state: present diff --git a/proftpd/defaults/main.yml b/proftpd/defaults/main.yml index 8bba4c29..f955cd39 100644 --- a/proftpd/defaults/main.yml +++ b/proftpd/defaults/main.yml @@ -2,6 +2,13 @@ proftpd_hostname: "{{ ansible_hostname }}" proftpd_fqdn: "{{ ansible_fqdn }}" proftpd_default_address: [] -proftpd_port: "21" +proftpd_ftp_enable: True +proftpd_port: 21 +proftpd_ftps_enable: False +proftpd_ftps_port: 990 +proftpd_ftps_cert: "/etc/ssl/certs/ssl-cert-snakeoil.pem" +proftpd_ftps_key: "/etc/ssl/private/ssl-cert-snakeoil.key" +proftpd_sftp_enable: False +proftpd_sftp_port: 2222 proftpd_accounts: [] proftpd_accounts_final: [] diff --git a/proftpd/tasks/accounts.yml b/proftpd/tasks/accounts.yml index b1563eaf..95098df2 100644 --- a/proftpd/tasks/accounts.yml +++ b/proftpd/tasks/accounts.yml @@ -25,7 +25,7 @@ tags: - proftpd -- name: Allow FTP account +- name: Allow FTP account (FTP) lineinfile: dest: /etc/proftpd/conf.d/z-evolinux.conf state: present @@ -33,5 +33,30 @@ insertbefore: "DenyAll" with_items: "{{ proftpd_accounts_final }}" notify: restart proftpd + when: proftpd_ftp_enable + tags: + - proftpd + +- name: Allow FTP account (FTPS) + lineinfile: + dest: /etc/proftpd/conf.d/ftps.conf + state: present + line: "\tAllowUser {{ item.name }}" + insertbefore: "DenyAll" + with_items: "{{ proftpd_accounts_final }}" + notify: restart proftpd + when: proftpd_ftps_enable + tags: + - proftpd + +- name: Allow FTP account (SFTP) + lineinfile: + dest: /etc/proftpd/conf.d/sftp.conf + state: present + line: "\tAllowUser {{ item.name }}" + insertbefore: "DenyAll" + with_items: "{{ proftpd_accounts_final }}" + notify: restart proftpd + when: proftpd_sftp_enable tags: - proftpd diff --git a/proftpd/tasks/main.yml b/proftpd/tasks/main.yml index 5fe33dbb..71b95e9b 100644 --- a/proftpd/tasks/main.yml +++ b/proftpd/tasks/main.yml @@ -15,13 +15,36 @@ tags: - proftpd -- name: local jail is installed +- name: FTP jail is installed template: src: evolinux.conf.j2 dest: /etc/proftpd/conf.d/z-evolinux.conf mode: "0644" force: no notify: restart proftpd + when: proftpd_ftp_enable + tags: + - proftpd + +- name: FTPS jail is installed + template: + src: ftps.conf.j2 + dest: /etc/proftpd/conf.d/ftps.conf + mode: "0644" + force: no + notify: restart proftpd + when: proftpd_ftps_enable + tags: + - proftpd + +- name: SFTP jail is installed + template: + src: sftp.conf.j2 + dest: /etc/proftpd/conf.d/sftp.conf + mode: "0644" + force: no + notify: restart proftpd + when: proftpd_sftp_enable tags: - proftpd diff --git a/proftpd/templates/ftps.conf.j2 b/proftpd/templates/ftps.conf.j2 new file mode 100644 index 00000000..ceec0631 --- /dev/null +++ b/proftpd/templates/ftps.conf.j2 @@ -0,0 +1,33 @@ + + LoadModule mod_tls.c + + + + TLSEngine on + TLSLog /var/log/proftpd/ftps.log + TLSProtocol TLSv1 + + TLSRSACertificateFile {{ proftpd_ftps_cert }} + TLSRSACertificateKeyFile {{ proftpd_ftps_key }} + + #TLSOptions AllowClientRenegotiations + + TLSOptions AllowPerUser + TLSVerifyClient off + TLSRequired off + + TLSRenegotiate required off + TLSOptions NoSessionReuseRequired + + RequireValidShell off + Port {{ proftpd_ftps_port }} + AuthUserFile /etc/proftpd/vpasswd + DefaultRoot ~ + + PassivePorts 60000 61000 + + + AllowGroup ftpusers + DenyAll + + diff --git a/proftpd/templates/sftp.conf.j2 b/proftpd/templates/sftp.conf.j2 new file mode 100644 index 00000000..5f12ca9c --- /dev/null +++ b/proftpd/templates/sftp.conf.j2 @@ -0,0 +1,28 @@ + + LoadModule mod_tls.c + + + + LoadModule mod_sftp.c + + + + SFTPEngine on + Port {{ proftpd_sftp_port }} + DefaultRoot ~ + + SFTPLog /var/log/proftpd/sftp.log + + SFTPAuthMethods password + SFTPHostKey /etc/ssh/ssh_host_ecdsa_key + SFTPHostKey /etc/ssh/ssh_host_rsa_key + + RequireValidShell off + + AuthUserFile /etc/proftpd/vpasswd + + + AllowGroup ftpusers + DenyAll + + diff --git a/redis/defaults/main.yml b/redis/defaults/main.yml index a64fb832..cb8d451d 100644 --- a/redis/defaults/main.yml +++ b/redis/defaults/main.yml @@ -5,6 +5,7 @@ redis_conf_path: /etc/redis/redis.conf redis_port: 6379 redis_bind_interface: 127.0.0.1 redis_unixsocket: '/var/run/redis/redis.sock' +redis_unixsocketperm: 770 redis_pidfile: "/var/run/redis/{{ redis_daemon }}.pid" redis_timeout: 300 diff --git a/redis/templates/redis.conf.j2 b/redis/templates/redis.conf.j2 index 4dcdba86..f2f17c70 100644 --- a/redis/templates/redis.conf.j2 +++ b/redis/templates/redis.conf.j2 @@ -5,6 +5,7 @@ bind {{ redis_bind_interface }} {% if redis_unixsocket %} unixsocket {{ redis_unixsocket }} +unixsocketperm {{ redis_unixsocketperm }} {% endif %} {% if redis_password %} diff --git a/redmine/defaults/main.yml b/redmine/defaults/main.yml index 049e6551..1a260ecc 100644 --- a/redmine/defaults/main.yml +++ b/redmine/defaults/main.yml @@ -3,6 +3,7 @@ puma_env: 'production' puma_worker: 2 puma_min_thread: 0 puma_max_thread: 4 +redmine_version: "4.0.1" redmine_db_name: "{{ redmine_user }}" redmine_db_host: "localhost" redmine_db_username: "{{ redmine_user }}" diff --git a/redmine/files/Gemfile.local b/redmine/files/Gemfile.local deleted file mode 100644 index b0aa3f4d..00000000 --- a/redmine/files/Gemfile.local +++ /dev/null @@ -1,2 +0,0 @@ -gem "puma" -gem "xpath", "< 3.0.0" diff --git a/redmine/files/logrotate b/redmine/files/logrotate new file mode 100644 index 00000000..55d19257 --- /dev/null +++ b/redmine/files/logrotate @@ -0,0 +1,8 @@ +/var/log/redmine/*.log { + daily + rotate 7 + missingok + notifempty + compress + create 640 root adm +} diff --git a/redmine/files/profile b/redmine/files/profile index 57d0668e..ddfcc44f 100644 --- a/redmine/files/profile +++ b/redmine/files/profile @@ -12,7 +12,7 @@ fi # set PATH so it includes gems bin if [ -d "$HOME/bin" ] ; then - export PATH="$HOME/.gems/ruby/2.1.0/bin:$PATH" + export PATH="$HOME/www/.gem/ruby/2.3.0/bin:$PATH" fi # For systemctl --user @@ -20,4 +20,3 @@ export XDG_RUNTIME_DIR=/run/user/$UID # Ruby vars export RAILS_ENV=production -export BUNDLE_GEMFILE="$HOME/www/Gemfile" diff --git a/redmine/files/puma.service b/redmine/files/puma.service index 6e993607..f64f2580 100644 --- a/redmine/files/puma.service +++ b/redmine/files/puma.service @@ -7,7 +7,7 @@ WorkingDirectory=%h/www UMask=0027 PIDFile=%h/ruby.pid ExecStartPre=/bin/mkdir -m 0750 -p %h/run -ExecStart=/usr/bin/bundle exec puma --bind unix://%h/run/puma.sock?umask=0007 --pidfile %h/run/puma.pid --dir %h/www --config /etc/puma/%u.rb +ExecStart=%h/.rbenv/bin/rbenv exec bundle exec puma --bind unix://%h/run/puma.sock?umask=0007 --pidfile %h/run/puma.pid --dir %h/www --config %h/config/puma.rb ExecReload=/bin/kill -USR2 $MAINPID KillMode=process #Restart=on-failure diff --git a/redmine/files/syslog.conf b/redmine/files/syslog.conf new file mode 100644 index 00000000..0c31a3bf --- /dev/null +++ b/redmine/files/syslog.conf @@ -0,0 +1,4 @@ +# Send Redmine messages to a dedicated logdir +$template Redmine, "/var/log/redmine/%PROGRAMNAME:%.log" +if $programname startswith 'redmine_' then ?Redmine +&~ diff --git a/redmine/handlers/main.yml b/redmine/handlers/main.yml new file mode 100644 index 00000000..3759afc4 --- /dev/null +++ b/redmine/handlers/main.yml @@ -0,0 +1,10 @@ +--- +- name: restart rsyslog + service: + name: rsyslog + state: restarted + +- name: reload nginc + service: + name: nginx + state: reloaded diff --git a/redmine/meta/main.yml b/redmine/meta/main.yml new file mode 100644 index 00000000..72b1bd7b --- /dev/null +++ b/redmine/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - nginx diff --git a/redmine/tasks/config.yml b/redmine/tasks/config.yml new file mode 100644 index 00000000..a08ba1c6 --- /dev/null +++ b/redmine/tasks/config.yml @@ -0,0 +1,59 @@ +--- +- name: Create systemd config dir + file: + state: directory + dest: "/home/{{ redmine_user }}/{{ item }}" + mode: "0750" + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + with_items: + - ".config" + - ".config/systemd" + - ".config/systemd/user" + tags: + - redmine + +- name: Deploy systemd unit + copy: + src: puma.service + dest: "/home/{{ redmine_user }}/.config/systemd/user/puma.service" + mode: "0644" + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + tags: + - redmine + +- name: Set user .profile + copy: + src: profile + dest: "/home/{{ redmine_user }}/.profile" + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + mode: "0640" + tags: + - redmine + +- name: Create config directory + file: + path: "/home/{{ redmine_user }}/config" + state: directory + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + mode: "0750" + tags: + - redmine + +- name: Copy configurations file + template: + src: "{{ item }}.j2" + dest: "/home/{{ redmine_user }}/config/{{ item }}" + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + mode: "0640" + with_items: + - 'configuration.yml' + - 'database.yml' + - 'additional_environment.rb' + - 'puma.rb' + tags: + - redmine diff --git a/redmine/tasks/main.yml b/redmine/tasks/main.yml index d5a93a36..2b7fd225 100644 --- a/redmine/tasks/main.yml +++ b/redmine/tasks/main.yml @@ -1,319 +1,13 @@ --- -- name: Install dependancy - apt: - name: "{{ item }}" - state: present - with_items: - - libpam-systemd - - ruby - - ruby-dev - - bundler - - imagemagick - - git-core - - git-svn - - gcc - - build-essential - - libxml2-dev - - libxslt1-dev - - libssl-dev - - libmagickwand-dev - - libmagickcore-dev - - libmysqlclient-dev - - python-mysqldb - tags: - - redmine - -#- name: -# lineinfile: -# with_items: -# - 'https://github.com/.*' -# - 'http://rubygems.org/.*' -# - 'http://.*.rubygems.org/.*' -# tags: -# - redmine - -- name: Deploy systemd unit - copy: - src: puma.service - dest: /etc/systemd/user/puma.service - mode: "0644" - tags: - - redmine - -- name: Create puma config dir - file: - path: /etc/puma - state: directory - mode: "0755" - owner: root - tags: - - redmine - -- name: Create redmine group - group: - name: "{{ redmine_user }}" - state: present - tags: - - redmine - -- name: Add www-data to redmine group - user: - name: www-data - groups: "{{ redmine_user }}" - append: yes - tags: - - redmine - -- name: Create redmine user - user: - name: "{{ redmine_user }}" - state: present - group: "{{ redmine_user }}" - createhome: yes - home: "/home/{{ redmine_user }}" - shell: /bin/bash - tags: - - redmine - -- name: Create required directory - file: - path: "{{ item }}" - state: directory - owner: "{{ redmine_user }}" - group: "{{ redmine_user }}" - mode: "0750" - with_items: - - "/home/{{ redmine_user }}" - - "/home/{{ redmine_user }}/files" - - "/home/{{ redmine_user }}/log" - tags: - - redmine - -- name: Touch Nginx logs file - file: - path: "/home/{{ redmine_user }}/log/{{ item }}" - state: touch - owner: "root" - group: "{{ redmine_user }}" - mode: "0640" - changed_when: false - with_items: - - nginx_access.log - - nginx_error.log - tags: - - redmine - -- name: Enable systemd user mode - command: "loginctl enable-linger {{ redmine_user }}" - changed_when: false - -- name: Set user .profile - copy: - src: profile - dest: "/home/{{ redmine_user }}/.profile" - owner: "{{ redmine_user }}" - group: "{{ redmine_user }}" - mode: "0640" - tags: - - redmine - -- name: Update or clone Redmine git - git: - repo: 'https://github.com/redmine/redmine.git' - dest: "/home/{{ redmine_user }}/www" - version: '3.4-stable' - umask: "027" - update: yes - become_user: "{{ redmine_user }}" - become: yes - register: redmine_git_task - tags: - - redmine - -- name: Deploy custom Gemfile - copy: - src: Gemfile.local - dest: "/home/{{ redmine_user }}/www" - owner: "{{ redmine_user }}" - group: "{{ redmine_user }}" - mode: "0640" - register: redmine_local_gemfile_task - tags: - - redmine - -- name: Get actual Mysql password - shell: "grep password /home/{{ redmine_user }}/.my.cnf | awk '{ print $3 }'" - register: redmine_get_mysql_password - check_mode: no - changed_when: False - failed_when: false - tags: - - redmine - -- name: Generate Mysql password - shell: perl -e 'print map{("a".."z","A".."Z",0..9)[int(rand(62))]}(1..16)' - register: redmine_generate_mysql_password - check_mode: no - changed_when: False - when: redmine_get_mysql_password.stdout == "" - tags: - - redmine - -- name: Set Mysql password - set_fact: - redmine_db_pass: "{{ redmine_generate_mysql_password.stdout | default(redmine_get_mysql_password.stdout) }}" - tags: - - redmine - -- name: Create Mysql database - mysql_db: - name: "{{ redmine_db_name }}" - config_file: "/root/.my.cnf" - state: present - tags: - - redmine - -- name: Create Mysql user - mysql_user: - name: "{{ redmine_db_username }}" - password: '{{ redmine_db_pass }}' - priv: "{{ redmine_user }}.*:ALL" - config_file: "/root/.my.cnf" - update_password: always - state: present - tags: - - redmine - -- name: Store credentials in my.cnf - ini_file: - dest: "/home/{{ redmine_user }}/.my.cnf" - owner: "{{ redmine_user }}" - group: "{{ redmine_user }}" - mode: "0600" - section: client - option: '{{ item.option }}' - value: '{{ item.value }}' - with_items: - - { option: 'host', value: "{{ redmine_db_host }}" } - - { option: 'user', value: "{{ redmine_db_username }}" } - - { option: 'database', value: "{{ redmine_db_name }}" } - - { option: 'password', value: '{{ redmine_db_pass }}' } - tags: - - redmine - -- name: Copy configurations file - template: - src: "{{ item }}.j2" - dest: "/home/{{ redmine_user }}/www/config/{{ item }}" - owner: "{{ redmine_user }}" - group: "{{ redmine_user }}" - mode: "0640" - with_items: - - 'configuration.yml' - - 'database.yml' - - 'additional_environment.rb' - tags: - - redmine - -- name: Install Redmine plugins - include: plugins.yml - with_items: "{{ redmine_plugins }}" - tags: - - redmine - -- name: Install Redmine themes - include: themes.yml - with_items: "{{ redmine_themes }}" - tags: - - redmine - -- name: Update local gems with bundle - bundler: - state: present - gemfile: "/home/{{ redmine_user }}/www/Gemfile" - gem_path: "/home/{{ redmine_user }}/.gems" - user_install: yes - become_user: "{{ redmine_user }}" - become: yes - when: redmine_git_task.changed or redmine_local_gemfile_task.changed or redmine_plugin_install.changed - tags: - - redmine - -- name: Migrate database with rake - shell: bundle exec rake -qf ~/www/Rakefile db:migrate - become_user: "{{ redmine_user }}" - become_method: sudo - become_flags: '-iu {{ redmine_user }}' - become: yes - when: redmine_git_task.changed - tags: - - redmine - -- name: Populate Mysql database - shell: bundle exec rake -qf ~/www/Rakefile redmine:load_default_data REDMINE_LANG=fr && touch ~/.populated - args: - creates: "/home/{{ redmine_user }}/.populated" - become_user: "{{ redmine_user }}" - become_method: sudo - become_flags: '-iu {{ redmine_user }}' - become: yes - tags: - - redmine - -- name: Migrate plugins - shell: bundle exec rake -qf ~/www/Rakefile redmine:plugins:migrate - become_user: "{{ redmine_user }}" - become_method: sudo - become_flags: '-iu {{ redmine_user }}' - become: yes - when: redmine_plugin_install.changed - tags: - - redmine - -- name: Generate secret token - shell: bundle exec rake -qf ~/www/Rakefile generate_secret_token - args: - creates: "/home/{{ redmine_user }}/www/config/initializers/secret_token.rb" - become_user: "{{ redmine_user }}" - become_method: sudo - become_flags: '-iu {{ redmine_user }}' - become: yes - tags: - - redmine - -- name: Copy puma config - template: - src: puma.rb.j2 - dest: "/etc/puma/{{ redmine_user }}.rb" - owner: "{{ redmine_user }}" - group: "{{ redmine_user }}" - mode: "0640" - register: redmine_puma_config_task - tags: - - redmine - -- name: Start puma service - systemd: - name: puma - daemon_reload: yes - enabled: yes - state: started - user: yes - become_user: "{{ redmine_user }}" - become_method: sudo - become_flags: '-iu {{ redmine_user }}' - become: yes - tags: - - redmine - -- name: Reload puma service - systemd: - name: puma - daemon_reload: yes - state: reloaded - user: yes - become_user: "{{ redmine_user }}" - become_method: sudo - become_flags: '-iu {{ redmine_user }}' - become: yes - when: redmine_puma_config_task.changed +- include: packages.yml +- include: syslog.yml +- include: user.yml +- include_role: + name: rbenv + vars: + - username: "{{ redmine_user }}" +- include: config.yml +- include: mysql.yml +- include: source.yml +- include: release.yml +- include: nginx.yml diff --git a/redmine/tasks/mysql.yml b/redmine/tasks/mysql.yml new file mode 100644 index 00000000..414da319 --- /dev/null +++ b/redmine/tasks/mysql.yml @@ -0,0 +1,62 @@ +--- +- name: Get actual Mysql password + shell: "grep password /home/{{ redmine_user }}/.my.cnf | awk '{ print $3 }'" + register: redmine_get_mysql_password + check_mode: no + changed_when: False + failed_when: false + tags: + - redmine + +- name: Generate Mysql password + shell: perl -e 'print map{("a".."z","A".."Z",0..9)[int(rand(62))]}(1..16)' + register: redmine_generate_mysql_password + check_mode: no + changed_when: False + when: redmine_get_mysql_password.stdout == "" + tags: + - redmine + +- name: Set Mysql password + set_fact: + redmine_db_pass: "{{ redmine_generate_mysql_password.stdout | default(redmine_get_mysql_password.stdout) }}" + tags: + - redmine + +- name: Create Mysql database + mysql_db: + name: "{{ redmine_db_name }}" + config_file: "/root/.my.cnf" + state: present + collation: "utf8_general_ci" + register: redmine_mysql_create + tags: + - redmine + +- name: Store credentials in my.cnf + ini_file: + dest: "/home/{{ redmine_user }}/.my.cnf" + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + mode: "0600" + section: client + option: '{{ item.option }}' + value: '{{ item.value }}' + with_items: + - { option: 'host', value: "{{ redmine_db_host }}" } + - { option: 'user', value: "{{ redmine_db_username }}" } + - { option: 'database', value: "{{ redmine_db_name }}" } + - { option: 'password', value: '{{ redmine_db_pass }}' } + tags: + - redmine + +- name: Create Mysql user + mysql_user: + name: "{{ redmine_db_username }}" + password: '{{ redmine_db_pass }}' + priv: "{{ redmine_user }}.*:ALL" + config_file: "/root/.my.cnf" + update_password: always + state: present + tags: + - redmine diff --git a/redmine/tasks/nginx.yml b/redmine/tasks/nginx.yml new file mode 100644 index 00000000..3940de17 --- /dev/null +++ b/redmine/tasks/nginx.yml @@ -0,0 +1,26 @@ +--- +- name: Add www-data to Redmine group + user: + name: www-data + groups: "{{ redmine_user }}" + append: True + tags: + - redmine + +- name: Copy nginx vhost + template: + src: nginx.conf.j2 + dest: "/etc/nginx/sites-available/{{ redmine_user }}.conf" + mode: "0644" + notify: reload nginx + tags: + - redmine + +- name: Enable nginx vhost + file: + src: "/etc/nginx/sites-available/{{ redmine_user }}.conf" + dest: "/etc/nginx/sites-enabled/{{ redmine_user }}.conf" + state: link + notify: reload nginx + tags: + - redmine diff --git a/redmine/tasks/packages.yml b/redmine/tasks/packages.yml new file mode 100644 index 00000000..2ac00fe9 --- /dev/null +++ b/redmine/tasks/packages.yml @@ -0,0 +1,21 @@ +--- +- name: Install dependancy + apt: + name: "{{ item }}" + state: present + with_items: + - libpam-systemd + - imagemagick + - git-core + - git-svn + - gcc + - build-essential + - libxml2-dev + - libxslt1-dev + - libssl-dev + - libmagickwand-dev + - libmagickcore-dev + - libmariadbclient-dev + - python-mysqldb + tags: + - redmine diff --git a/redmine/tasks/plugins.yml b/redmine/tasks/plugins.yml deleted file mode 100644 index 479ffeaf..00000000 --- a/redmine/tasks/plugins.yml +++ /dev/null @@ -1,28 +0,0 @@ ---- -- name: Copy/Update plugin from archive - unarchive: - src: "{{ item.zip }}" - dest: "/home/{{ redmine_user }}/www/plugins/" - remote_src: yes - owner: "{{ redmine_user }}" - group: "{{ redmine_user }}" - mode: "0750" - register: redmine_plugin_install - when: item.zip is defined - -- name: Copy/Update plugin from git repository - git: - repo: "{{ item.git }}" - dest: "/home/{{ redmine_user }}/www/plugins/{{ item.git | basename | splitext | first }}" - version: "{{ item.tree | default('master') }}" - register: redmine_plugin_install - when: item.git is defined - -- name: Fix rights on plugin dir - file: - path: "/home/{{ redmine_user }}/www/plugins/{{ item.git | basename | splitext | first }}" - owner: "{{ redmine_user }}" - group: "{{ redmine_user }}" - mode: "u=rwX,g=rX,o=" - recurse: True - when: item.git is defined diff --git a/redmine/tasks/release.yml b/redmine/tasks/release.yml new file mode 100644 index 00000000..730b0877 --- /dev/null +++ b/redmine/tasks/release.yml @@ -0,0 +1,123 @@ +--- +- name: Get id of user + command: "id -u {{ redmine_user }}" + register: redmine_command_user_id + changed_when: False + check_mode: False + tags: + - redmine + +- name: Define user environment + set_fact: + user_env: + XDG_RUNTIME_DIR: "/run/user/{{ redmine_command_user_id.stdout }}" + RAILS_ENV: production + tags: + - redmine + +- name: Stop puma service + systemd: + name: puma + daemon_reload: yes + state: stopped + user: yes + become_user: "{{ redmine_user }}" + environment: "{{ user_env }}" + tags: + - redmine + +- name: Create mysqldump directory + file: + path: "/home/{{ redmine_user }}/mysqldump" + state: directory + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + mode: "0750" + tags: + - redmine + +- name: Dump mysql database + mysql_db: + state: dump + config_file: "/home/{{ redmine_user }}/.my.cnf" + name: "{{ redmine_db_name }}" + target: "/home/{{ redmine_user }}/mysqldump/{{ ansible_date_time.iso8601_basic_short }}.sql.gz" + tags: + - redmine + +- name: Change www link + file: + state: link + src: "/home/{{ redmine_user }}/releases/{{ redmine_version }}" + dest: "/home/{{ redmine_user }}/www" + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + tags: + - redmine + +- name: Update Gemfile.lock + command: "~/.rbenv/bin/rbenv exec bundle lock" + args: + chdir: "/home/{{ redmine_user }}/www" + become_user: "{{ redmine_user }}" + become: yes + tags: + - redmine + +- name: Update local gems with bundle + command: "~/.rbenv/bin/rbenv exec bundle install --deployment" + args: + chdir: "/home/{{ redmine_user }}/www" + become_user: "{{ redmine_user }}" + become: yes + tags: + - redmine + +- name: Generate secret token + command: "~/.rbenv/bin/rbenv exec bundle exec rake -q generate_secret_token" + args: + chdir: "/home/{{ redmine_user }}/www" + creates: "/home/{{ redmine_user }}/www/config/initializers/secret_token.rb" + become_user: "{{ redmine_user }}" + environment: "{{ user_env }}" + tags: + - redmine + +- name: Migrate database with rake + command: "~/.rbenv/bin/rbenv exec bundle exec rake -q db:migrate" + args: + chdir: "/home/{{ redmine_user }}/www/" + become_user: "{{ redmine_user }}" + environment: "{{ user_env }}" + tags: + - redmine + +- name: Populate Mysql database + command: "~/.rbenv/bin/rbenv exec bundle exec rake -q redmine:load_default_data REDMINE_LANG=fr" + args: + chdir: "/home/{{ redmine_user }}/www/" + become_user: "{{ redmine_user }}" + environment: "{{ user_env }}" + when: redmine_mysql_create.changed + tags: + - redmine + +- name: Migrate plugins + command: "~/.rbenv/bin/rbenv exec bundle exec rake -q redmine:plugins:migrate" + args: + chdir: "/home/{{ redmine_user }}/www/" + become_user: "{{ redmine_user }}" + environment: "{{ user_env }}" + tags: + - redmine + +- name: Start puma service + systemd: + name: puma + daemon_reload: yes + state: started + user: yes + become_user: "{{ redmine_user }}" + environment: "{{ user_env }}" + tags: + - redmine diff --git a/redmine/tasks/source.yml b/redmine/tasks/source.yml new file mode 100644 index 00000000..51427acf --- /dev/null +++ b/redmine/tasks/source.yml @@ -0,0 +1,98 @@ +--- +- name: Create releases directory + file: + path: "/home/{{ redmine_user }}/{{ item }}" + state: directory + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + mode: "0750" + with_items: + - "releases" + - "releases/{{ redmine_version }}" + tags: + - redmine + +- name: Download Redmine archive + unarchive: + src: "https://redmine.org/releases/redmine-{{ redmine_version }}.tar.gz" + dest: "/home/{{ redmine_user }}/releases/{{ redmine_version }}" + remote_src: True + extra_opts: --strip-components=1 + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + tags: + - redmine + +- name: Link config files + file: + state: link + src: "/home/{{ redmine_user }}/config/{{ item }}" + dest: "/home/{{ redmine_user }}/releases/{{ redmine_version }}/config/{{ item }}" + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + with_items: + - 'configuration.yml' + - 'database.yml' + - 'additional_environment.rb' + tags: + - redmine + +- name: Copy/Update plugin from archive + unarchive: + src: "{{ item.zip }}" + dest: "/home/{{ redmine_user }}/releases/{{ redmine_version }}/plugins/" + remote_src: yes + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + mode: "0750" + when: item.zip is defined + with_items: "{{ redmine_plugins }}" + tags: + - redmine + +- name: Copy/Update plugin from git repository + git: + repo: "{{ item.git }}" + dest: "/home/{{ redmine_user }}/releases/{{ redmine_version }}/plugins/{{ item.git | basename | splitext | first }}" + version: "{{ item.tree | default('master') }}" + umask: "027" + become_user: "{{ redmine_user }}" + when: item.git is defined + with_items: "{{ redmine_plugins }}" + tags: + - redmine + +- name: Copy/Update theme from archive + unarchive: + src: "{{ item.zip }}" + dest: "/home/{{ redmine_user }}/releases/{{ redmine_version }}/public/themes" + remote_src: yes + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + mode: "0750" + when: item.zip is defined + with_items: "{{ redmine_themes }}" + tags: + - redmine + +- name: Copy/Update theme from git repository + git: + repo: "{{ item.git }}" + dest: "/home/{{ redmine_user }}/releases/{{ redmine_version }}/public/themes/{{ item.git | basename | splitext | first }}" + version: "{{ item.tree | default('master') }}" + umask: "027" + become_user: "{{ redmine_user }}" + when: item.git is defined + with_items: "{{ redmine_themes }}" + tags: + - redmine + +- name: Deploy custom Gemfile + template: + src: Gemfile.local.j2 + dest: "/home/{{ redmine_user }}/releases/{{ redmine_version }}/Gemfile.local" + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + mode: "0640" + tags: + - redmine diff --git a/redmine/tasks/syslog.yml b/redmine/tasks/syslog.yml new file mode 100644 index 00000000..b53e2660 --- /dev/null +++ b/redmine/tasks/syslog.yml @@ -0,0 +1,27 @@ +--- +- name: Create log directory + file: + state: directory + dest: /var/log/redmine + owner: root + group: adm + mode: "0750" + tags: + - redmine + +- name: Copy syslog configuration + copy: + src: syslog.conf + dest: /etc/rsyslog.d/redmine.conf + mode: "0644" + notify: restart rsyslog + tags: + - redmine + +- name: Copy logrotate configuration + copy: + src: logrotate + dest: /etc/logrotate.d/redmine + mode: "0644" + tags: + - redmine diff --git a/redmine/tasks/themes.yml b/redmine/tasks/themes.yml deleted file mode 100644 index 510e2038..00000000 --- a/redmine/tasks/themes.yml +++ /dev/null @@ -1,26 +0,0 @@ ---- -- name: Copy/Update theme from archive - unarchive: - src: "{{ item.zip }}" - dest: "/home/{{ redmine_user }}/www/public/themes/" - remote_src: yes - owner: "{{ redmine_user }}" - group: "{{ redmine_user }}" - mode: "0750" - when: item.zip is defined - -- name: Copy/Update theme from git repository - git: - repo: "{{ item.git }}" - dest: "/home/{{ redmine_user }}/www/public/themes/{{ item.git | basename | splitext | first }}" - version: "{{ item.tree | default('master') }}" - when: item.git is defined - -- name: Fix rights on theme dir - file: - path: "/home/{{ redmine_user }}/www/public/themes/{{ item.git | basename | splitext | first }}" - owner: "{{ redmine_user }}" - group: "{{ redmine_user }}" - mode: "0750" - recurse: True - when: item.git is defined diff --git a/redmine/tasks/user.yml b/redmine/tasks/user.yml new file mode 100644 index 00000000..ecc5b6d5 --- /dev/null +++ b/redmine/tasks/user.yml @@ -0,0 +1,44 @@ +--- +- name: Create redmine group + group: + name: "{{ redmine_user }}" + state: present + tags: + - redmine + +- name: Create redmine user + user: + name: "{{ redmine_user }}" + state: present + group: "{{ redmine_user }}" + createhome: yes + home: "/home/{{ redmine_user }}" + shell: /bin/bash + tags: + - redmine + +- name: Add redmine user to Redis group + user: + name: "{{ redmine_user }}" + groups: "redis-{{ redmine_user }}" + append: True + when: redmine_redis_path is defined + tags: + - redmine + +- name: Create required directory + file: + path: "{{ item }}" + state: directory + owner: "{{ redmine_user }}" + group: "{{ redmine_user }}" + mode: "0750" + with_items: + - "/home/{{ redmine_user }}" + - "/home/{{ redmine_user }}/files" + tags: + - redmine + +- name: Enable systemd user mode + command: "loginctl enable-linger {{ redmine_user }}" + changed_when: false diff --git a/redmine/templates/Gemfile.local.j2 b/redmine/templates/Gemfile.local.j2 new file mode 100644 index 00000000..72f9857a --- /dev/null +++ b/redmine/templates/Gemfile.local.j2 @@ -0,0 +1,5 @@ +gem "syslogger" +{% if redmine_redis_path is defined %} +gem "redis-rails" +gem "redis-rack-cache" +{% endif %} diff --git a/redmine/templates/additional_environment.rb.j2 b/redmine/templates/additional_environment.rb.j2 index b6065a57..9427c305 100644 --- a/redmine/templates/additional_environment.rb.j2 +++ b/redmine/templates/additional_environment.rb.j2 @@ -1,2 +1,13 @@ -config.paths['log'] = "/home/{{ redmine_user }}/log/redmine.log" -config.log_level = :warn +config.log_level = :info +config.logger = Syslogger.new("redmine_{{ redmine_user }}") +{% if redmine_redis_path is defined %} +config.session_store :redis_store, + servers: { path: '{{ redmine_redis_path }}', db: 0, namespace: "session" } +config.cache_store = :redis_store, + "redis://{{ redmine_redis_path }}/cache_rails", + { expires_in: 90.minutes } +config.action_dispatch.rack_cache = { + metastore: "redis://{{ redmine_redis_path }}/cache_metastore", + entitystore: "redis://{{ redmine_redis_path }}/cache_entitystore" +} +{% endif %} diff --git a/redmine/templates/nginx.conf.j2 b/redmine/templates/nginx.conf.j2 new file mode 100644 index 00000000..3356ad19 --- /dev/null +++ b/redmine/templates/nginx.conf.j2 @@ -0,0 +1,44 @@ +upstream puma_{{ redmine_user }} { + server unix:/home/{{ redmine_user }}/run/puma.sock fail_timeout=0; +} +server { + server_name {{ redmine_domain }}; + + listen 0.0.0.0:80; + listen [::]:80; + listen 0.0.0.0:443 ssl http2; + listen [::]:443 ssl http2; + + if ( $scheme = http ) { + return 301 https://$server_name$request_uri; + } + + include /etc/nginx/ssl/{{ redmine_user }}[.]conf; + root /home/{{ redmine_user }}/www/public; + access_log /var/log/nginx/{{ redmine_user }}_access.log; + error_log /var/log/nginx/{{ redmine_user }}_error.log; + error_page 503 @maintenance; + client_max_body_size 50M; + + include /etc/nginx/snippets/letsencrypt[.]conf; + + location / { + if (!-f /home/{{ redmine_user }}/run/puma.pid) { + return 503; + } + try_files $uri @puma; + } + + location @maintenance { + rewrite ^(.*)$ /500.html break; + } + + location @puma { + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Host $http_host; + proxy_redirect off; + proxy_read_timeout 30; + proxy_pass http://puma_{{ redmine_user }}; + } +}