├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── defaults └── main.yml ├── handlers └── main.yml ├── meta └── main.yml ├── run-local-tests.sh ├── tasks └── main.yml └── tests ├── Dockerfile.centos-7.ansible-2.5 ├── Dockerfile.centos-7.ansible-2.9 ├── Dockerfile.centos-8.ansible-2.5 ├── Dockerfile.centos-8.ansible-2.9 ├── Dockerfile.ubuntu-16.04.ansible-2.5 ├── Dockerfile.ubuntu-16.04.ansible-2.9 ├── Dockerfile.ubuntu-18.04.ansible-2.5 ├── Dockerfile.ubuntu-18.04.ansible-2.9 └── test.yml /.editorconfig: -------------------------------------------------------------------------------- 1 | 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | 8 | [*.yml] 9 | indent_size = 2 10 | indent_style = space 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | sudo: required 3 | 4 | env: 5 | - ansible: 2.5 6 | distribution: ubuntu 7 | version: 16.04 8 | init: /sbin/init 9 | run_opts: "" 10 | - ansible: 2.9 11 | distribution: ubuntu 12 | version: 16.04 13 | init: /sbin/init 14 | run_opts: "" 15 | - ansible: 2.5 16 | distribution: ubuntu 17 | version: 18.04 18 | init: /sbin/init 19 | run_opts: "" 20 | - ansible: 2.9 21 | distribution: ubuntu 22 | version: 18.04 23 | init: /sbin/init 24 | run_opts: "" 25 | - ansible: 2.5 26 | distribution: centos 27 | version: 7 28 | init: /sbin/init 29 | run_opts: "" 30 | - ansible: 2.9 31 | distribution: centos 32 | version: 7 33 | init: /sbin/init 34 | run_opts: "" 35 | - ansible: 2.5 36 | distribution: centos 37 | version: 8 38 | init: /sbin/init 39 | run_opts: "" 40 | - ansible: 2.9 41 | distribution: centos 42 | version: 8 43 | init: /sbin/init 44 | run_opts: "" 45 | 46 | services: 47 | - docker 48 | 49 | before_install: 50 | # Pull container 51 | - "sudo docker pull ${distribution}:${version}" 52 | # Customize container 53 | - "sudo docker build --rm=true --file=tests/Dockerfile.${distribution}-${version}.ansible-${ansible} --tag=${distribution}-${version}:ansible-${ansible} tests" 54 | 55 | script: 56 | - container_id=$(mktemp) 57 | # Run container in detached state 58 | - 'sudo docker run --detach --volume="${PWD}":/etc/ansible/roles/role_under_test:ro ${run_opts} ${distribution}-${version}:ansible-${ansible} "${init}" > "${container_id}"' 59 | 60 | # Ansible syntax check. 61 | - 'sudo docker exec --tty "$(cat ${container_id})" env TERM=xterm ansible-playbook /etc/ansible/roles/role_under_test/tests/test.yml --syntax-check' 62 | 63 | # Test role. 64 | - 'sudo docker exec --tty "$(cat ${container_id})" env TERM=xterm ansible-playbook /etc/ansible/roles/role_under_test/tests/test.yml' 65 | 66 | # Small tests for workings of role. 67 | - > 68 | sudo docker exec --tty "$(cat ${container_id})" env TERM=xterm grep "user1" /etc/shadow 69 | && (echo 'User created' && exit 0) 70 | || (echo 'User not created' && exit 1) 71 | - > 72 | sudo docker exec --tty "$(cat ${container_id})" env TERM=xterm test -d /home/user1/test1 73 | && (echo 'Directory created' && exit 0) 74 | || (echo 'Directory not created' && exit 1) 75 | 76 | # Group specfic tests. 77 | - > 78 | sudo docker exec --tty "$(cat ${container_id})" env TERM=xterm grep "foobar" /etc/group 79 | && (echo 'Group created' && exit 0) 80 | || (echo 'Group not created' && exit 1) 81 | - > 82 | sudo docker exec --tty "$(cat ${container_id})" env TERM=xterm '[ $(stat --format %G /home/user2) = "foobar" ]' 83 | && (echo 'Good directory ownership' && exit 0) 84 | || (echo 'Wrong directory ownership' && exit 1) 85 | - > 86 | sudo docker exec --tty "$(cat ${container_id})" env TERM=xterm '[ $(stat --format %G /home/user1) = "sftpusers" ]' 87 | && (echo 'Good directory ownership' && exit 0) 88 | || (echo 'Wrong directory ownership' && exit 1) 89 | 90 | # Test user-specific directory creation 91 | - > 92 | sudo docker exec --tty "$(cat ${container_id})" env TERM=xterm test -d /home/user1/test3 93 | && (echo 'User Directory created' && exit 0) 94 | || (echo 'User Directory not created' && exit 1) 95 | 96 | # Test role idempotence. 97 | - > 98 | sudo docker exec "$(cat ${container_id})" ansible-playbook /etc/ansible/roles/role_under_test/tests/test.yml 99 | | grep -q 'changed=0.*failed=0' 100 | && (echo 'Idempotence test: pass' && exit 0) 101 | || (echo 'Idempotence test: fail' && exit 1) 102 | # Clean up 103 | - 'sudo docker stop "$(cat ${container_id})"' 104 | # notifications: 105 | # webhooks: https://galaxy.ansible.com/api/v1/notifications/ 106 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Johan Meiring 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SFTP-Server 2 | 3 | [![Ansible Role](https://img.shields.io/ansible/role/991.svg)](https://galaxy.ansible.com/johanmeiring/sftp-server/) [![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-round)](https://github.com/johanmeiring/ansible-sftp/blob/master/LICENSE) [![Build Status](https://travis-ci.com/johanmeiring/ansible-sftp.svg?branch=master)](https://travis-ci.com/johanmeiring/ansible-sftp) 4 | 5 | An Ansible role which configures an OpenSSH server for chrooted SFTP access. The role is built in such a way that it will not unnecessarily alter a user's OpenSSH customisations. Instead, it simply changes the crucial bits that it needs to, and adds the rest of its configuration in the form of a custom config block (OpenSSH's lack of some form of conf.d/ support forces this behaviour). 6 | 7 | ## Requirements 8 | 9 | It is advisable that `scp_if_ssh` be set to `true` in the `ssh_connection` section of your `ansible.cfg` file, seeing as how Ansible uses SFTP for file transfers by default, and you can easily lock yourself out of your server's SFTP by using this role. The SCP fallback will continue to work. Example config: 10 | 11 | ```ini 12 | ; ansible.cfg 13 | ... 14 | [ssh_connection] 15 | scp_if_ssh=True 16 | ``` 17 | 18 | Other than that, only Ansible itself is required. Tested using Ansible 2.0.2.0, 2.2.2.0 and 2.3.0.0. Works on Ubuntu 14.04 and 16.04, untested on other versions. Some work has been done on supporting RHEL, though this is not currently officially supported by the original author (further contributions are obviously welcome ;-) 19 | 20 | ## Role Variables 21 | 22 | The following role variables are relevant: 23 | 24 | * `sftp_home_partition`: The partition where SFTP users' home directories will be located. Defaults to "/home". 25 | * `sftp_group_name`: The name of the Unix group to which all SFTP users must belong. Defaults to "sftpusers". 26 | * `sftp_directories`: A list of directories that need to be created automatically by default for all SFTP user. Defaults to a blank list (i.e. "[]"). 27 | * Values can be plain strings, or dictionaries containing `name` and (optionally) `mode` key/value pairs. 28 | * `sftp_start_directory`: A directory that need to be part of sftp_directories values and that is the start directory of new sftp connection. Disable by default with an empty string value. 29 | * `sftp_allow_passwords`: Whether or not to allow password authentication for SFTP. Defaults to False. 30 | * `sftp_enable_selinux_support`: Whether or not to explicitly enable SELinux support. Defaults to False. 31 | * `sftp_enable_logging`: Enable logging. Auth logs will be written to `/var/log/sftp/auth.log`, and SFTP activity logs will be written to `/var/log/sftp/verbose.log`. Defaults to False. 32 | * `sftp_users`: A list of users, in map form, containing the following elements: 33 | * `name`: The Unix name of the user that requires SFTP access. 34 | * `group`: An optional user primary group. If set, it will be used for the user's home permission. Otherwise, the `sftp_group_name` is used. 35 | * `password`: A password hash for the user to login with - ie `openssl passwd -1 -salt salty passpass`. Blank passwords can be set with `password: ""`. NOTE: It appears that `UsePAM yes` and `PermitEmptyPassword yes` need to be set in `sshd_config` in order for blank passwords to work properly. Making those changes currently falls outside the scope of this role and will need to be done externally. 36 | * `shell`: Boolean indicating if the user should have a shell access (default to `True`). 37 | * `authorized`: An optional list of files placed in `files/` which contain valid public keys for the SFTP user. 38 | * `sftp_directories`: A list of directories that need to be individually created for an SFTP user. Defaults to a blank list (i.e. "[]"). 39 | * `append`: Boolean to add `sftp_group_name` to the user groups (if any) instead of setting it (default to `False`). 40 | * `mode`: The users home directory mode (defaults to `0750`). 41 | * `skeleton`: An optional home skeleton directory (e.g: /dev/null). Default to system defaults. 42 | * `home`: An optional home directory (e.g: /home/bob). Default to `sftp_home_partition/name`. 43 | * `sftp_nologin_shell`: The "nologin" user shell. (defaults to /sbin/nologin.) 44 | 45 | Notes: 46 | 47 | * The `sftp_nologin_shell` setting defines the shell assigned to sftp_users when the sftp user's shell is set to False. (The nologin shell ensures the user may only use SFTP and have no other login permissions.) This value may vary depending on the operating system version. 48 | 49 | ## Example Playbook 50 | 51 | ```yaml 52 | --- 53 | - name: test-playbook | Test sftp-server role 54 | hosts: all 55 | become: yes 56 | become_user: root 57 | vars: 58 | - sftp_users: 59 | - name: peter 60 | password: "$1$salty$li5TXAa2G6oxHTDkqx3Dz/" # passpass 61 | shell: False 62 | sftp_directories: 63 | - directory_only_for_peter1 64 | - directory_only_for_peter2 65 | - name: sally 66 | password: "" 67 | authorized: [sally.pub] 68 | home: /var/tmp/sally 69 | append: True 70 | - sftp_directories: 71 | - imports 72 | - exports 73 | - { name: public, mode: 755 } 74 | - other 75 | roles: 76 | - sftp-server 77 | ``` 78 | 79 | ## License 80 | 81 | This Ansible role is distributed under the MIT License. See the LICENSE file for more details. 82 | 83 | ## Donations 84 | 85 | Donations are very welcome, and can be made to the following addresses: 86 | 87 | * BTC: 1AWHJcUBha35FnuuWat9urRW2FNc4ftztv 88 | * ETH: 0xAF1Aac4c40446F4C46e55614F14d9b32d712ECBc 89 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | sftp_home_partition: /home 3 | sftp_group_name: sftpusers 4 | sftp_directories: [] 5 | sftp_start_directory: '' 6 | sftp_allow_passwords: False 7 | sftp_enable_selinux_support: False 8 | sftp_enable_logging: False 9 | sftp_nologin_shell: /sbin/nologin 10 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: SFTP-Server | Restart sshd 3 | service: 4 | name: "{{ 'ssh' if ansible_os_family == 'Debian' else 'sshd' }}" 5 | state: restarted 6 | ignore_errors: Yes 7 | 8 | - name: SFTP-Server | Restart rsyslog 9 | service: 10 | name: rsyslog 11 | state: restarted 12 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: Johan Meiring 4 | description: "Setup chrooted SFTP service on top of OpenSSH" 5 | license: MIT 6 | min_ansible_version: 2.5 7 | 8 | platforms: 9 | - name: Ubuntu 10 | versions: 11 | - xenial 12 | - yakkety 13 | - zesty 14 | - artful 15 | - bionic 16 | - cosmic 17 | - disco 18 | - eoan 19 | - name: EL 20 | versions: 21 | - 7 22 | - 8 23 | 24 | galaxy_tags: 25 | - networking 26 | - system 27 | - sftp 28 | - ssh 29 | 30 | dependencies: [] 31 | -------------------------------------------------------------------------------- /run-local-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | run_test() { 5 | echo "Testing role on Ansible version $3 on $1 $2....." 6 | docker pull $1:$2 7 | docker build --rm=true --file=tests/Dockerfile.$1-$2.ansible-$3 --tag=$1-$2:ansible-$3 tests 8 | container_id=$(mktemp) 9 | docker run --rm=true --detach --volume="${PWD}":/etc/ansible/roles/role_under_test:ro $1-$2:ansible-$3 /sbin/init > "${container_id}" 10 | docker exec --tty "$(cat ${container_id})" env TERM=xterm python --version 11 | docker exec --tty "$(cat ${container_id})" env TERM=xterm ansible-playbook /etc/ansible/roles/role_under_test/tests/test.yml --syntax-check 12 | docker exec --tty "$(cat ${container_id})" env TERM=xterm ansible-playbook /etc/ansible/roles/role_under_test/tests/test.yml 13 | docker exec --tty "$(cat ${container_id})" env TERM=xterm grep "user1" /etc/shadow && (echo 'User created' && exit 0) || (echo 'User not created' && exit 1) 14 | docker exec --tty "$(cat ${container_id})" env TERM=xterm test -d /home/user1/test1 && (echo 'Directory created' && exit 0) || (echo 'Directory not created' && exit 1) 15 | docker exec --tty "$(cat ${container_id})" env TERM=xterm grep "foobar" /etc/group && (echo 'Group created' && exit 0) || (echo 'Group not created' && exit 1) 16 | docker exec --tty "$(cat ${container_id})" env TERM=xterm stat -c '%G' /var/tmp/user2 17 | docker exec --tty "$(cat ${container_id})" env TERM=xterm '[ $(stat --format '%G' /var/tmp/user2) = "foobar" ]' && (echo 'Good directory ownership' && exit 0) || (echo 'Wrong directory ownership' && exit 1) 18 | docker exec --tty "$(cat ${container_id})" env TERM=xterm '[ $(stat --format '%G' /home/user1) = "sftpusers" ]' && (echo 'Good directory ownership' && exit 0) || (echo 'Wrong directory ownership' && exit 1) 19 | docker exec --tty "$(cat ${container_id})" env TERM=xterm test -d /home/user1/test3 && (echo 'User Directory created' && exit 0) || (echo 'User Directory not created' && exit 1) 20 | docker exec "$(cat ${container_id})" ansible-playbook /etc/ansible/roles/role_under_test/tests/test.yml | grep -q 'changed=0.*failed=0' && (echo 'Idempotence test: pass' && exit 0) || (echo 'Idempotence test: fail' && exit 1) 21 | docker stop "$(cat ${container_id})" 22 | } 23 | 24 | run_test ubuntu 16.04 2.5 25 | run_test ubuntu 16.04 2.9 26 | 27 | run_test ubuntu 18.04 2.5 28 | run_test ubuntu 18.04 2.9 29 | 30 | run_test centos 7 2.5 31 | run_test centos 7 2.9 32 | 33 | run_test centos 8 2.5 34 | run_test centos 8 2.9 35 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "Compute SFTP users." 3 | set_fact: 4 | _sftp_users: >- 5 | [{% for sftp_user in sftp_users -%} 6 | {{ sftp_user | combine({'home': sftp_user.home | default(sftp_home_partition + '/' + sftp_user.name) }) }} 7 | {{ '' if loop.last else ',' }} 8 | {%- endfor %}] 9 | 10 | # Creates group for SFTP users. 11 | - name: SFTP-Server | Create sftp user group 12 | group: 13 | name: "{{ sftp_group_name }}" 14 | state: present 15 | 16 | # Necessary for chrooting of SFTP users. 17 | - name: SFTP-Server | Alter sftp subsystem entry 18 | lineinfile: 19 | dest: /etc/ssh/sshd_config 20 | regexp: '^Subsystem(\s+)sftp' 21 | line: "Subsystem sftp internal-sftp -f AUTH -l VERBOSE" 22 | state: present 23 | notify: SFTP-Server | Restart sshd 24 | 25 | - name: SFTP-Server | Ensure SELinux management package is present 26 | package: 27 | name: "{{ 'python-semanage' if ansible_distribution == 'Debian' else 'libsemanage-python' }}" 28 | state: present 29 | when: ansible_selinux and sftp_enable_selinux_support 30 | 31 | - name: SFTP-Server | Set SELinux booleans 32 | seboolean: 33 | name: "{{ item }}" 34 | state: yes 35 | persistent: yes 36 | with_items: 37 | - ssh_chroot_full_access 38 | - ssh_chroot_rw_homedirs 39 | when: ansible_selinux and sftp_enable_selinux_support 40 | 41 | - name: SFTP-Server | Add sshd_config block 42 | blockinfile: 43 | dest: /etc/ssh/sshd_config 44 | marker: "# {mark} SFTP-Server {{ sftp_group_name }} block" 45 | block: | 46 | Match Group {{ sftp_group_name }} 47 | ChrootDirectory %h 48 | AllowTCPForwarding no 49 | PermitTunnel no 50 | X11Forwarding no 51 | ForceCommand internal-sftp {{ sftp_enable_logging | ternary('-l VERBOSE', '') }} {{ (sftp_start_directory in sftp_directories or sftp_start_directory in sftp_directories | selectattr("name", "defined") | map(attribute='name') | list) | ternary('-d /' + sftp_start_directory, '') }} 52 | PasswordAuthentication {{ sftp_allow_passwords | ternary('yes', 'no') }} 53 | notify: SFTP-Server | Restart sshd 54 | 55 | - name: SFTP-Server | Create sftp user's group 56 | group: 57 | name: "{{ item }}" 58 | state: present 59 | with_items: "{{ _sftp_users | selectattr('group', 'defined') | map(attribute='group') | list }}" 60 | 61 | # Create each SFTP user with home directory on the correct partition, and add to SFTP group. 62 | - name: SFTP-Server | Create sftp users 63 | user: 64 | name: "{{ item.name }}" 65 | group: "{{ item.group | default(omit) }}" 66 | groups: "{{ sftp_group_name }}" 67 | append: "{{ item.append | default(False) }}" 68 | home: "{{ item.home }}" 69 | # `None` means default value -> default is to have a shell 70 | shell: "{{ None if (item.shell | default(True)) else sftp_nologin_shell }}" 71 | skeleton: "{{ item.skeleton | default(omit) }}" 72 | state: present 73 | with_items: "{{ _sftp_users }}" 74 | 75 | # A working chrooted SFTP setup requires root:sftgroup ownership of a user's home directory. 76 | # Temporarily removing the task below until we find a solution which does not 77 | # set the permissions of e.g. /home 78 | # Original issue: https://github.com/johanmeiring/ansible-sftp/issues/46 79 | # New issue: https://github.com/johanmeiring/ansible-sftp/issues/49 80 | # - name: SFTP-Server | Root SFTP permissions 81 | # file: 82 | # path: "{{ sftp_home_partition }}" 83 | # state: directory 84 | # mode: 0750 85 | # group: "{{ sftp_group_name }}" 86 | # owner: root 87 | 88 | - name: SFTP-Server | Correct ownership and permission of home directories 89 | file: 90 | path: "{{ item.home }}" 91 | owner: root 92 | group: "{{ item.group | default(sftp_group_name) }}" 93 | mode: "{{ item.mode | default('0750') }}" 94 | with_items: "{{ _sftp_users }}" 95 | 96 | # Install all relevant public keys. 97 | - name: SFTP-Server | Install public keys 98 | authorized_key: 99 | user: "{{ item.0.name }}" 100 | key: "{{ lookup('file', item.1) }}" 101 | with_subelements: 102 | - "{{ _sftp_users }}" 103 | - authorized 104 | - flags: 105 | skip_missing: True 106 | 107 | # Update user passwords, if they were specified. 108 | - name: SFTP-Server | Update user passwords 109 | user: 110 | name: "{{ item.name }}" 111 | password: "{{ item.password }}" 112 | with_items: "{{ _sftp_users }}" 113 | when: item.password is defined 114 | 115 | # Create directories for all SFTP users. Optional, but recommended. 116 | - name: SFTP-Server | Create directories 117 | file: 118 | path: "{{ item[0].home }}/{{ item[1].name | default(item[1]) }}" 119 | owner: "{{ item[0].name }}" 120 | group: "{{ item[0].group | default(item[0].name) }}" 121 | mode: "{{ item[1].mode | default('0750') }}" 122 | state: directory 123 | with_nested: 124 | - "{{ _sftp_users }}" 125 | - "{{ sftp_directories }}" 126 | 127 | # Create directories for individual SFTP users. Optional. 128 | - name: SFTP-Server | Create directories per user 129 | file: 130 | path: "{{ item[0].home }}/{{ item[1].name | default(item[1]) }}" 131 | owner: "{{ item[0].name }}" 132 | group: "{{ item[0].group | default(item[0].name) }}" 133 | mode: "{{ item[1].mode | default('0750') }}" 134 | state: directory 135 | with_subelements: 136 | - "{{ _sftp_users }}" 137 | - "sftp_directories" 138 | - flags: 139 | skip_missing: True 140 | 141 | - name: SFTP-Server | Create dev directory for logging 142 | file: 143 | path: "{{ item.home }}/dev" 144 | owner: root 145 | group: root 146 | state: directory 147 | with_items: 148 | - "{{ _sftp_users }}" 149 | when: sftp_enable_logging 150 | 151 | - name: SFTP-Server | Enable Logging 152 | blockinfile: 153 | dest: "/etc/rsyslog.d/sshd.conf" 154 | create: yes 155 | block: | 156 | # Create an additional socket for some of the sshd chrooted users. 157 | {% for user in sftp_users %} 158 | $AddUnixListenSocket {{ sftp_home_partition }}/{{ user.name }}/dev/log 159 | {% endfor %} 160 | 161 | # Log internal-sftp in a separate file 162 | :programname, isequal, "internal-sftp" -/var/log/sftp/verbose.log 163 | :programname, isequal, "internal-sftp" ~ 164 | 165 | # additionally write an auth log 166 | auth,authpriv.* /var/log/sftp/auth.log 167 | when: sftp_enable_logging 168 | notify: SFTP-Server | Restart rsyslog 169 | 170 | # Restart sshd to ensure all configuration has been applied. This should always be the last task. 171 | - name: SFTP-Server | Restart sshd 172 | service: 173 | name: "{{ 'ssh' if ansible_os_family == 'Debian' else 'sshd' }}" 174 | state: restarted 175 | ignore_errors: Yes 176 | -------------------------------------------------------------------------------- /tests/Dockerfile.centos-7.ansible-2.5: -------------------------------------------------------------------------------- 1 | FROM centos:7 2 | RUN yum -y update 3 | 4 | # Install OpenSSH server 5 | RUN yum install -y openssh-server epel-release libffi-devel gcc 6 | 7 | # Install Ansible 8 | RUN yum install -y python3-pip python3-devel openssl-devel 9 | #software-properties-common git python-dev libffi-dev libssl-dev 10 | RUN pip3 install -U setuptools 11 | RUN pip3 install 'ansible~=2.5.0' 12 | RUN alternatives --install /usr/bin/python python /usr/bin/python3 60 13 | 14 | # Install Ansible inventory file 15 | RUN mkdir /etc/ansible/ && echo "localhost ansible_connection=local" > /etc/ansible/hosts 16 | -------------------------------------------------------------------------------- /tests/Dockerfile.centos-7.ansible-2.9: -------------------------------------------------------------------------------- 1 | FROM centos:7 2 | RUN yum -y update 3 | 4 | # Install OpenSSH server 5 | RUN yum install -y openssh-server epel-release libffi-devel gcc 6 | 7 | # Install Ansible 8 | RUN yum install -y python3-pip python3-devel openssl-devel 9 | #software-properties-common git python-dev libffi-dev libssl-dev 10 | RUN pip3 install -U setuptools 11 | RUN pip3 install 'ansible~=2.9.0' 12 | RUN alternatives --install /usr/bin/python python /usr/bin/python3 60 13 | 14 | # Install Ansible inventory file 15 | RUN mkdir /etc/ansible/ && echo "localhost ansible_connection=local" > /etc/ansible/hosts 16 | -------------------------------------------------------------------------------- /tests/Dockerfile.centos-8.ansible-2.5: -------------------------------------------------------------------------------- 1 | FROM centos:8 2 | RUN yum -y update 3 | 4 | # Install OpenSSH server 5 | RUN yum install -y openssh-server epel-release libffi-devel gcc 6 | 7 | # Install Ansible 8 | RUN yum install -y python3-pip python3-devel openssl-devel 9 | #software-properties-common git python-dev libffi-dev libssl-dev 10 | RUN pip3 install -U setuptools 11 | RUN pip3 install 'ansible~=2.5.0' 12 | RUN alternatives --set python /usr/bin/python3 13 | 14 | # Install Ansible inventory file 15 | RUN mkdir /etc/ansible/ && echo "localhost ansible_connection=local" > /etc/ansible/hosts 16 | -------------------------------------------------------------------------------- /tests/Dockerfile.centos-8.ansible-2.9: -------------------------------------------------------------------------------- 1 | FROM centos:8 2 | RUN yum -y update 3 | 4 | # Install OpenSSH server 5 | RUN yum install -y openssh-server epel-release libffi-devel gcc 6 | 7 | # Install Ansible 8 | RUN yum install -y python3-pip python3-devel openssl-devel 9 | #software-properties-common git python-dev libffi-dev libssl-dev 10 | RUN pip3 install -U setuptools 11 | RUN pip3 install 'ansible~=2.9.0' 12 | RUN alternatives --set python /usr/bin/python3 13 | 14 | # Install Ansible inventory file 15 | RUN mkdir /etc/ansible/ && echo "localhost ansible_connection=local" > /etc/ansible/hosts 16 | -------------------------------------------------------------------------------- /tests/Dockerfile.ubuntu-16.04.ansible-2.5: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | RUN apt-get update 3 | 4 | # Install OpenSSH server 5 | RUN apt-get install -y openssh-server 6 | 7 | # Install Ansible 8 | RUN apt-get install -y software-properties-common git python3-pip python3-dev libffi-dev libssl-dev 9 | RUN pip3 install -U setuptools 10 | RUN pip3 install 'ansible~=2.5.0' 11 | RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 10 12 | 13 | # Install Ansible inventory file 14 | RUN mkdir /etc/ansible/ && echo "[local]\nlocalhost ansible_connection=local" > /etc/ansible/hosts 15 | -------------------------------------------------------------------------------- /tests/Dockerfile.ubuntu-16.04.ansible-2.9: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | RUN apt-get update 3 | 4 | # Install OpenSSH server 5 | RUN apt-get install -y openssh-server 6 | 7 | # Install Ansible 8 | RUN apt-get install -y software-properties-common git python3-pip python3-dev libffi-dev libssl-dev 9 | RUN pip3 install -U setuptools 10 | RUN pip3 install 'ansible~=2.9.0' 11 | RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 10 12 | 13 | # Install Ansible inventory file 14 | RUN mkdir /etc/ansible/ && echo "[local]\nlocalhost ansible_connection=local" > /etc/ansible/hosts 15 | -------------------------------------------------------------------------------- /tests/Dockerfile.ubuntu-18.04.ansible-2.5: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | RUN apt-get update 3 | 4 | # Install OpenSSH server 5 | RUN apt-get install -y openssh-server 6 | 7 | # Install Ansible 8 | RUN apt-get install -y software-properties-common git python3-pip python3-dev libffi-dev libssl-dev 9 | RUN pip3 install -U setuptools 10 | RUN pip3 install 'ansible~=2.5.0' 11 | RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 10 12 | 13 | # Install Ansible inventory file 14 | RUN mkdir /etc/ansible/ && echo "[local]\nlocalhost ansible_connection=local" > /etc/ansible/hosts 15 | -------------------------------------------------------------------------------- /tests/Dockerfile.ubuntu-18.04.ansible-2.9: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | RUN apt-get update 3 | 4 | # Install OpenSSH server 5 | RUN apt-get install -y openssh-server 6 | 7 | # Install Ansible 8 | RUN apt-get install -y software-properties-common git python3-pip python3-dev libffi-dev libssl-dev 9 | RUN pip3 install -U setuptools 10 | RUN pip3 install 'ansible~=2.9.0' 11 | RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 10 12 | 13 | # Install Ansible inventory file 14 | RUN mkdir /etc/ansible/ && echo "[local]\nlocalhost ansible_connection=local" > /etc/ansible/hosts 15 | -------------------------------------------------------------------------------- /tests/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | 4 | vars: 5 | sftp_directories: 6 | - test1 7 | - test2 8 | - name: test5 9 | mode: 770 10 | sftp_start_directory: test5 11 | sftp_users: 12 | - name: user1 13 | password: "" 14 | authorized: [] 15 | sftp_directories: 16 | - test3 17 | - test4 18 | - name: user2 19 | home: /var/tmp/user2 20 | group: foobar 21 | password: "" 22 | authorized: [] 23 | 24 | 25 | roles: 26 | - role_under_test 27 | --------------------------------------------------------------------------------