# FTP Setup Guide on RHEL 7 ### Overview This FTP application (Flash FTP) relies on `vsftpd` and `pam_mysql` so that FTP guest users are not required to be LDAP system users. The credentials for an FTP guest user reside in a MySQL table and `pam_mysql` handles taking the FTP username/password, hashing it and comparing it to the username/password fields in the database table, thus allowing or denying guest users access to the FTP service. Users that wish to share files with a guest are able to login into the system (i.e., authenticate against LDAP) and send invitations to guests users by e-mail. This documentation assumes that the Django app resides in `/devel/ftp_project` and the FTP directory is `/project/ftp_public`. ![Service Diagram](./service_diagram.png) ### Components - RHEL 7 - Python 3.6.8 (or later) - Django 2.2 LTS - MySQL - LDAP - Folders, file permissions and mounts - IP Tables/Firewall Daemon ### Install EPEL and build packages ```sh yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm yum -y groupinstall "Development Tools" ``` ### MySQL Edit the file `/etc/yum.repos.d/mysql-community.repo`: ```sh # Enable to use MySQL 5.7 [mysql57-community] name=MySQL 5.7 Community Server baseurl=http://repo.mysql.com/yum/mysql-5.7-community/el/7/$basearch/ enabled=1 gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql ``` Copy the GPG key in https://dev.mysql.com/doc/refman/5.7/en/checking-gpg-signature.html to `/etc/pki/rpm-gpg/RPM-GPG-KEY-mysql` and install MySQL: ```sh yum repolist enabled | grep mysql yum install mysql-community-server systemctl start mysqld.service systemctl enable mysqld.service ``` ### Create the database ```sh # get the temporary root password sudo grep 'temporary password' /var/log/mysqld.log mysql -u root -p mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'vsftpd'; mysql> CREATE DATABASE vsftpd; mysql> exit; mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql -p ``` ### LDAP client ```sh yum install openldap-clients nss-pam-ldapd pam_ldap authconfig --enableldap --enableldapauth --ldapserver="" --ldapbasedn="" --update authconfig --enableforcelegacy --update ``` You might need to edit `/etc/nslcd.conf` to provide cetificate info. Test the client: ```sh systemctl restart nslcd getent passwd ``` ### IP Tables ```sh yum install iptables-services iptables -A INPUT -p tcp -m tcp --sport 1024:65535 --dport 20:65535 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A INPUT -j DROP service iptables save systemctl enable iptables ``` ### Python 3 Install Python 3 and set up a virtual environment for user __. Then become __ user: ```sh pip install --upgrade pip pip install -r requirements.txt pip install gunicorn ``` ### FTP Create user `vsftpd` and configure `vsftpd`: ```ssh useradd -G users -s /bin/false -d /home/vsftpd vsftpd passwd vsftpd yum install -y vsftpd cp -p /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf-backup cp -p provision/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf chown root.root /etc/vsftpd/vsftpd.conf mkdir -p /project/ftp_public/ mkdir -p /project/vsftpd_user_conf chmod 755 /project/ftp_public/ chown : /project/ftp_public/ systemctl start vsftpd systemctl enable vsftpd ``` ### User directories Create an FTP directory for each FTP user under `/project/ftp_public/`: ```sh mkdir chmod 700 chown : chmod g+s setfacl -R -m u::rwx setfacl -R -m u:vsftpd-guest:rwx setfacl -R -m d:u:vsftpd-guest:rwx setfacl -R -m d:u::rwx ``` ### Create user `vsftpd` in the database ```sh mysql> CREATE USER 'vsftpd'@'localhost' IDENTIFIED BY 'vsftpd'; mysql> GRANT ALL PRIVILEGES ON vsftpd.* TO 'vsftpd'@'localhost'; ``` ### PAM MySQL Download and install `pam_mysql`. Check if there's a library called _pam_mysql.so_ in folder `/usr/lib64/security/`. ```sh cp /etc/pam.d/vsftpd vsftpd.orig cp provision/vsftpd/vsftpd_pam /etc/pam.d/vsftpd chown root:root /etc/pam.d/vsftpd ``` Download mirrors: https://centos.pkgs.org/7/cheese-x86_64/pam_mysql-0.7-0.21.rc1.el7.x86_64.rpm.html ### Deploy the Django database ```sh python manage.py makemigrations python manage.py migrate ``` Create the authentication view for library `pam_mysql.so`: ```sh mysql> CREATE VIEW account_table AS SELECT username,password from ftp_manager_secondaryaccount WHERE expiration_time>now() UNION SELECT username,password FROM ftp_manager_account WHERE expiration_time>now(); ``` __Edit `settings.py` to suit your needs (LDAP, FTP and e-mail settings):__ ``` # ---------------------------------------------------------------------------- # LDAP SERVER AUTH CONFIG # ---------------------------------------------------------------------------- AUTH_LDAP_SERVER_URI = '' # Can leave blank if anonymous binding is sufficient AUTH_LDAP_BIND_DN = '' AUTH_LDAP_BIND_PASSWORD = '' # Any user account that has valid auth credentials can login AUTH_LDAP_USER_SEARCH = LDAPSearch('', ldap.SCOPE_SUBTREE, "(uid=%(user)s)") AUTH_LDAP_GROUP_SEARCH = LDAPSearch('', ldap.SCOPE_SUBTREE, "(objectClass=posixGroup)") AUTH_LDAP_GROUP_TYPE = PosixGroupType() # Map LDAP group membership into Django admin flags AUTH_LDAP_USER_FLAGS_BY_GROUP = { "is_staff": '', "is_superuser": '' } # ---------------------------------------------------------------------------- # biohpc_accounts app # ---------------------------------------------------------------------------- # LDAP URI, user and password for BioHPC Directory (read/write) BIOHPC_ACCOUNTS_LDAP_URI = '' BIOHPC_ACCOUNTS_LDAP_USER = '' BIOHPC_ACCOUNTS_LDAP_PASSWORD = '' # Default primary GID for newly created users BIOHPC_ACCOUNTS_DEFAULT_GID = '' # Samba Domain Name BIOHPC_ACCOUNTS_SAMBA_DOMAIN = '' # Samba Domain SID BIOHPC_ACCOUNTS_SAMBA_SID = '' # LDAP Base DN to check for users/groups anywhere in the tree BIOHPC_ACCOUNTS_BASE_DN = '' # LDAP suffix for new users added to directory, but not enabled for services # Have portal access only BIOHPC_ACCOUNTS_NEW_USER_SUFFIX = '' # LDAP suffix for active users in directory BIOHPC_ACCOUNTS_ACTIVE_USER_SUFFIX = '' # LDAP Suffix for group search BIOHPC_ACCOUNTS_GROUP_SUFFIX = '' # Permitted domains for users email at registration BIOHPC_ACCOUNTS_GOOD_EMAIL_DOMAINS = ['', ''] # ---------------------------------------------------------------------------- # ftp_manager app # ---------------------------------------------------------------------------- FTP_SECRETE = '' FROM_EMAIL = '' ``` ### Run locally Set `DEBUG=True` and test the application: ```sh python manage.py runserver ``` ### Static files and Apache During development, if you use `django.contrib.staticfiles`, this will be done automatically by runserver when `DEBUG` is set to `True`. For production, run `collectstatic` to copy all the static files into `STATIC_ROOT`: ```sh python manage.py collectstatic ``` Have `httpd` serve static files: ```sh yum install httpd cp provision/httpd/apache.conf /etc/httpd/conf.d/apache.conf systemctl start httpd systemctl enable httpd ``` In `settings.py`, set `DEBUG` and `TEMPLATE_DEBUG` to `False`. ### Final check ``` python manage.py check --deploy ``` ### Run FTP application ```sh gunicorn ftp_site.wsgi:application ``` ### Pylint-Django (optional) ```sh pip install pylint pip install pylint-django # To use pylint-django pylint --load-plugins pylint-django pylint --load-plugins=pylint_django --extension-pkg-whitelist=_ldap /devel/work/ftp_site/ ``` ## Contributing to Flash FTP We are open to contributions from external developers. We advise you to open an issue that describes the contribution and then submit a pull request. For additional details, refer to the LICENSE file contained in this repository.