eventlet / eventlet

Concurrent networking library for Python
https://eventlet.net
Other
1.24k stars 320 forks source link

ssl.SSLError: [SSL: TLSV1_ALERT_UNKNOWN_CA] #712

Open busslina opened 3 years ago

busslina commented 3 years ago

Today I have move from flask default development server (Werkzeug) to a production one. I installed Evenlet and run it (Flask Socket IO detects Evenlet is installed and run it). Apparently everything runs fine. My https site runs okay. Even better, because with Werkzeug server, the app was randomly crashing due to "headers already sent" bug and it was breaking my head. But it appears constantly a SSL error that is not causing my server crash. But I want to know why occurs. Every browser that I tested with it process successfully the SSL certificate (LetsEncrypt).

Traceback (most recent call last): File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/hubs/poll.py", line 111, in wait listener.cb(fileno) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/greenthread.py", line 221, in main result = function(*args, kwargs) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/wsgi.py", line 815, in process_request proto.init(conn_state, self) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/wsgi.py", line 346, in init self.handle() File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/wsgi.py", line 379, in handle self.handle_one_request() File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/wsgi.py", line 408, in handle_one_request self.raw_requestline = self._read_request_line() File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/wsgi.py", line 391, in _read_request_line return self.rfile.readline(self.server.url_length_limit) File "/usr/lib/python3.7/socket.py", line 589, in readinto return self._sock.recv_into(b) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/green/ssl.py", line 252, in recv_into return self.base_recv(nbytes, flags, into=True, buffer=buffer) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/green/ssl.py", line 267, in base_recv read = self.read(nbytes, buffer) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/green/ssl.py", line 187, in read super(GreenSSLSocket, self).read, *args, *kwargs) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/green/ssl.py", line 161, in _call_trampolining return func(a, kw) File "/usr/lib/python3.7/ssl.py", line 911, in read return self._sslobj.read(len, buffer) ssl.SSLError: [SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca (_ssl.c:2488) Removing descriptor: 9

temoto commented 3 years ago

Sorry that you had troubles.

We need a detailed (preferrably automated like script/repo/image) way to reproduce the issue to be able to help.

busslina commented 3 years ago

I post here my main.py script which launch every module. I hope this is usefull.

PREVENT_USED_AS_MODULE = False
EVENTLET_MODE = True
GEVENT_MODE = False

if PREVENT_USED_AS_MODULE and __name__ != '__main__':
    raise Exception('Executing main script as module')
else:
    import os
    from core.auth import Auth, AuthMiddleware
    from flask import Flask
    from core.commons import get_mongodb_uri, set_database, Commons
    from core.config import Config
    from core.websocket import Websocket
    from core.routes import RouteManager
    from flask_cors import CORS
    from pymongo import MongoClient
    from core.telegram import Telegram
    import logging
    from ssl import SSLContext

    try:

        # Setting up log configuration
        log = logging.getLogger('werkzeug')
        log.setLevel(logging.ERROR)

        # Load configuration
        Config.load_config_file()

        # Flask App
        Commons.app = Flask(__name__)
        Commons.app.config['SERVER_NAME'] = Config.HOST
        Commons.app.config['SECRET_KEY'] = os.urandom(16)

        # MongoDB connection
        mongo = MongoClient(get_mongodb_uri(), tls=True)
        set_database(mongo.get_default_database())

        # Check database values
        if not Auth.check_database_values():
            raise Exception('Database check failed. Admin users count is invalid')

        # CORS
        cors = CORS(Commons.app)
        Commons.app.config['CORS_HEADERS'] = 'Content-Type'

        # JWT configuration
        Auth.configure_jwt(Commons.app)

        # Middlewares
        Commons.app.wsgi_app = AuthMiddleware(Commons.app.wsgi_app)

        # Routes
        RouteManager.init(Commons.app)

        # Socket IO
        Websocket.init(Commons.app, debug_mode=False)
        socketio = Websocket.get_socket_io()

        # Telegram Bot
        Telegram.init()
        Telegram.send_message_to_admin('Starting')

        if __name__ == '__main__':

            DEBUG = True
            USE_RELOADER = True

            # Execute web app
            if EVENTLET_MODE:
                socketio.run(
                    app=Commons.app,
                    port=443,
                    host='0.0.0.0',
                    keyfile=Config.SSL_KEY,
                    certfile=Config.SSL_CERT,
                    debug=DEBUG,
                    use_reloader=USE_RELOADER
                )
            elif GEVENT_MODE:
                context = SSLContext()
                context.load_cert_chain(Config.SSL_CERT, Config.SSL_KEY)
                socketio.run(
                    app=Commons.app,
                    port=443,
                    host='0.0.0.0',
                    ssl_context=context,
                    debug=DEBUG,
                    use_reloader=USE_RELOADER
                )
            else:
                socketio.run(
                    app=Commons.app,
                    port=443,
                    host='0.0.0.0',
                    ssl_context=(Config.SSL_CERT, Config.SSL_KEY),
                    debug=DEBUG,
                    use_reloader=USE_RELOADER
                )

            # Closing message
            Telegram.send_message_to_admin('Closing')

    except Exception as e:
        error_msg = f'Flask App failed: {e}'
        print(error_msg)
        Telegram.send_message_to_admin(error_msg)
temoto commented 3 years ago

Good start, it probably is useful. Do you get that error with EVENTLET_MODE=False and no eventlet in virtualenv?

Likely you can remove pymongo and telegram from reproduction script.

Likely problem is in Config.SSL_CERT, please share it too. Don't share SSL_KEY.

Please fill this script until you get that error:

python3 -m venv venv
venv/bin/pip install eventlet flask
venv/bin/python main.py
busslina commented 3 years ago

Okay, firstable, with EVENTLET_MODE=False and no eventlet installed on virtualenv never happened this error.

Secondly, after removing pymongo and telegram from execution i get the same error. My code:

PREVENT_USED_AS_MODULE = False
EVENTLET_MODE = True
GEVENT_MODE = False

if PREVENT_USED_AS_MODULE and __name__ != '__main__':
    raise Exception('Executing main script as module')
else:
    import os
    from core.auth import Auth, AuthMiddleware
    from flask import Flask
    from core.commons import get_mongodb_uri, set_database, Commons
    from core.config import Config
    from core.websocket import Websocket
    from core.routes import RouteManager
    from flask_cors import CORS
    from pymongo import MongoClient
    from core.telegram import Telegram
    import logging
    from ssl import SSLContext

    try:

        # Setting up log configuration
        log = logging.getLogger('werkzeug')
        log.setLevel(logging.ERROR)

        # Load configuration
        Config.load_config_file()

        # Flask App
        Commons.app = Flask(__name__)
        Commons.app.config['SERVER_NAME'] = Config.HOST
        Commons.app.config['SECRET_KEY'] = os.urandom(16)

        # MongoDB connection
        # mongo = MongoClient(get_mongodb_uri(), tls=True)
        # set_database(mongo.get_default_database())

        # Check database values
        # if not Auth.check_database_values():
        #     raise Exception('Database check failed. Admin users count is invalid')

        # CORS
        cors = CORS(Commons.app)
        Commons.app.config['CORS_HEADERS'] = 'Content-Type'

        # JWT configuration
        Auth.configure_jwt(Commons.app)

        # Middlewares
        Commons.app.wsgi_app = AuthMiddleware(Commons.app.wsgi_app)

        # Routes
        RouteManager.init(Commons.app)

        # Socket IO
        Websocket.init(Commons.app, debug_mode=False)
        socketio = Websocket.get_socket_io()

        # Telegram Bot
        # Telegram.init()
        # Telegram.send_message_to_admin('Starting')

        if __name__ == '__main__':

            DEBUG = True
            USE_RELOADER = True

            # Execute web app
            if EVENTLET_MODE:
                socketio.run(
                    app=Commons.app,
                    port=443,
                    host='0.0.0.0',
                    keyfile=Config.SSL_KEY,
                    certfile=Config.SSL_CERT,
                    debug=DEBUG,
                    use_reloader=USE_RELOADER
                )
            elif GEVENT_MODE:
                context = SSLContext()
                context.load_cert_chain(Config.SSL_CERT, Config.SSL_KEY)
                socketio.run(
                    app=Commons.app,
                    port=443,
                    host='0.0.0.0',
                    ssl_context=context,
                    debug=DEBUG,
                    use_reloader=USE_RELOADER
                )
            else:
                socketio.run(
                    app=Commons.app,
                    port=443,
                    host='0.0.0.0',
                    ssl_context=(Config.SSL_CERT, Config.SSL_KEY),
                    debug=DEBUG,
                    use_reloader=USE_RELOADER
                )

            # Closing message
            # Telegram.send_message_to_admin('Closing')

    except Exception as e:
        error_msg = f'Flask App failed: {e}'
        print(error_msg)
        # Telegram.send_message_to_admin(error_msg)

Finally, my SSL certificate generated with certbot and Let's Encrypt. I have two files cert1.pem and fullchain1.pem. I tried with both but usually I use fullchain one:

-----BEGIN CERTIFICATE----- MIIFKjCCBBKgAwIBAgISA1W7ySMUmgxAB0oraAg3ylbJMA0GCSqGSIb3DQEBCwUA MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD EwJSMzAeFw0yMTAzMjAxMTQyMjJaFw0yMTA2MTgxMTQyMjJaMBYxFDASBgNVBAMT C2J1c3NsaW5hLmV1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0PI0 Q24kOljs8WBbUJKVfITVX7bFnhJ/Uaz+74FBIFlLSKRHV50kqAdpm5XVvaRYDpH0 D824PwzxL9oC0x9EuVhyNXevhdUP5MFyRS9WK/MwUNyM+QFJ0WFXTXPj4N2UpOR4 cVjg40knMdl1ausBFty2jHUDZvHtvZsP+843f8fk7RWTT4u0p5N2SABLkV3DblP5 tpLuXtVagl9o4T4wGwx33RTHHWZYluslSpGUl6ydriqhFfeoe6M3KzM3GpxnH5eX IHYFRNas+Ruxt+N7bGcVXsGZ8YUTZW+3/962VL6a5Q209QTHvBn3Op9/kNbVuyNa ieuEM7ne6YylpMO8iwIDAQABo4ICVDCCAlAwDgYDVR0PAQH/BAQDAgWgMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQW BBRz+h3rmwwHLp9wA4QnOPik4q7pLDAfBgNVHSMEGDAWgBQULrMXt1hWy65QCUDm H6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0dHA6Ly9yMy5v LmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iub3JnLzAl BgNVHREEHjAcgg0qLmJ1c3NsaW5hLmV1ggtidXNzbGluYS5ldTBMBgNVHSAERTBD MAgGBmeBDAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8v Y3BzLmxldHNlbmNyeXB0Lm9yZzCCAQMGCisGAQQB1nkCBAIEgfQEgfEA7wB1AJQg vB6O1Y1siHMfgosiLA3R2k1ebE+UPWHbTi9YTaLCAAABeE+ocPoAAAQDAEYwRAIg bonQoD4JCqKeJjhGqatqy2iZecYJF0rClvkyETvf0rICIEZgK9aCZF2WQOsNWv6E UFya61t9erZxqmuMEknUZftsAHYA9lyUL9F3MCIUVBgIMJRWjuNNExkzv98MLyAL zE7xZOMAAAF4T6hxCQAABAMARzBFAiEA/DDLBf+AjTo97xF6JR6SmXvjHWQcRr7k TL2NvxypMCcCICaS7c58wcYspKnzPP1G/aOXthcEWXtB99JsAYMVg6zoMA0GCSqG SIb3DQEBCwUAA4IBAQAulBtPDY5w707Bzq1TmMnbh0SuPhEvFSfoNr+HFJjlnkpw IkKButgjY2obnQHsPpfMALzH+GrzSx5ksCLa1vqkvywia/5zPJEpzDmSZvfCnWLU mnwlSCMHxurIqRvhc+NkbiQRqxbS2+lNjWT3y0uQxDDpqcI9PJZWSwNuMB5qUpzG fppop6ykwJoBQisHFs2z5D1pGK4VYawjfp8pVMd5CYs+8+EWYBx1eC2VYW1tadOm L1haoZRfvomwiFlyzvY2EpRnhxEY0ysCK+DvaTDq3UTQm5BPvSTwWTBoGH8fRdIR u0f+zO3zopxtIE9snGCutP1fahsTHGGb9H+EuKXT -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEZTCCA02gAwIBAgIQQAF1BIMUpMghjISpDBbN3zANBgkqhkiG9w0BAQsFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT DkRTVCBSb290IENBIFgzMB4XDTIwMTAwNzE5MjE0MFoXDTIxMDkyOTE5MjE0MFow MjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxCzAJBgNVBAMT AlIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuwIVKMz2oJTTDxLs jVWSw/iC8ZmmekKIp10mqrUrucVMsa+Oa/l1yKPXD0eUFFU1V4yeqKI5GfWCPEKp Tm71O8Mu243AsFzzWTjn7c9p8FoLG77AlCQlh/o3cbMT5xys4Zvv2+Q7RVJFlqnB U840yFLuta7tj95gcOKlVKu2bQ6XpUA0ayvTvGbrZjR8+muLj1cpmfgwF126cm/7 gcWt0oZYPRfH5wm78Sv3htzB2nFd1EbjzK0lwYi8YGd1ZrPxGPeiXOZT/zqItkel /xMY6pgJdz+dU/nPAeX1pnAXFK9jpP+Zs5Od3FOnBv5IhR2haa4ldbsTzFID9e1R oYvbFQIDAQABo4IBaDCCAWQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E BAMCAYYwSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5p ZGVudHJ1c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTE p7Gkeyxx+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEE AYLfEwEBATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2Vu Y3J5cHQub3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0 LmNvbS9EU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYf r52LFMLGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0B AQsFAAOCAQEA2UzgyfWEiDcx27sT4rP8i2tiEmxYt0l+PAK3qB8oYevO4C5z70kH ejWEHx2taPDY/laBL21/WKZuNTYQHHPD5b1tXgHXbnL7KqC401dk5VvCadTQsvd8 S8MXjohyc9z9/G2948kLjmE6Flh9dDYrVYA9x2O+hEPGOaEOa1eePynBgPayvUfL qjBstzLhWVQLGAkXXmNs+5ZnPBxzDJOLxhF2JIbeQAcH5H0tZrUlo5ZYyOqA7s9p O5b85o3AM/OJ+CktFBQtfvBhcJVd9wvlwPsk+uyOy2HI7mNxKKgsBTt375teA2Tw UdHkhVNcsAKX1H7GNNLOEADksd86wuoXvg== -----END CERTIFICATE-----

Thank you very much for your help.

busslina commented 3 years ago

Good start, it probably is useful. Do you get that error with EVENTLET_MODE=False and no eventlet in virtualenv?

Likely you can remove pymongo and telegram from reproduction script.

Likely problem is in Config.SSL_CERT, please share it too. Don't share SSL_KEY.

Please fill this script until you get that error:

python3 -m venv venv
venv/bin/pip install eventlet flask
venv/bin/python main.py

I use pipenv tool but no big difference.

sh scripts/server.sh sudo pipenv run python3 main.py (929) wsgi starting up on https://0.0.0.0:443 (929) accepted ('192.168.1.1', 53788) Traceback (most recent call last): File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/hubs/poll.py", line 111, in wait listener.cb(fileno) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/greenthread.py", line 221, in main result = function(*args, kwargs) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/wsgi.py", line 815, in process_request proto.init(conn_state, self) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/wsgi.py", line 346, in init self.handle() File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/wsgi.py", line 379, in handle self.handle_one_request() File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/wsgi.py", line 408, in handle_one_request self.raw_requestline = self._read_request_line() File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/wsgi.py", line 391, in _read_request_line return self.rfile.readline(self.server.url_length_limit) File "/usr/lib/python3.7/socket.py", line 589, in readinto return self._sock.recv_into(b) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/green/ssl.py", line 252, in recv_into return self._baserecv(nbytes, flags, into=True, buffer=buffer) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/green/ssl.py", line 267, in _baserecv read = self.read(nbytes, buffer) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/green/ssl.py", line 187, in read super(GreenSSLSocket, self).read, *args, *kwargs) File "/root/.local/share/virtualenvs/https-server-S4Igx79L/lib/python3.7/site-packages/eventlet/green/ssl.py", line 161, in _call_trampolining return func(a, kw) File "/usr/lib/python3.7/ssl.py", line 911, in read return self._sslobj.read(len, buffer)

Also I have to say that I use DNS loopback option in my router in order to be able to connect to my site from inside of the same LAN.

This is triggered always without open my site on the browser.

(929) accepted ('192.168.1.1', 53788)

temoto commented 3 years ago

Yes, pipenv is nice. The goal here is to transfer a minimal environment reproducing an error. So please share pipenv config with minimum of lines required to get error.

On Thu, May 20, 2021, 21:54 busslina @.***> wrote:

Good start, it probably is useful. Do you get that error with EVENTLET_MODE=False and no eventlet in virtualenv?

Likely you can remove pymongo and telegram from reproduction script.

Likely problem is in Config.SSL_CERT, please share it too. Don't share SSL_KEY.

Please fill this script until you get that error:

python3 -m venv venv venv/bin/pip install eventlet flask venv/bin/python main.py

I use pipenv tool but no big difference.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/eventlet/eventlet/issues/712#issuecomment-845387276, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAGTMJBXSZ65NRGPXP2F33TOVLHPANCNFSM45HMDFRQ .

busslina commented 3 years ago

Not sure this is what you want. Pipfile content:

[[source]] url = "https://pypi.org/simple" verify_ssl = true name = "pypi"

[packages] bson = "" flask = "" pymongo = "" cryptography = "" python-telegram-bot = "" flask-jwt-extended = "" flask-cors = "" flask-socketio = "" eventlet = "*"

[dev-packages]

[requires] python_version = "3.7"

pip freeze command output:

APScheduler==3.6.3 bidict==0.21.2 bson==0.5.10 certifi==2020.12.5 cffi==1.14.5 click==8.0.0 cryptography==3.4.7 dnspython==1.16.0 eventlet==0.31.0 Flask==2.0.0 Flask-Cors==3.0.10 Flask-JWT-Extended==4.2.1 Flask-SocketIO==5.0.3 greenlet==1.1.0 itsdangerous==2.0.1 Jinja2==3.0.1 MarkupSafe==2.0.1 pycparser==2.20 PyJWT==2.1.0 pymongo==3.11.4 python-dateutil==2.8.1 python-engineio==4.2.0 python-socketio==5.3.0 python-telegram-bot==13.5 pytz==2021.1 six==1.16.0 tornado==6.1 tzlocal==2.1 Werkzeug==2.0.1 zope.event==4.5.0 zope.interface==5.4.0

busslina commented 3 years ago

Still with that problem. It's weird because I use a valid Letsencrypt certificate. If anyone has an idea about it I would appreciate