TPPZ
TPPZ

Reputation: 4891

Secure FTP deployment for Azure App using python (using TLS or FTPS)

I am trying to copy some files to an Azure App using python as part of a wider python script.

I can do this using FTP, but I can not figure out how to do it in a secure way using TLS.

I am using the credentials I downloaded from the Azure Portal clicking on "Get Publish Profile", then using them inside the python code like this:

import ftplib

ftpServer = ftplib.FTP_TLS(host='waws-<...>.ftp.azurewebsites.windows.net',
                        user='<MY_USER>\$<MY_USER>',
                        passwd='<VERY_LONG_PSW>')

however when executing ftpServer.cwd('<THE_PATH_TO_INSPECT>') then I see: ConnectionRefusedError: [Errno 111] Connection refused

When using ftplib.FTP(...) instead of ftplib.FTP_TLS(...) everything works as expected.

Looking at the Python docs here https://docs.python.org/3.5/library/ftplib.html it seems I should make sure there is some sort of implicit/explicit condition met, but I can not figure out what to do.

Reading on various web resources it seems I should use a different port than the standard 21, someone is saying 990, some other is saying 989, but I can not figure out where to specify this different port in the python code.

EDIT 1:

It seems this implicit connection for FTP is related to TLS version 1.2 (as per python docs), I am not 100% sure as I am not familiar with these standards, however I've tried anyway but without success. Bare in mind that <MY_USER>\$<MY_USER> (and password) comes from the content of the file I download from the Azure Portal as a "Publish Profile", see below:

$ python
Python 3.6.6 |Anaconda, Inc.| (default, Jun 28 2018, 17:14:51) 
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> 
>>> 
>>> 
>>> import ftplib
>>> 
>>> 
>>> ftpServer = ftplib.FTP_TLS(host='waws-<...>.ftp.azurewebsites.windows.net',
...                         user='<MY_USER>\$<MY_USER>',
...                         passwd='<VERY_LONG_PSW>')
>>> 
>>> 
>>> 
>>> ftpServer.dir()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/<MY_USER>/Conda/lib/python3.6/ftplib.py", line 575, in dir
    self.retrlines(cmd, func)
  File "/home/<MY_USER>/Conda/lib/python3.6/ftplib.py", line 468, in retrlines
    with self.transfercmd(cmd) as conn, \
  File "/home/<MY_USER>/Conda/lib/python3.6/ftplib.py", line 399, in transfercmd
    return self.ntransfercmd(cmd, rest)[0]
  File "/home/<MY_USER>/Conda/lib/python3.6/ftplib.py", line 798, in ntransfercmd
    conn, size = FTP.ntransfercmd(self, cmd, rest)
  File "/home/<MY_USER>/Conda/lib/python3.6/ftplib.py", line 361, in ntransfercmd
    source_address=self.source_address)
  File "/home/<MY_USER>/Conda/lib/python3.6/socket.py", line 724, in create_connection
    raise err
  File "/home/<MY_USER>/Conda/lib/python3.6/socket.py", line 713, in create_connection
    sock.connect(sa)
ConnectionRefusedError: [Errno 111] Connection refused
>>> 
>>> 

Upvotes: 0

Views: 1431

Answers (1)

evilSnobu
evilSnobu

Reputation: 26324

Seems to work just fine on implicit FTPS (990/TCP):

$ openssl s_client -connect waws-prod-am2-119.ftp.azurewebsites.windows.net:990

CONNECTED(00000003)
[...]
---
Certificate chain
 0 s:/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/
      CN=waws-prod-am2-119.publish.azurewebsites.windows.net
   i:/C=US/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA
 1 s:/C=US/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA
---
[...]
SSL handshake has read 3574 bytes and written 390 bytes
Verification: OK
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-SHA384
Server public key is 2048 bit
[...]
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-SHA384
    [...]
    Verify return code: 0 (ok)
    Extended master secret: yes
---
220 Microsoft FTP Service

The Python client library may be out of date or does not have a recent CA bundle containing the DigiCert CAs. You shouldn't be FTP-ing, try to upload to blob storage instead and have the Web App serve the files from that storage account (with a SAS signature if the files shouldn't be public).

If you're trying to deploy the Web App, use a git repo or Web Deploy, it's much more reliable.

Using ftplib in stock Python 3.6:

>>> ftpServer = FTP_TLS(host='waws-prod-am2-119.ftp.azurewebsites.windows.net',
...                         user='myuser\$myuser',
...                         passwd='rM....dsFsfp')

>>> ftpServer.dir()
03-21-17  09:27AM       <DIR>          .ssh
02-22-18  08:19AM       <DIR>          ciphers
02-22-18  10:28AM       <DIR>          data
01-12-18  12:58AM       <DIR>          LogFiles
02-22-18  08:16AM       <DIR>          site

>>> ftpServer.cwd('data')
'250 CWD command successful.'

Upvotes: 1

Related Questions