Skip to content

Commit

Permalink
Merge pull request #2992 from Nordix/deprecate-ssl-version
Browse files Browse the repository at this point in the history
Deprecate ssl_version option
  • Loading branch information
benoitc committed May 11, 2023
2 parents 4aca2e4 + d8c3b14 commit b7242be
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 122 deletions.
4 changes: 3 additions & 1 deletion docs/gunicorn_ext.py
Expand Up @@ -48,7 +48,9 @@ def format_settings(app):


def fmt_setting(s):
if callable(s.default):
if hasattr(s, "default_doc"):
val = s.default_doc
elif callable(s.default):
val = inspect.getsource(s.default)
val = "\n".join(" %s" % line for line in val.splitlines())
val = "\n\n.. code-block:: python\n\n" + val
Expand Down
97 changes: 59 additions & 38 deletions docs/source/settings.rst
Expand Up @@ -32,7 +32,7 @@ Config File

**Default:** ``'./gunicorn.conf.py'``

The Gunicorn config file.
:ref:`The Gunicorn config file<configuration_file>`.

A string of the form ``PATH``, ``file:PATH``, or ``python:MODULE_NAME``.

Expand Down Expand Up @@ -305,16 +305,6 @@ The log config file to use.
Gunicorn uses the standard Python logging module's Configuration
file format.

.. _logconfig-json:

logiconfig_json
~~~~~~~~~

* ``--log-config-json FILE``
* ``None``

The log config file written in JSON.

.. _logconfig-dict:

``logconfig_dict``
Expand All @@ -324,16 +314,31 @@ The log config file written in JSON.

The log config dictionary to use, using the standard Python
logging module's dictionary configuration format. This option
takes precedence over the :ref:`logconfig` and :ref:`logConfigJson` options, which uses the
older file configuration format and JSON respectively.

takes precedence over the :ref:`logconfig` and :ref:`logConfigJson` options,
which uses the older file configuration format and JSON
respectively.

Format: https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig

For more context you can look at the default configuration dictionary for logging, which can be found at ``gunicorn.glogging.CONFIG_DEFAULTS``.

.. versionadded:: 19.8

.. _logconfig-json:

``logconfig_json``
~~~~~~~~~~~~~~~~~~

**Command line:** ``--log-config-json FILE``

**Default:** ``None``

The log config to read config from a JSON file

Format: https://docs.python.org/3/library/logging.config.html#logging.config.jsonConfig

.. versionadded:: 20.0

.. _syslog-addr:

``syslog_addr``
Expand Down Expand Up @@ -519,7 +524,10 @@ SSL certificate file

**Default:** ``<_SSLMethod.PROTOCOL_TLS: 2>``

SSL version to use.
SSL version to use (see stdlib ssl module's).

.. deprecated:: 20.2
The option is deprecated and it is currently ignored. Use :ref:`ssl-context` instead.

============= ============
--ssl-version Description
Expand All @@ -542,6 +550,9 @@ TLS_SERVER Auto-negotiate the highest protocol version like TLS,
.. versionchanged:: 20.0
This setting now accepts string names based on ``ssl.PROTOCOL_``
constants.
.. versionchanged:: 20.0.1
The default value has been changed from ``ssl.PROTOCOL_SSLv23`` to
``ssl.PROTOCOL_TLS`` when Python >= 3.6 .

.. _cert-reqs:

Expand All @@ -554,15 +565,13 @@ TLS_SERVER Auto-negotiate the highest protocol version like TLS,

Whether client certificate is required (see stdlib ssl module's)

**Options:**

`--cert-reqs=0` --- no client veirifcation

`--cert-reqs=1` --- ssl.CERT_OPTIONAL

`--cert-reqs=2` --- ssl.CERT_REQUIRED


=========== ===========================
--cert-reqs Description
=========== ===========================
`0` no client veirifcation
`1` ssl.CERT_OPTIONAL
`2` ssl.CERT_REQUIRED
=========== ===========================

.. _ca-certs:

Expand Down Expand Up @@ -954,15 +963,26 @@ The callable needs to accept a single instance variable for the Arbiter.
Called when SSLContext is needed.

Allows fully customized SSL context to be used in place of the default
context.
Allows customizing SSL context.

The callable needs to accept an instance variable for the Config and
a factory function that returns default SSLContext which is initialized
with certificates, private key, cert_reqs, and ciphers according to
config and can be further customized by the callable.
The callable needs to return SSLContext object.

Following example shows a configuration file that sets the minimum TLS version to 1.3:

.. code-block:: python
def ssl_context(conf, default_ssl_context_factory):
import ssl
context = default_ssl_context_factory()
context.minimum_version = ssl.TLSVersion.TLSv1_3
return context
.. versionadded:: 20.2

Server Mechanics
----------------

Expand Down Expand Up @@ -1107,7 +1127,7 @@ If not set, the default temporary directory will be used.

**Command line:** ``-u USER`` or ``--user USER``

**Default:** ``501``
**Default:** ``os.geteuid()``

Switch worker processes to run as this user.

Expand All @@ -1122,7 +1142,7 @@ change the worker process user.

**Command line:** ``-g GROUP`` or ``--group GROUP``

**Default:** ``20``
**Default:** ``os.getegid()``

Switch worker process to run as this group.

Expand Down Expand Up @@ -1226,8 +1246,9 @@ variable. If it is not defined, the default is ``"127.0.0.1"``.
.. note::

The interplay between the request headers, the value of ``forwarded_allow_ips``, and the value of
``secure_scheme_headers`` is complex. Various scenarios are documented below to further elaborate. In each case, we
have a request from the remote address 134.213.44.18, and the default value of ``secure_scheme_headers``:
``secure_scheme_headers`` is complex. Various scenarios are documented below to further elaborate.
In each case, we have a request from the remote address 134.213.44.18, and the default value of
``secure_scheme_headers``:

.. code::
Expand All @@ -1238,7 +1259,7 @@ variable. If it is not defined, the default is ``"127.0.0.1"``.
}
.. list-table::
.. list-table::
:header-rows: 1
:align: center
:widths: auto
Expand All @@ -1247,35 +1268,35 @@ variable. If it is not defined, the default is ``"127.0.0.1"``.
- Secure Request Headers
- Result
- Explanation
* - .. code::
* - .. code::

["127.0.0.1"]
- .. code::

X-Forwarded-Proto: https
- .. code::
- .. code::

wsgi.url_scheme = "http"
- IP address was not allowed
* - .. code::
* - .. code::

"*"
- <none>
- .. code::
- .. code::

wsgi.url_scheme = "http"
- IP address allowed, but no secure headers provided
* - .. code::
* - .. code::

"*"
- .. code::

X-Forwarded-Proto: https
- .. code::
- .. code::

wsgi.url_scheme = "https"
- IP address allowed, one request header matched
* - .. code::
* - .. code::

["134.213.44.18"]
- .. code::
Expand Down
71 changes: 34 additions & 37 deletions gunicorn/config.py
Expand Up @@ -364,25 +364,9 @@ def validate_pos_int(val):


def validate_ssl_version(val):
ssl_versions = {}
for protocol in [p for p in dir(ssl) if p.startswith("PROTOCOL_")]:
ssl_versions[protocol[9:]] = getattr(ssl, protocol)
if val in ssl_versions:
# string matching PROTOCOL_...
return ssl_versions[val]

try:
intval = validate_pos_int(val)
if intval in ssl_versions.values():
# positive int matching a protocol int constant
return intval
except (ValueError, TypeError):
# negative integer or not an integer
# drop this in favour of the more descriptive ValueError below
pass

raise ValueError("Invalid ssl_version: %s. Valid options: %s"
% (val, ', '.join(ssl_versions)))
if val != SSLVersion.default:
sys.stderr.write("Warning: option `ssl_version` is deprecated and it is ignored. Use ssl_context instead.\n")
return val


def validate_string(val):
Expand Down Expand Up @@ -736,7 +720,7 @@ class WorkerConnections(Setting):
desc = """\
The maximum number of simultaneous clients.
This setting only affects the Eventlet and Gevent worker types.
This setting only affects the ``gthread``, ``eventlet`` and ``gevent`` worker types.
"""


Expand Down Expand Up @@ -1066,6 +1050,7 @@ class Chdir(Setting):
cli = ["--chdir"]
validator = validate_chdir
default = util.getcwd()
default_doc = "``'.'``"
desc = """\
Change directory to specified directory before loading apps.
"""
Expand Down Expand Up @@ -1157,6 +1142,7 @@ class User(Setting):
meta = "USER"
validator = validate_user
default = os.geteuid()
default_doc = "``os.geteuid()``"
desc = """\
Switch worker processes to run as this user.
Expand All @@ -1173,6 +1159,7 @@ class Group(Setting):
meta = "GROUP"
validator = validate_group
default = os.getegid()
default_doc = "``os.getegid()``"
desc = """\
Switch worker process to run as this group.
Expand Down Expand Up @@ -2019,14 +2006,25 @@ def ssl_context(config, default_ssl_context_factory):
desc = """\
Called when SSLContext is needed.
Allows fully customized SSL context to be used in place of the default
context.
Allows customizing SSL context.
The callable needs to accept an instance variable for the Config and
a factory function that returns default SSLContext which is initialized
with certificates, private key, cert_reqs, and ciphers according to
config and can be further customized by the callable.
The callable needs to return SSLContext object.
Following example shows a configuration file that sets the minimum TLS version to 1.3:
.. code-block:: python
def ssl_context(conf, default_ssl_context_factory):
import ssl
context = default_ssl_context_factory()
context.minimum_version = ssl.TLSVersion.TLSv1_3
return context
.. versionadded:: 20.2
"""

class ProxyProtocol(Setting):
Expand Down Expand Up @@ -2105,17 +2103,12 @@ class SSLVersion(Setting):
else:
default = ssl.PROTOCOL_SSLv23

desc = """\
SSL version to use (see stdlib ssl module's)
.. versionchanged:: 20.0.1
The default value has been changed from ``ssl.PROTOCOL_SSLv23`` to
``ssl.PROTOCOL_TLS`` when Python >= 3.6 .
"""
default = ssl.PROTOCOL_SSLv23
desc = """\
SSL version to use.
SSL version to use (see stdlib ssl module's).
.. deprecated:: 20.2
The option is deprecated and it is currently ignored. Use :ref:`ssl-context` instead.
============= ============
--ssl-version Description
Expand All @@ -2138,6 +2131,9 @@ class SSLVersion(Setting):
.. versionchanged:: 20.0
This setting now accepts string names based on ``ssl.PROTOCOL_``
constants.
.. versionchanged:: 20.0.1
The default value has been changed from ``ssl.PROTOCOL_SSLv23`` to
``ssl.PROTOCOL_TLS`` when Python >= 3.6 .
"""


Expand All @@ -2149,13 +2145,14 @@ class CertReqs(Setting):
default = ssl.CERT_NONE
desc = """\
Whether client certificate is required (see stdlib ssl module's)
============== ===========================
`--cert-reqs=0` --- no client veirifcation
`--cert-reqs=1` --- ssl.CERT_OPTIONAL
`--cert-reqs=2` --- ssl.CERT_REQUIRED
============== ===========================
=========== ===========================
--cert-reqs Description
=========== ===========================
`0` no client veirifcation
`1` ssl.CERT_OPTIONAL
`2` ssl.CERT_REQUIRED
=========== ===========================
"""


Expand Down
4 changes: 1 addition & 3 deletions gunicorn/sock.py
Expand Up @@ -213,13 +213,11 @@ def close_sockets(listeners, unlink=True):

def ssl_context(conf):
def default_ssl_context_factory():
context = ssl.SSLContext(conf.ssl_version)
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile=conf.ca_certs)
context.load_cert_chain(certfile=conf.certfile, keyfile=conf.keyfile)
context.verify_mode = conf.cert_reqs
if conf.ciphers:
context.set_ciphers(conf.ciphers)
if conf.ca_certs:
context.load_verify_locations(cafile=conf.ca_certs)
return context

return conf.ssl_context(conf, default_ssl_context_factory)
Expand Down

0 comments on commit b7242be

Please sign in to comment.