diff --git a/roles/includes/webapps_create_mysql_db.yml b/roles/includes/webapps_create_mysql_db.yml index 9d1b453..4ec07fa 100644 --- a/roles/includes/webapps_create_mysql_db.yml +++ b/roles/includes/webapps_create_mysql_db.yml @@ -15,6 +15,7 @@ mysql_db: name: "{{ db_name }}" login_host: "{{ db_server | default(mysql_server) }}" + login_port: "{{ db_port | default(omit) }}" login_user: sqladmin login_password: "{{ mysql_admin_pass }}" state: present @@ -30,6 +31,7 @@ append_privs: "{{ append_privs | default(False) }}" host: "{{ ( db_server == 'localhost' ) | ternary('localhost', item ) }}" login_host: "{{ db_server }}" + login_port: "{{ db_port | default(omit) }}" login_user: sqladmin login_password: "{{ mysql_admin_pass }}" state: present diff --git a/roles/sftpgo/defaults/main.yml b/roles/sftpgo/defaults/main.yml new file mode 100644 index 0000000..6b80769 --- /dev/null +++ b/roles/sftpgo/defaults/main.yml @@ -0,0 +1,100 @@ +--- + +# Version to deploy +sftpgo_version: 2.1.2 +# URL of the archive +sftpgo_archive_url: https://github.com/drakkan/sftpgo/releases/download/v{{ sftpgo_version }}/sftpgo_v{{ sftpgo_version }}_linux_x86_64.tar.xz +# Expected sha1 of the archive +sftpgo_archive_sha1: 6b9ea26c53d62b47eec3ad18afeb90b6651df10c + +# Should ansible handle upgrades ? If False, only initial install will be done +sftpgo_manage_upgrade: True + +# Root dir where sftpgo will be installed +sftpgo_root_dir: /opt/sftpgo + +# User account under which sftpgo will run +sftpgo_user: sftpgo + +# Database settings +sftpgo_db_server: "{{ mysql_server | default('localhost') }}" +sftpgo_db_port: 3306 +sftpgo_db_name: sftpgo +sftpgo_db_user: sftpgo +# If the password is not defined, a random one will be created and stored under {{ sftpgo_root_dir }}/meta/ansible_dbpass +# sftpgo_db_pass: S3cr3t. + +# You can restrict access per port. This can be a list of IP (or network in CIDR notation) +# Access will be controlled by iptables +sftpgo_src_ip: [] +sftpgo_sftp_src_ip: "{{ sftpgo_src_ip }}" +sftpgo_ftp_src_ip: "{{ sftpgo_src_ip }}" +sftpgo_webdav_src_ip: "{{ sftpgo_src_ip }}" +sftpgo_http_src_ip: "{{ sftpgo_src_ip }}" + +# Base configuration of the service +sftpgo_base_conf: + common: + upload_mode: 1 + setstat_mode: 1 + temp_path: "{{ sftpgo_root_dir }}/tmp" + max_total_connections: 500 + max_per_host_connections: 20 + defender: + enabled: True + ban_time: 5 + ban_time_increment: 50 + threshold: 20 + score_invalid: 10 + score_valid: 1 + score_limit_exceeded: 10 + observation_time: 10 + sftpd: + bindings: + port: 2022 + max_auth_tries: 4 + ftpd: + bindings: + port: 2021 + passive_port_range: + start: 50000 + end: 50200 + force_passive_ip: '' + disable_active_mode: True + webdavd: + bindings: + port: 2080 + prefix: /dav + proxy_allowed: [] + data_provider: + driver: mysql + name: "{{ sftpgo_db_name }}" + host: "{{ sftpgo_db_server }}" + port: "{{ sftpgo_db_port }}" + username: "{{ sftpgo_db_user }}" + password: "{{ sftpgo_db_pass }}" + track_quota: 1 + delayed_quota_update: 60 + pool_size: 5 + users_base_dir: "{{ sftpgo_root_dir }}/data/home/" + httpd: + bindings: + port: 8080 + address: '' + proxy_allowed: [] + enable_web_admin: True + enable_web_client: True + templates_path: "{{ sftpgo_root_dir }}/app/templates" + static_files_path: "{{ sftpgo_root_dir }}/app/static" + backups_path: "{{ sftpgo_root_dir }}/backup" + max_upload_file_size: 1048576000 + telemetry: + bind_port: 0 + +# You can override and/or add custom settings here. Same format as sftpgo_base_conf +# The extra conf will be merged on top of the base conf +sftpgo_extra_conf: {} +sftpgo_conf: "{{ sftpgo_base_conf | combine(sftpgo_extra_conf, recursive=True) }}" + + + diff --git a/roles/sftpgo/handlers/main.yml b/roles/sftpgo/handlers/main.yml new file mode 100644 index 0000000..571b569 --- /dev/null +++ b/roles/sftpgo/handlers/main.yml @@ -0,0 +1,4 @@ +--- + +- name: restart sftpgo + service: name=sftpgo state=restarted diff --git a/roles/sftpgo/meta/main.yml b/roles/sftpgo/meta/main.yml new file mode 100644 index 0000000..d8c4089 --- /dev/null +++ b/roles/sftpgo/meta/main.yml @@ -0,0 +1,5 @@ +--- + +dependencies: + - role: mysql_server + when: sftpgo_db_server in ['localhost','127.0.0.1'] diff --git a/roles/sftpgo/tasks/archive_post.yml b/roles/sftpgo/tasks/archive_post.yml new file mode 100644 index 0000000..3b88c9e --- /dev/null +++ b/roles/sftpgo/tasks/archive_post.yml @@ -0,0 +1,10 @@ +--- + +- name: Compress previous version + command: tar cf {{ sftpgo_root_dir }}/archives/{{ sftpgo_current_version }}.tar.zst --use-compress-program=zstd ./ + args: + chdir: "{{ sftpgo_root_dir }}/archives/{{ sftpgo_current_version }}" + warn: False + environment: + ZSTD_CLEVEL: 10 + tags: sftpgo diff --git a/roles/sftpgo/tasks/archive_pre.yml b/roles/sftpgo/tasks/archive_pre.yml new file mode 100644 index 0000000..c7bef17 --- /dev/null +++ b/roles/sftpgo/tasks/archive_pre.yml @@ -0,0 +1,23 @@ +--- + +- name: Create the archive dir + file: path={{ sftpgo_root_dir }}/archives/{{ sftpgo_current_version }} state=directory + tags: sftpgo + +- name: Backup previous version + copy: src={{ sftpgo_root_dir }}/app dest={{ sftpgo_root_dir }}/archives/{{ sftpgo_current_version }}/ remote_src=True + tags: sftpgo + +- name: Archive the database + mysql_db: + state: dump + name: "{{ sftpgo_db_name }}" + target: "{{ sftpgo_root_dir }}/archives/{{ sftpgo_current_version }}/{{ sftpgo_db_name }}.sql.xz" + login_host: "{{ sftpgo_db_server }}" + login_user: sqladmin + login_password: "{{ mysql_admin_pass }}" + quick: True + single_transaction: True + environment: + XZ_OPT: -T0 + tags: sftpgo diff --git a/roles/sftpgo/tasks/cleanup.yml b/roles/sftpgo/tasks/cleanup.yml new file mode 100644 index 0000000..7b285f9 --- /dev/null +++ b/roles/sftpgo/tasks/cleanup.yml @@ -0,0 +1,9 @@ +--- + +- name: Remove tmp and obsolete files + file: path={{ item }} state=absent + loop: + - "{{ sftpgo_root_dir }}/archives/{{ sftpgo_current_version }}" + - "{{ sftpgo_root_dir }}/tmp/sftpgo_v{{ sftpgo_version }}_linux_x86_64.tar.xz" + - "{{ sftpgo_root_dir }}/tmp/{{ sftpgo_version }}" + tags: sftpgo diff --git a/roles/sftpgo/tasks/conf.yml b/roles/sftpgo/tasks/conf.yml new file mode 100644 index 0000000..743d514 --- /dev/null +++ b/roles/sftpgo/tasks/conf.yml @@ -0,0 +1,12 @@ +--- + +- name: Deploy sftpgo config + template: src=sftpgo.yml.j2 dest={{ sftpgo_root_dir }}/etc/sftpgo.yml group={{ sftpgo_user }} mode=640 + notify: restart sftpgo + tags: sftpgo + +- name: Init or upgrade the database + command: "{{ sftpgo_root_dir }}/app/sftpgo --config-file {{ sftpgo_root_dir }}/etc/sftpgo.yml initprovider" + become_user: "{{ sftpgo_user }}" + when: sftpgo_install_mode != 'none' + tags: sftpgo diff --git a/roles/sftpgo/tasks/directories.yml b/roles/sftpgo/tasks/directories.yml new file mode 100644 index 0000000..7e299e0 --- /dev/null +++ b/roles/sftpgo/tasks/directories.yml @@ -0,0 +1,29 @@ +--- + +- name: Create directories + file: path={{ sftpgo_root_dir }}/{{ item.dir }} state=directory owner={{ item.owner | default(omit) }} group={{ item.group | default(omit) }} mode={{ item.mode | default(omit) }} + loop: + - dir: / + owner: "{{ sftpgo_user }}" + mode: 700 + - dir: meta + mode: 700 + - dir: archives + omde: 700 + - dir: tmp + owner: "{{ sftpgo_user }}" + mode: 700 + - dir: etc + owner: "{{ sftpgo_user }}" + mode: 700 + - dir: bin + - dir: data + owner: "{{ sftpgo_user }}" + mode: 700 + - dir: data/home + owner: "{{ sftpgo_user }}" + mode: 700 + - dir: backup + owner: "{{ sftpgo_user }}" + mode: 700 + tags: sftpgo diff --git a/roles/sftpgo/tasks/facts.yml b/roles/sftpgo/tasks/facts.yml new file mode 100644 index 0000000..072cb3b --- /dev/null +++ b/roles/sftpgo/tasks/facts.yml @@ -0,0 +1,28 @@ +--- + +- include_vars: "{{ item }}" + with_first_found: + - vars/{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml + - vars/{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml + - vars/{{ ansible_distribution }}.yml + - vars/{{ ansible_os_family }}.yml + tags: sftpgo + +- name: Detect installed version + block: + - import_tasks: ../includes/webapps_set_install_mode.yml + vars: + - root_dir: "{{ sftpgo_root_dir }}" + - version: "{{ sftpgo_version }}" + - set_fact: sftpgo_install_mode={{ (install_mode == 'upgrade' and not sftpgo_manage_upgrade) | ternary('none',install_mode) }} + - set_fact: sftpgo_current_version={{ current_version | default('') }} + tags: sftpgo + +- when: sftpgo_db_pass is not defined + name: Generate a random pass for the database + block: + - import_tasks: ../includes/get_rand_pass.yml + vars: + - pass_file: "{{ sftpgo_root_dir }}/meta/ansible_dbpass" + - set_fact: sftpgo_db_pass={{ rand_pass }} + tags: sftpgo diff --git a/roles/sftpgo/tasks/install.yml b/roles/sftpgo/tasks/install.yml new file mode 100644 index 0000000..f5da6d8 --- /dev/null +++ b/roles/sftpgo/tasks/install.yml @@ -0,0 +1,71 @@ +--- + +- name: Install dependencies + package: + name: "{{ sftpgo_packages }}" + tags: sftpgo + +- name: Stop the service during upgrades + service: name=sftpgo state=stopped + when: sftpgo_install_mode == 'upgrade' + tags: sftpgo + +- when: sftpgo_install_mode != 'none' + block: + + - name: Download sftpgo + get_url: + url: "{{ sftpgo_archive_url }}" + dest: "{{ sftpgo_root_dir }}/tmp/" + checksum: sha1:{{ sftpgo_archive_sha1 }} + + - name: Create tmp dir + file: path={{ sftpgo_root_dir }}/tmp/{{ sftpgo_version }} state=directory + + - name: Extract sftpgo archive + unarchive: + src: "{{ sftpgo_root_dir }}/tmp/sftpgo_v{{ sftpgo_version }}_linux_x86_64.tar.xz" + dest: "{{ sftpgo_root_dir }}/tmp/{{ sftpgo_version }}" + remote_src: True + + - name: Install or update the app + synchronize: + src: "{{ sftpgo_root_dir }}/tmp/{{ sftpgo_version }}/{{ item }}" + dest: "{{ sftpgo_root_dir }}/app/" + compress: False + delete: True + loop: + - sftpgo + - templates + - static + delegate_to: "{{ inventory_hostname }}" + notify: restart sftpgo + + tags: sftpgo + +- name: Install systemd unit + template: src=sftpgo.service.j2 dest=/etc/systemd/system/sftpgo.service + register: sftpgo_unit + tags: sftpgo + +- name: Reload systemd + systemd: daemon_reload=True + when: sftpgo_unit.changed + tags: sftpgo + + # Create MySQL database +- import_tasks: ../includes/webapps_create_mysql_db.yml + vars: + - db_name: "{{ sftpgo_db_name }}" + - db_user: "{{ sftpgo_db_user }}" + - db_server: "{{ sftpgo_db_server }}" + - db_port: "{{ sftpgo_db_port }}" + - db_pass: "{{ sftpgo_db_pass }}" + tags: sftpgo + +- name: Install backups hooks + template: src={{ item }}-backup.j2 dest=/etc/backup/{{ item }}.d/sftpgo mode=700 + loop: + - pre + - post + tags: sftpgo diff --git a/roles/sftpgo/tasks/iptables.yml b/roles/sftpgo/tasks/iptables.yml new file mode 100644 index 0000000..bdf8065 --- /dev/null +++ b/roles/sftpgo/tasks/iptables.yml @@ -0,0 +1,21 @@ +--- + +- name: Handle sftpgo ports in the firewall + iptables_raw: + name: "{{ item.name }}" + state: "{{ (item.src_ip | length > 0) | ternary('present','absent') }}" + rules: "-A INPUT -m state --state NEW -p tcp {{ item.port is string | ternary('--dport ' ~ item.port, '-m multiport --dports ' ~ item.port | join(',')) }} -s {{ item.src_ip | join(',') }} -j ACCEPT" + with_items: + - port: "{{ sftpgo_conf.sftpd.bindings.port }}" + name: sftpgo_sftp_port + src_ip: "{{ sftpgo_sftp_src_ip }}" + - port: "{{ [sftpgo_conf.ftpd.bindings.port,sftpgo_conf.ftpd.passive_port_range.start ~ ':' ~ sftpgo_conf.ftpd.passive_port_range.end] }}" + name: sftpgo_ftp_port + src_ip: "{{ sftpgo_ftp_src_ip }}" + - port: "{{ sftpgo_conf.webdavd.bindings.port }}" + name: sftpgo_webdav_port + src_ip: "{{ sftpgo_webdav_src_ip }}" + - port: "{{ sftpgo_conf.httpd.bindings.port }}" + name: sftpgo_http_port + src_ip: "{{ sftpgo_http_src_ip }}" + tags: firewall,sftpgo diff --git a/roles/sftpgo/tasks/main.yml b/roles/sftpgo/tasks/main.yml new file mode 100644 index 0000000..739dd38 --- /dev/null +++ b/roles/sftpgo/tasks/main.yml @@ -0,0 +1,18 @@ +--- + +- include: user.yml +- include: directories.yml +- include: facts.yml +- include: archive_pre.yml + when: sftpgo_install_mode == 'upgrade' +- include: install.yml +- include: selinux.yml + when: ansible_selinux.status == 'enabled' +- include: conf.yml +- include: iptables.yml + when: iptables_manage | default(True) +- include: services.yml +- include: write_version.yml +- include: archive_post.yml + when: sftpgo_install_mode == 'upgrade' +- include: cleanup.yml diff --git a/roles/sftpgo/tasks/selinux.yml b/roles/sftpgo/tasks/selinux.yml new file mode 100644 index 0000000..7ad0ef2 --- /dev/null +++ b/roles/sftpgo/tasks/selinux.yml @@ -0,0 +1,15 @@ +--- + +- name: Set correct SELinux context + sefcontext: + target: "{{ sftpgo_root_dir }}/app/sftpgo" + setype: bin_t + state: present + register: sftpgo_selinux_context + tags: sftpgo + +- name: Restore correct SELinux context + command: restorecon {{ sftpgo_root_dir }}/app/sftpgo + when: sftpgo_selinux_context.changed + tags: sftpgo + diff --git a/roles/sftpgo/tasks/services.yml b/roles/sftpgo/tasks/services.yml new file mode 100644 index 0000000..02b0c89 --- /dev/null +++ b/roles/sftpgo/tasks/services.yml @@ -0,0 +1,5 @@ +--- + +- name: Start and enable the service + service: name=sftpgo state=started enabled=True + tags: sftpgo diff --git a/roles/sftpgo/tasks/user.yml b/roles/sftpgo/tasks/user.yml new file mode 100644 index 0000000..61120cf --- /dev/null +++ b/roles/sftpgo/tasks/user.yml @@ -0,0 +1,10 @@ +--- + +- name: Create sftpgo user + user: + name: "{{ sftpgo_user }}" + comment: SFTPGO User account + home: "{{ sftpgo_root_dir }}" + system: True + shell: /sbin/nologin + tags: sftpgo diff --git a/roles/sftpgo/tasks/write_version.yml b/roles/sftpgo/tasks/write_version.yml new file mode 100644 index 0000000..86e063d --- /dev/null +++ b/roles/sftpgo/tasks/write_version.yml @@ -0,0 +1,5 @@ +--- + +- name: Write installed version + copy: content={{ sftpgo_version }} dest={{ sftpgo_root_dir }}/meta/ansible_version + tags: sftpgo diff --git a/roles/sftpgo/templates/post-backup.j2 b/roles/sftpgo/templates/post-backup.j2 new file mode 100644 index 0000000..2f442da --- /dev/null +++ b/roles/sftpgo/templates/post-backup.j2 @@ -0,0 +1,5 @@ +#!/bin/bash + +set -eo pipefail + +rm -f {{ sftpgo_root_dir }}/backup/*.sql.zst {{ sftpgo_root_dir }}/backup/id_* diff --git a/roles/sftpgo/templates/pre-backup.j2 b/roles/sftpgo/templates/pre-backup.j2 new file mode 100644 index 0000000..4a7bc87 --- /dev/null +++ b/roles/sftpgo/templates/pre-backup.j2 @@ -0,0 +1,16 @@ +#!/bin/bash + +set -eo pipefail + +/usr/bin/mysqldump \ +{% if sftpgo_db_server not in ['localhost', '127.0.0.1'] %} + --user={{ sftpgo_db_user | quote }} \ + --password={{ sftpgo_db_pass | quote }} \ + --host={{ sftpgo_db_server | quote }} \ + --port={{ sftpgo_db_port }} \ +{% endif %} + --quick --single-transaction \ + --add-drop-table {{ sftpgo_db_name }} | \ + zstd -c > {{ sftpgo_root_dir }}/backup/{{ sftpgo_db_name }}.sql.zst + +cp -a {{ sftpgo_root_dir }}/etc/id_* {{ sftpgo_root_dir }}/backup/ diff --git a/roles/sftpgo/templates/sftpgo.service.j2 b/roles/sftpgo/templates/sftpgo.service.j2 new file mode 100644 index 0000000..a4d9475 --- /dev/null +++ b/roles/sftpgo/templates/sftpgo.service.j2 @@ -0,0 +1,33 @@ +[Unit] +Description=SFTPGo Server +After=network.target mariadb.service mysqld.service postgresql.service + +[Service] +User={{ sftpgo_user }} +Group={{ sftpgo_user }} +Type=simple +WorkingDirectory={{ sftpgo_root_dir }}/data +ExecStart={{ sftpgo_root_dir }}/app/sftpgo --config-file={{ sftpgo_root_dir }}/etc/sftpgo.yml --config-dir={{ sftpgo_root_dir }}/etc --log-file-path='' serve +ExecReload=/bin/kill -s HUP $MAINPID +KillMode=mixed +Restart=always +StartLimitInterval=0 +RestartSec=10s +PrivateTmp=true +PrivateDevices=yes +ProtectSystem=strict +ReadWritePaths={{ sftpgo_root_dir }}/etc/ {{ sftpgo_root_dir }}/data/ +ProtectHome=yes +NoNewPrivileges=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +RestrictRealtime=yes +RestrictSUIDSGID=yes +UMask=077 +MemoryLimit=2048M +# Allow binding on privileged ports +CapabilityBoundingSet=CAP_NET_BIND_SERVICE +AmbientCapabilities=CAP_NET_BIND_SERVICE + +[Install] +WantedBy=multi-user.target diff --git a/roles/sftpgo/templates/sftpgo.yml.j2 b/roles/sftpgo/templates/sftpgo.yml.j2 new file mode 100644 index 0000000..05bf7d6 --- /dev/null +++ b/roles/sftpgo/templates/sftpgo.yml.j2 @@ -0,0 +1,3 @@ +--- + +{{ sftpgo_conf | to_nice_yaml(indent=2, width=1000) }} diff --git a/roles/sftpgo/vars/RedHat.yml b/roles/sftpgo/vars/RedHat.yml new file mode 100644 index 0000000..9d4a72a --- /dev/null +++ b/roles/sftpgo/vars/RedHat.yml @@ -0,0 +1,6 @@ +--- + +sftpgo_packages: + - tar + - zstd + - mariadb