├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── defaults └── main.yml ├── handlers └── main.yml ├── meta └── main.yml ├── tasks ├── main.yml └── selinux.yml ├── templates └── etc_vsftpd_vsftpd.conf.j2 └── vars ├── Debian.yml └── RedHat.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # .gitignore 2 | 3 | # Hidden Vagrant-directory 4 | .vagrant 5 | 6 | # Backup files (e.g. Vim, Gedit, etc.) 7 | *~ 8 | 9 | # Vagrant base boxes (you never know when someone puts one in the repository) 10 | *.box 11 | 12 | # Compiled Python 13 | *.pyc 14 | 15 | # Test directory/-ies (sits in a separate branch) 16 | *-tests/ 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # .travis.yml Execution script for role tests on Travis-CI 2 | --- 3 | sudo: required 4 | 5 | env: 6 | matrix: 7 | - DISTRIBUTION: centos 8 | VERSION: 7 9 | - DISTRIBUTION: fedora 10 | VERSION: 26 11 | - DISTRIBUTION: debian 12 | VERSION: 8 13 | - DISTRIBUTION: debian 14 | VERSION: 9 15 | - DISTRIBUTION: ubuntu 16 | VERSION: 16.04 17 | 18 | 19 | services: 20 | - docker 21 | 22 | before_install: 23 | # Install latest Git 24 | - sudo apt-get update 25 | - sudo apt-get install --only-upgrade git 26 | # Allow fetching other branches than master 27 | - git config remote.origin.fetch +refs/heads/*:refs/remotes/origin/* 28 | # Fetch the branch with test code 29 | - git fetch origin docker-tests 30 | - git worktree add docker-tests origin/docker-tests 31 | 32 | script: 33 | # Create container and apply test playbook 34 | - ./docker-tests/docker-tests.sh 35 | 36 | # Run functional tests on the container 37 | - SUT_IP=172.17.0.2 ./docker-tests/functional-tests.sh 38 | 39 | notifications: 40 | webhooks: https://galaxy.ansible.com/api/v1/notifications/ 41 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change log 2 | 3 | This file contains al notable changes to the bertvv.vsftpd Ansible role. This file adheres to the guidelines of [http://keepachangelog.com/](http://keepachangelog.com/). Versioning follows [Semantic Versioning](http://semver.org/). 4 | 5 | ## 2.1.0 - 2017-11-10 6 | 7 | ## Added 8 | 9 | - Role variables `vsftpd_owner`, `vsftpd_group`, for setting the owner of `local_root` and `anon_root`. 10 | - Role variable `vsftpd_mode` for setting the file permissions of `local_root` and `anon_root`. 11 | - (GH-5) Support for CentOS 6 (credit: @renux360) 12 | 13 | ### Changed 14 | 15 | - Fix Ansible 2.4 deprecation warnings 16 | 17 | ## 2.0.2 - 2017-04-02 18 | 19 | ### Changed 20 | 21 | - (GH-4) Fixed testing for SELinux status 22 | - Added Debian Jessie to the list of supported platforms 23 | 24 | Ubuntu 14.04 and 16.04 should also work, but the Docker tests still fail. 25 | 26 | ## 2.0.1 - 2017-02-03 27 | 28 | ### Changed 29 | 30 | - (GH-3) Only enable SELinux boolean ftp_home_dir when it is present 31 | - Added Vagrant and Docker test branches 32 | - Added support for Fedora 25 33 | 34 | ## 2.0.0 - 2016-11-17 35 | 36 | ### Changed 37 | 38 | - Use the OS independent package module. This breaks compatibility with Ansible <2.0, hence the major version bump. 39 | 40 | ## 1.0.0 - 2015-12-15 41 | 42 | First release! 43 | 44 | ### Added 45 | 46 | - Installs and configures Vsftpd 47 | - Tested on CentOS 7, Ubuntu LTS 12.04 (precise) and 14.04 (trusty) 48 | 49 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # BSD License 2 | 3 | Copyright (c) 2015, Bert Van Vreckem, (bert.vanvreckem@gmail.com) 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible role `vsftpd` 2 | 3 | [![Build Status](https://travis-ci.org/bertvv/ansible-role-vsftpd.svg?branch=master)](https://travis-ci.org/bertvv/ansible-role-vsftpd) 4 | 5 | An Ansible role for setting up Vsftpd under CentOS/RHEL 6-7, Fedora 26, Ubuntu LTS 12.04 (precise) / 14.04 (trusty), or Debian 8 (Jessie) and 9 (Stretch). Specifically, the responsibilities of this role are to: 6 | 7 | - install necessary packages 8 | - manage configuration 9 | - manage SELinux settings, when it is enabled 10 | 11 | Configuring the firewall is outside the scope of this role. Use another role suitable for your distribution, e.g. [bertvv.rh-base](https://galaxy.ansible.com/bertvv/rh-base). 12 | 13 | **If you like/use this role, please consider giving it a star. Thanks!** 14 | 15 | ## Requirements 16 | 17 | No specific requirements 18 | 19 | ## Role Variables 20 | 21 | Please refer to the [vsftpd.conf(5)](http://vsftpd.beasts.org/vsftpd_conf.html) man page for detailed info on the variables listed below. The variable names here are consistent with the Vsftpd configuration parameters. 22 | 23 | | Variable | Default | Comments (type) | 24 | | :--- | :--- | :--- | 25 | | `vsftpd_anon_root` | - | Directory for guest users. Defaults to home directory of the `ftp` user. | 26 | | `vsftpd_anonymous_enable` | true | Specifies whether anonymous logins are permitted or not. | 27 | | `vsftpd_connect_from_port_20` | true | Controls whether PORT style data connections use port 20 on the server. machine. | 28 | | `vsftpd_group` | root | Group that will own `anon_root` and `local_root` | 29 | | `vsftpd_listen` | true | When enabled, run `vsftpd` in standalone mode. Mutually exclusive with `vsftpd_listen_ipv6` | 30 | | `vsftpd_listen_ipv6` | false | When enabled, run `vsftpd` in standalone mode, over IPv6. | 31 | | `vsftpd_local_enable` | false | Specifies whether logins from registered users are permitted or not. | 32 | | `vsftpd_local_root` | - | Directory for registered users. Defaults to their home directory. | 33 | | `vsftpd_local_umask` | 022 | The value that the umask for file creation is set to for local users. | 34 | | `vsftpd_options` | - | List of dicts for other options not available as role variables. See below. | 35 | | `vsftpd_owner` | root | User that will own `anon_root` and `local_root` | 36 | | `vsftpd_syslog_enable` | true | If enabled, log output goes to the system log (`journalctl -u vsftpd.service`) | 37 | | `vsftpd_write_enable` | true | Controls whether any FTP commands which change the filesystem are allowed or not. | 38 | 39 | Vsftpd options not provided in the list above can be added with `vsftpd_options` as a list of dicts with two fields, `key` and `value`. **Remark** that boolean options should be specified with `'YES'` or `'NO` *within quotes*. Otherwise the Jinja template engine will interpret these values as booleans instead of strings an translate them into, "True" and "False", respectively. 40 | 41 | ```Yaml 42 | vsftpd_options: 43 | - key: xferlog_enable 44 | value: 'YES' 45 | - key: xferlog_file 46 | value: /var/log/vsftp_xfer.log 47 | ``` 48 | 49 | Since vsftpd is dependent on fixed ACL permissions on the system this is in most cases easy to set but there are cases where a specific group needs access to some folders that can't be set when simply using chmod. In this case it is needed to add some extra read/write permissions for the specific user/group. 50 | For this scenario it is possible to use the underlying variables in your playbook which will set these extra ACL entries. 51 | 52 | ```Yaml 53 | vsftpd_extra_permissions: 54 | - folder: "/srv/shares/sales" 55 | entity: "management" 56 | etype: "group" 57 | permissions: "r-x" 58 | ``` 59 | 60 | ## Dependencies 61 | 62 | No dependencies. 63 | 64 | ## Example Playbook 65 | 66 | See the test playbooks in either the [Vagrant](https://github.com/bertvv/ansible-role-vsftpd/blob/vagrant-tests/test.yml) or [Docker](https://github.com/bertvv/ansible-role-vsftpd/blob/docker-tests/test.yml) test environment. See the section Testing for details. 67 | 68 | ## Testing 69 | 70 | There are two types of test environments available. One powered by Vagrant, another by Docker. The latter is suitable for running automated tests on Travis-CI. Test code is kept in separate orphan branches. For details of how to set up these test environments on your own machine, see the README files in the respective branches: 71 | 72 | - Vagrant: [vagrant-tests](https://github.com/bertvv/ansible-role-vsftpd/tree/vagrant-tests) 73 | - Docker: [docker-tests](https://github.com/bertvv/ansible-role-vsftpd/tree/docker-tests) 74 | 75 | ## Contributing 76 | 77 | Issues, feature requests, ideas are appreciated and can be posted in the Issues section. 78 | 79 | Pull requests are also very welcome. The best way to submit a PR is by first creating a fork of this Github project, then creating a topic branch for the suggested change and pushing that branch to your own fork. Github can then easily create a PR based on that branch. 80 | 81 | ## License 82 | 83 | 2-clause BSD license, see [LICENSE.md](LICENSE.md) 84 | 85 | ## Contributors 86 | 87 | - [Bert Van Vreckem](https://github.com/bertvv/) (maintainer) 88 | - [renux360](https://github.com/renux360) 89 | - [Jens Van Deynse](https://github.com/JensVanDeynse1994) 90 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | # roles/vsftpd/defaults/main.yml 2 | --- 3 | 4 | vsftpd_anonymous_enable: true 5 | vsftpd_connect_from_port_20: true 6 | vsftpd_group: root 7 | vsftpd_listen: true 8 | vsftpd_listen_ipv6: false 9 | vsftpd_local_enable: false 10 | vsftpd_local_umask: '022' 11 | vsftpd_mode: '0755' 12 | vsftpd_owner: root 13 | vsftpd_setype: public_content_t 14 | vsftpd_syslog_enable: true 15 | vsftpd_write_enable: true 16 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | # roles/vsftpd/handlers/main.yml 2 | --- 3 | 4 | - name: restart vsftpd 5 | service: 6 | name: "{{ vsftpd_service }}" 7 | state: restarted 8 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: Bert Van Vreckem 4 | description: "An Ansible role for setting up Vsftpd" 5 | license: BSD 6 | min_ansible_version: 2.4 7 | platforms: 8 | - name: EL 9 | versions: 10 | - 6 11 | - 7 12 | - name: Fedora 13 | versions: 14 | - 26 15 | - name: Ubuntu 16 | versions: 17 | - precise 18 | - trusty 19 | - name: Debian 20 | versions: 21 | - jessie 22 | - stretch 23 | categories: 24 | - system 25 | dependencies: [] 26 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | # roles/vsftpd/tasks/main.yml 2 | --- 3 | 4 | - name: Ensure `listen` and `listen_ipv6` are mutually exclusive 5 | assert: 6 | that: "vsftpd_listen != vsftpd_listen_ipv6" 7 | tags: vsftpd 8 | 9 | - name: Include OS-specific variables 10 | include_vars: "{{ item }}" 11 | with_first_found: 12 | - "{{ ansible_os_family }}.yml" 13 | - default.yml 14 | tags: vsftpd 15 | 16 | - name: Install Vsftpd 17 | package: 18 | name: '{{ vsftpd_packages }}' 19 | state: present 20 | tags: vsftpd 21 | 22 | - include_tasks: selinux.yml 23 | when: ansible_selinux is defined and ansible_selinux != false and ansible_selinux.status == 'enabled' 24 | 25 | - name: Ensure `anon_root` exists 26 | file: 27 | path: '{{ vsftpd_anon_root }}' 28 | state: directory 29 | owner: '{{ vsftpd_owner }}' 30 | group: '{{ vsftpd_group }}' 31 | mode: '{{ vsftpd_mode }}' 32 | setype: '{{ vsftpd_setype }}' 33 | when: vsftpd_anon_root is defined 34 | tags: vsftpd 35 | 36 | - name: Ensure `local_root` exists 37 | file: 38 | path: '{{ vsftpd_local_root }}' 39 | state: directory 40 | owner: '{{ vsftpd_owner }}' 41 | group: '{{ vsftpd_group }}' 42 | mode: '{{ vsftpd_mode }}' 43 | setype: '{{ vsftpd_setype }}' 44 | when: vsftpd_local_root is defined 45 | tags: vsftpd 46 | 47 | - name: Install configuration file 48 | template: 49 | src: etc_vsftpd_vsftpd.conf.j2 50 | dest: "{{ vsftpd_config_file }}" 51 | mode: '0600' 52 | #validate: 'vsftpd -olisten=NO %s' 53 | # validation always exits with status 1, even if everything seems ok 54 | notify: restart vsftpd 55 | tags: vsftpd 56 | 57 | - name: Add extra (ACL) permissions 58 | acl: 59 | name: "{{ item.folder }}" 60 | entity: "{{ item.entity }}" 61 | etype: "{{ item.etype }}" 62 | permissions: "{{ item.permissions }}" 63 | state: present 64 | with_items: "{{ vsftpd_extra_permissions }}" 65 | when: vsftpd_extra_permissions is defined 66 | tags: vsftpd 67 | 68 | - name: Ensure service is started 69 | service: 70 | name: '{{ vsftpd_service }}' 71 | state: started 72 | enabled: true 73 | tags: vsftpd 74 | -------------------------------------------------------------------------------- /tasks/selinux.yml: -------------------------------------------------------------------------------- 1 | # roles/vsftpd/tasks/selinux.yml 2 | --- 3 | 4 | - name: Allow full read/write access through SELinux for el7+ 5 | seboolean: 6 | name: ftpd_full_access 7 | state: yes 8 | persistent: yes 9 | tags: vsftpd 10 | when: 11 | - ansible_os_family == 'RedHat' 12 | - ansible_distribution_major_version >= "7" 13 | 14 | - name: Allow full read/write access through SELinux for el6 15 | seboolean: 16 | name: allow_ftpd_full_access 17 | state: yes 18 | persistent: yes 19 | tags: vsftpd 20 | when: 21 | - ansible_os_family == 'RedHat' 22 | - ansible_distribution_major_version == "6" 23 | 24 | # in RHEL/CentOS 7.3, the SELinux boolean ftp_home_dir was removed and 25 | # access to home directories is enabled by default 26 | # See https://bugzilla.redhat.com/show_bug.cgi?id=1352257 27 | - name: Check if ftp_home_dir exists 28 | shell: getsebool -a | grep '^ftp_home_dir\b' 29 | register: var_exists 30 | failed_when: false 31 | changed_when: false 32 | tags: vsftpd 33 | 34 | - name: Allow access to home directories 35 | seboolean: 36 | name: ftp_home_dir 37 | state: yes 38 | persistent: yes 39 | when: var_exists.rc == 0 40 | tags: vsftpd 41 | 42 | -------------------------------------------------------------------------------- /templates/etc_vsftpd_vsftpd.conf.j2: -------------------------------------------------------------------------------- 1 | # Vsftpd configuration 2 | # Managed by Ansible, don't edit manually 3 | 4 | # 5 | # General settings 6 | # 7 | 8 | connect_from_port_20={{ 'YES' if vsftpd_connect_from_port_20 else 'NO' }} 9 | listen={{ 'YES' if vsftpd_listen else 'NO' }} 10 | listen_ipv6={{ 'YES' if vsftpd_listen_ipv6 else 'NO' }} 11 | pam_service_name={{ vsftpd_service }} 12 | syslog_enable={{ 'YES' if vsftpd_syslog_enable else 'NO' }} 13 | 14 | # 15 | # Access control for anonymous users 16 | # 17 | anonymous_enable={{ 'YES' if vsftpd_anonymous_enable else 'NO' }} 18 | {% if vsftpd_anon_root is defined %} 19 | anon_root={{ vsftpd_anon_root }} 20 | {% endif %} 21 | 22 | # 23 | # Access control for registered users 24 | # 25 | local_enable={{ 'YES' if vsftpd_local_enable else 'NO' }} 26 | {% if vsftpd_local_root is defined %} 27 | local_root={{ vsftpd_local_root }} 28 | {% endif %} 29 | local_umask={{ vsftpd_local_umask }} 30 | 31 | write_enable={{ 'YES' if vsftpd_write_enable else 'NO' }} 32 | {% if not (ansible_os_family == 'RedHat' and ansible_distribution_major_version == '6') %} 33 | seccomp_sandbox=NO 34 | {% endif %} 35 | 36 | {% if vsftpd_options is defined %} 37 | # 38 | # Other settings 39 | # 40 | {% for setting in vsftpd_options %} 41 | {{ setting.key }}={{ setting.value }} 42 | {% endfor %} 43 | {% endif %} 44 | -------------------------------------------------------------------------------- /vars/Debian.yml: -------------------------------------------------------------------------------- 1 | # roles/vsftpd/vars/Debian.yml 2 | --- 3 | 4 | vsftpd_packages: 5 | - vsftpd 6 | 7 | vsftpd_service: vsftpd 8 | 9 | vsftpd_config_file: /etc/vsftpd.conf 10 | -------------------------------------------------------------------------------- /vars/RedHat.yml: -------------------------------------------------------------------------------- 1 | # roles/vsftpd/vars/RedHat.yml 2 | --- 3 | 4 | vsftpd_packages: 5 | - vsftpd 6 | - libsemanage-python 7 | 8 | vsftpd_service: vsftpd 9 | 10 | vsftpd_config_file: /etc/vsftpd/vsftpd.conf 11 | --------------------------------------------------------------------------------