Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation updates + nginx cleanup #57

Merged
merged 5 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 77 additions & 23 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ operate their own.
Running a Porter Instance
-------------------------

By default, Porter runs on port ``9155``.

Security Considerations
***********************

Expand All @@ -39,16 +41,49 @@ Security Considerations


.. note::

Ideally, you would run Porter behind a reverse proxy (e.g. `nginx <https://www.nginx.com/>`_) for additional
functionality such as HTTPS, CORS, authentication etc.
Managing a Porter instance on ``mainnet`` requires solid server
administration skills. This includes understanding how to provision and
secure servers, applying security best practices, and maintaining
consistent system performance. Key competencies like network configuration,
SSL/TLS encryption, and CORS, are also essential to ensure the
secure and efficient operation of your Porter instance.

.. warning::

By default, Porter runs over HTTP. However, Porter instances must be
secured with a valid HTTPS certificate in order to be compatible with
network applications. A Porter instance running without SSL/TLS is not
only insecure but also browser-based apps and websites will be
unable to connect.

To secure your Porter instance with HTTPS, use a reverse proxy
like `Nginx <https://www.nginx.com/>`_ or
`Apache <https://httpd.apache.org/docs/2.4/ssl/ssl_howto.html>`_ for SSL
processing, and potentially `Let's Encrypt <https://letsencrypt.org/>`_
for automated SSL certificate issuance and renewal. Additionally, consider
using cloud-based services like AWS/Digital Ocean load balancers or
Cloudflare for SSL termination and enhanced security.


Configurable Operation Timeouts
*******************************
Some Porter endpoints allow optional integer timeouts to be specified as a
parameter. However, to prevent DDOS attacks, timeouts are capped. By default
the ``/decrypt`` and ``/get_ursulas`` endpoints limit their timeouts at 15s. If
the optional timeout parameter is not provided or the provided timeout
parameter value is greater than the default timeout, the timeout used for the
operation will be the default timeout.

If modifying the default timeout values is desirable, they can be configured
via environment variables:

* ``PORTER_MAX_DECRYPTION_TIMEOUT`` for ``/decrypt`` operations
* ``PORTER_MAX_GET_URSULAS_TIMEOUT`` for ``/get_ursulas`` operations


Run via Docker
**************

By default, Porter runs on port ``9155``.

#. Get the latest ``porter`` image:

.. code:: bash
Expand All @@ -66,7 +101,8 @@ By default, Porter runs on port ``9155``.
--restart=unless-stopped \
nucypher/porter:latest \
nucypher-porter run \
--eth-endpoint <YOUR WEB3 PROVIDER URI> \
--eth-endpoint <YOUR ETH WEB3 PROVIDER URI> \
--polygon-endpoint <YOUR POLYGON WEB3 PROVIDER URI> \
--domain <TACO DOMAIN>

The command above is for illustrative purposes and can be modified as
Expand Down Expand Up @@ -113,7 +149,7 @@ For a full list of CLI options after installation ``nucypher-porter``, run:
* Run Porter service via HTTP
.. code:: console

$ nucypher-porter run --eth-endpoint <YOUR WEB3 PROVIDER URI> --domain <TACO DOMAIN>
$ nucypher-porter run --eth-endpoint <YOUR ETH WEB3 PROVIDER URI> --polygon-endpoint <YOUR POLYGON WEB3 PROVIDER URI> --domain <TACO DOMAIN>


______
Expand All @@ -127,6 +163,7 @@ For a full list of CLI options after installation ``nucypher-porter``, run:

TACo Domain: <TACO DOMAIN>
ETH Endpoint URI: ...
Polygon Endpoint URI: ...
Running Porter Web Controller at http://127.0.0.1:9155


Expand Down Expand Up @@ -205,6 +242,15 @@ Parameters
| ``encrypted_decryption_requests`` | Dict[String, String] | | Base64 encoded encrypted decryption requests |
| | | | keyed by node staking provider address. |
+-----------------------------------+----------------------+------------------------------------------------+
| ``timeout`` | *(Optional)* int | | The timeout for the operation. Default value |
| | | | is 15s unless the Porter instance is |
| | | | configured to modify the default setting via |
| | | | the ``PORTER_MAX_DECRYPTION_TIMEOUT`` env |
| | | | variable on startup. Timeouts provided that |
| | | | are greater than this max default value are |
| | | | capped at the default value |
+-----------------------------------+----------------------+------------------------------------------------+


Returns
^^^^^^^
Expand Down Expand Up @@ -256,7 +302,7 @@ Example Response
}
}
},
"version":"1.0.0"
"version": "3.3.0"
}

.. note::
Expand All @@ -272,19 +318,27 @@ and associated information.

Parameters
^^^^^^^^^^
+----------------------------------+---------------+-----------------------------------------------+
| **Parameter** | **Type** | **Description** |
+==================================+===============+===============================================+
| ``quantity`` | Integer | Number of total TACo nodes to return. |
+----------------------------------+---------------+-----------------------------------------------+
| ``include_ursulas`` *(Optional)* | List[String] | | List of Ursula checksum addresses to |
| | | | give preference to. If any of these Ursulas |
| | | | are unavailable, they will not be included |
| | | | in result. |
+----------------------------------+---------------+-----------------------------------------------+
| ``exclude_ursulas`` *(Optional)* | List[String] | | List of Ursula checksum addresses to not |
| | | | include in the result. |
+----------------------------------+---------------+-----------------------------------------------+
+----------------------------------+------------------+------------------------------------------------+
| **Parameter** | **Type** | **Description** |
+==================================+==================+================================================+
| ``quantity`` | Integer | Number of total TACo nodes to return. |
+----------------------------------+------------------+------------------------------------------------+
| ``include_ursulas`` *(Optional)* | List[String] | | List of Ursula checksum addresses to |
| | | | give preference to. If any of these Ursulas |
| | | | are unavailable, they will not be included |
| | | | in result. |
+----------------------------------+------------------+------------------------------------------------+
| ``exclude_ursulas`` *(Optional)* | List[String] | | List of Ursula checksum addresses to not |
| | | | include in the result. |
+----------------------------------+------------------+------------------------------------------------+
| ``timeout`` | *(Optional)* int | | The timeout for the operation. Default value |
| | | | is 15s unless the Porter instance is |
| | | | configured to modify the default setting via |
| | | | the ``PORTER_MAX_GET_URSULAS_TIMEOUT`` env |
| | | | variable on startup. Timeouts provided that |
| | | | are greater than this max default value are |
| | | | capped at the default value |
+----------------------------------+------------------+------------------------------------------------+


Returns
Expand Down Expand Up @@ -351,7 +405,7 @@ Example Response
}
]
},
"version": "1.0.0"
"version": "3.3.0"
}


Expand Down Expand Up @@ -455,5 +509,5 @@ Example Response
}
]
},
"version": "1.0.0"
"version": "3.3.0"
}
6 changes: 3 additions & 3 deletions deploy/docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ services:
- .:/code
- ~/.local/share/nucypher:/nucypher
command: ["nucypher-porter", "run",
"--eth-endpoint", "${WEB3_PROVIDER_URI}",
"--domain", "${NUCYPHER_NETWORK}",
"--allow-origins", "${PORTER_CORS_ALLOW_ORIGINS}"] # empty string if env var not defined which translates to CORS not enabled by default
"--eth-endpoint", "${ETH_WEB3_PROVIDER_URI}",
"--polygon-endpoint", "${POLY_WEB3_PROVIDER_URI}",
"--domain", "${TACO_DOMAIN}"]
4 changes: 0 additions & 4 deletions deploy/docker/nginx/Dockerfile

This file was deleted.

38 changes: 0 additions & 38 deletions deploy/docker/nginx/docker-compose.yml

This file was deleted.

19 changes: 0 additions & 19 deletions deploy/docker/nginx/porter.local_location

This file was deleted.

42 changes: 22 additions & 20 deletions porter/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os
from pathlib import Path
from typing import Dict, List, NamedTuple, Optional, Sequence
from typing import Dict, List, NamedTuple, Optional, Sequence, Union

from constant_sorrow.constants import NO_CONTROL_PROTOCOL
from eth_typing import ChecksumAddress
Expand Down Expand Up @@ -56,7 +56,7 @@ class Porter(Learner):

DEFAULT_PORT = 9155

MAX_GET_URSULAS_TIMEOUT = os.getenv("PORTER_GET_URSULAS_TIMEOUT", default=15)
MAX_GET_URSULAS_TIMEOUT = os.getenv("PORTER_MAX_GET_URSULAS_TIMEOUT", default=15)
MAX_DECRYPTION_TIMEOUT = os.getenv(
"PORTER_MAX_DECRYPTION_TIMEOUT",
default=ThresholdDecryptionClient.DEFAULT_DECRYPTION_TIMEOUT,
Expand Down Expand Up @@ -152,15 +152,9 @@ def get_ursulas(
include_ursulas: Optional[Sequence[ChecksumAddress]] = None,
timeout: Optional[int] = None,
) -> List[UrsulaInfo]:
if timeout and timeout > self.MAX_GET_URSULAS_TIMEOUT:
self.log.warn(
f"Provided sampling timeout ({timeout}s) exceeds "
f"maximum ({self.MAX_GET_URSULAS_TIMEOUT}s); "
f"using {self.MAX_GET_URSULAS_TIMEOUT}s instead"
)
timeout = self.MAX_GET_URSULAS_TIMEOUT
else:
timeout = timeout or self.MAX_GET_URSULAS_TIMEOUT
timeout = self._configure_timeout(
"sampling", timeout, self.MAX_GET_URSULAS_TIMEOUT
)

reservoir = self._make_reservoir(exclude_ursulas, include_ursulas)
available_nodes_to_sample = len(reservoir.values) + len(reservoir.reservoir)
Expand Down Expand Up @@ -244,15 +238,9 @@ def decrypt(
timeout: Optional[int] = None,
) -> DecryptOutcome:
decryption_client = ThresholdDecryptionClient(self)
if timeout and timeout > self.MAX_DECRYPTION_TIMEOUT:
self.log.warn(
f"Provided decryption timeout ({timeout}s) exceeds "
f"maximum ({self.MAX_DECRYPTION_TIMEOUT}s); "
f"using {self.MAX_DECRYPTION_TIMEOUT}s instead"
)
timeout = self.MAX_DECRYPTION_TIMEOUT
else:
timeout = timeout or self.MAX_DECRYPTION_TIMEOUT
timeout = self._configure_timeout(
"decryption", timeout, self.MAX_DECRYPTION_TIMEOUT
)

successes, failures = decryption_client.gather_encrypted_decryption_shares(
encrypted_requests=encrypted_decryption_requests,
Expand All @@ -265,6 +253,20 @@ def decrypt(
)
return decrypt_outcome

def _configure_timeout(
self, operation: str, timeout: Union[int, None], max_timeout: int
):
if timeout and timeout > max_timeout:
self.log.warn(
f"Provided {operation} timeout ({timeout}s) exceeds "
f"maximum ({max_timeout}s); "
f"using {max_timeout}s instead"
)
timeout = max_timeout
else:
timeout = timeout or max_timeout
return timeout

def _make_reservoir(
self,
exclude_ursulas: Optional[Sequence[ChecksumAddress]] = None,
Expand Down
45 changes: 45 additions & 0 deletions tests/test_porter_configure_timeout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import pytest

from porter.main import Porter


@pytest.mark.parametrize(
"provided_timeout,max_timeout,expected_timeout",
[
(None, 10, 10),
(1, 10, 1),
(5, 10, 5),
(9, 10, 9),
(10, 10, 10),
(11, 10, 10),
(20, 10, 10),
(25, 10, 10),
(
Porter.MAX_GET_URSULAS_TIMEOUT - 1,
Porter.MAX_GET_URSULAS_TIMEOUT,
Porter.MAX_GET_URSULAS_TIMEOUT - 1,
),
(
Porter.MAX_GET_URSULAS_TIMEOUT + 1,
Porter.MAX_GET_URSULAS_TIMEOUT,
Porter.MAX_GET_URSULAS_TIMEOUT,
),
(
Porter.MAX_DECRYPTION_TIMEOUT / 2,
Porter.MAX_DECRYPTION_TIMEOUT,
Porter.MAX_DECRYPTION_TIMEOUT / 2,
),
(
Porter.MAX_DECRYPTION_TIMEOUT * 2,
Porter.MAX_DECRYPTION_TIMEOUT,
Porter.MAX_DECRYPTION_TIMEOUT,
),
],
)
def test_porter_configure_timeout(
porter, provided_timeout, max_timeout, expected_timeout
):
resultant_timeout = porter._configure_timeout(
operation="test", timeout=provided_timeout, max_timeout=max_timeout
)
assert resultant_timeout == expected_timeout