Skip to content

Commit

Permalink
feat: add support for remote signers - use_remote_signer (ethpandao…
Browse files Browse the repository at this point in the history
…ps#791)

Adds the `use_remote_signer` flag, outsourcing validator key management
to a remote signer, which validator clients connect to.

Supported by all VCs except Lighthouse through this PR.

Slashing protection DB is not enabled for web3signer since that would
require adding significantly more complexity - creating a separate
postgres DB and running migrations.

I was thinking a lot what to call the remote signer service, in the end
went with `signer-1-geth-lodestar` (this is the remote signer for
`vc-1-geth-lodestar`).

Addresses ethpandaops#263 / ethpandaops#758 

Prerequisite for adding [Vero](https://github.com/serenita-org/vero) as
a validator client - it exclusively uses a remote signer

---------

Co-authored-by: Barnabas Busa <[email protected]>
  • Loading branch information
eth2353 and barnabasbusa authored Oct 7, 2024
1 parent 12b787d commit 9f1b6e9
Show file tree
Hide file tree
Showing 19 changed files with 530 additions and 20 deletions.
5 changes: 4 additions & 1 deletion .github/tests/mix-public.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ port_publisher:
vc:
enabled: true
public_port_start: 34000
additional_services:
remote_signer:
enabled: true
public_port_start: 35000
additional_services:
enabled: true
public_port_start: 36000
23 changes: 23 additions & 0 deletions .github/tests/remote-signer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
participants:
- el_type: geth
cl_type: lodestar
use_separate_vc: true
use_remote_signer: true
- el_type: geth
cl_type: nimbus
use_separate_vc: true
use_remote_signer: true
- el_type: geth
cl_type: prysm
use_separate_vc: true
use_remote_signer: true
- el_type: geth
cl_type: teku
use_separate_vc: true
use_remote_signer: true
- el_type: geth
cl_type: grandine
use_separate_vc: true
use_remote_signer: true
# Grandine doesn't have a separate VC
vc_type: lodestar
62 changes: 57 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ participants:
# Defaults to 1
vc_count: 1

# The log level string that this participant's CL client should log at
# The log level string that this participant's validator client should log at
# If this is emptystring then the global `logLevel` parameter's value will be translated into a string appropriate for the client (e.g. if
# global `logLevel` = `info` then Teku would receive `INFO`, Prysm would receive `info`, etc.)
# If this is not emptystring, then this value will override the global `logLevel` setting to allow for fine-grained control
Expand All @@ -324,11 +324,11 @@ participants:
# A list of optional extra env_vars the vc container should spin up with
vc_extra_env_vars: {}

# A list of optional extra labels that will be passed to the CL client validator container.
# A list of optional extra labels that will be passed to the validator client validator container.
# Example; vc_extra_labels: {"ethereum-package.partition": "1"}
vc_extra_labels: {}

# A list of optional extra params that will be passed to the CL client validator container for modifying its behaviour
# A list of optional extra params that will be passed to the validator client container for modifying its behaviour
# If the client combines the Beacon & validator nodes (e.g. Teku, Nimbus), then this list will also be passed to the combined Beacon-validator node
vc_extra_params: []

Expand Down Expand Up @@ -357,6 +357,51 @@ participants:
# network parameter num_validator_keys_per_node
validator_count: null

# Whether to use a remote signer instead of the vc directly handling keys
# Note Lighthouse VC does not support this flag
# Defaults to false
use_remote_signer: false

# Remote signer Specific flags
# The type of remote signer that should be used
# Valid values are web3signer
# Defaults to web3signer
remote_signer_type: "web3signer"

# The Docker image that should be used for the remote signer
# Defaults to "consensys/web3signer:latest"
remote_signer_image: "consensys/web3signer:latest"

# A list of optional extra env_vars the remote signer container should spin up with
remote_signer_extra_env_vars: {}

# A list of optional extra labels that will be passed to the remote signer container.
# Example; remote_signer_extra_labels: {"ethereum-package.partition": "1"}
remote_signer_extra_labels: {}

# A list of optional extra params that will be passed to the remote signer container for modifying its behaviour
remote_signer_extra_params: []

# A list of tolerations that will be passed to the remote signer container
# Only works with Kubernetes
# Example: remote_signer_tolerations:
# - key: "key"
# operator: "Equal"
# value: "value"
# effect: "NoSchedule"
# toleration_seconds: 3600
# Defaults to empty
remote_signer_tolerations: []

# Resource management for remote signer containers
# CPU is milicores
# RAM is in MB
# Defaults to 0, which results in no resource limits
remote_signer_min_cpu: 0
remote_signer_max_cpu: 0
remote_signer_min_mem: 0
remote_signer_max_mem: 0

# Participant specific flags
# Node selector
# Only works with Kubernetes
Expand Down Expand Up @@ -862,13 +907,20 @@ port_publisher:
vc:
enabled: false
public_port_start: 34000
# Additional services public port exposed to your local machine
# remote signer public port exposed to your local machine
# Disabled by default
# Public port start defaults to 35000
# You can't run multiple enclaves on the same port settings
additional_services:
remote_signer:
enabled: false
public_port_start: 35000
# Additional services public port exposed to your local machine
# Disabled by default
# Public port start defaults to 36000
# You can't run multiple enclaves on the same port settings
additional_services:
enabled: false
public_port_start: 36000
```
#### Example configurations
Expand Down
3 changes: 3 additions & 0 deletions main.star
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,14 @@ def run(plan, args={}):
all_el_contexts = []
all_cl_contexts = []
all_vc_contexts = []
all_remote_signer_contexts = []
all_ethereum_metrics_exporter_contexts = []
all_xatu_sentry_contexts = []
for participant in all_participants:
all_el_contexts.append(participant.el_context)
all_cl_contexts.append(participant.cl_context)
all_vc_contexts.append(participant.vc_context)
all_remote_signer_contexts.append(participant.remote_signer_context)
all_ethereum_metrics_exporter_contexts.append(
participant.ethereum_metrics_exporter_context
)
Expand Down Expand Up @@ -634,6 +636,7 @@ def run(plan, args={}):
all_el_contexts,
all_cl_contexts,
all_vc_contexts,
all_remote_signer_contexts,
prometheus_additional_metrics_jobs,
all_ethereum_metrics_exporter_contexts,
all_xatu_sentry_contexts,
Expand Down
17 changes: 16 additions & 1 deletion network_params.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ participants:
vc_min_mem: 0
vc_max_mem: 0
validator_count: null
use_remote_signer: false
# Remote signer
remote_signer_type: web3signer
remote_signer_image: consensys/web3signer:latest
remote_signer_extra_env_vars: {}
remote_signer_extra_labels: {}
remote_signer_extra_params: []
remote_signer_tolerations: []
remote_signer_min_cpu: 0
remote_signer_max_cpu: 0
remote_signer_min_mem: 0
remote_signer_max_mem: 0
# participant specific
node_selectors: {}
tolerations: []
Expand Down Expand Up @@ -174,6 +186,9 @@ port_publisher:
vc:
enabled: false
public_port_start: 34000
additional_services:
remote_signer:
enabled: false
public_port_start: 35000
additional_services:
enabled: false
public_port_start: 36000
3 changes: 3 additions & 0 deletions src/package_io/constants.star
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ VC_TYPE = struct(
teku="teku",
)

REMOTE_SIGNER_TYPE = struct(web3signer="web3signer")

GLOBAL_LOG_LEVEL = struct(
info="info",
error="error",
Expand All @@ -38,6 +40,7 @@ CLIENT_TYPES = struct(
el="execution",
cl="beacon",
validator="validator",
remote_signer="remote-signer",
)

TCP_DISCOVERY_PORT_ID = "tcp-discovery"
Expand Down
49 changes: 48 additions & 1 deletion src/package_io/input_parser.star
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ DEFAULT_VC_IMAGES_MINIMAL = {
"grandine": "ethpandaops/grandine:master-minimal",
}

DEFAULT_REMOTE_SIGNER_IMAGES = {
"web3signer": "consensys/web3signer:latest",
}

# Placeholder value for the deneb fork epoch if electra is being run
# TODO: This is a hack, and should be removed once we electra is rebased on deneb
HIGH_DENEB_VALUE_FORK_VERKLE = 2000000000
Expand Down Expand Up @@ -213,6 +217,15 @@ def input_parser(plan, input_args):
vc_extra_params=participant["vc_extra_params"],
vc_extra_env_vars=participant["vc_extra_env_vars"],
vc_extra_labels=participant["vc_extra_labels"],
use_remote_signer=participant["use_remote_signer"],
remote_signer_type=participant["remote_signer_type"],
remote_signer_image=participant["remote_signer_image"],
remote_signer_tolerations=participant["remote_signer_tolerations"],
remote_signer_extra_env_vars=participant[
"remote_signer_extra_env_vars"
],
remote_signer_extra_params=participant["remote_signer_extra_params"],
remote_signer_extra_labels=participant["remote_signer_extra_labels"],
builder_network_params=participant["builder_network_params"],
supernode=participant["supernode"],
el_min_cpu=participant["el_min_cpu"],
Expand All @@ -227,6 +240,10 @@ def input_parser(plan, input_args):
vc_max_cpu=participant["vc_max_cpu"],
vc_min_mem=participant["vc_min_mem"],
vc_max_mem=participant["vc_max_mem"],
remote_signer_min_cpu=participant["remote_signer_min_cpu"],
remote_signer_max_cpu=participant["remote_signer_max_cpu"],
remote_signer_min_mem=participant["remote_signer_min_mem"],
remote_signer_max_mem=participant["remote_signer_max_mem"],
validator_count=participant["validator_count"],
tolerations=participant["tolerations"],
node_selectors=participant["node_selectors"],
Expand Down Expand Up @@ -397,6 +414,10 @@ def input_parser(plan, input_args):
el_public_port_start=result["port_publisher"]["el"]["public_port_start"],
vc_enabled=result["port_publisher"]["vc"]["enabled"],
vc_public_port_start=result["port_publisher"]["vc"]["public_port_start"],
remote_signer_enabled=result["port_publisher"]["remote_signer"]["enabled"],
remote_signer_public_port_start=result["port_publisher"]["remote_signer"][
"public_port_start"
],
additional_services_enabled=result["port_publisher"]["additional_services"][
"enabled"
],
Expand Down Expand Up @@ -473,6 +494,7 @@ def parse_network_params(plan, input_args):
el_type = participant["el_type"]
cl_type = participant["cl_type"]
vc_type = participant["vc_type"]
remote_signer_type = participant["remote_signer_type"]

if (
cl_type in (constants.CL_TYPE.nimbus)
Expand Down Expand Up @@ -537,6 +559,9 @@ def parse_network_params(plan, input_args):
else:
participant["use_separate_vc"] = True

if participant["use_remote_signer"] and not participant["use_separate_vc"]:
fail("`use_remote_signer` requires `use_separate_vc`")

if vc_type == "":
# Defaults to matching the chosen CL client
vc_type = cl_type
Expand Down Expand Up @@ -567,6 +592,12 @@ def parse_network_params(plan, input_args):
)
participant["vc_image"] = default_image

remote_signer_image = participant["remote_signer_image"]
if remote_signer_image == "":
participant["remote_signer_image"] = DEFAULT_REMOTE_SIGNER_IMAGES.get(
remote_signer_type, ""
)

if result["parallel_keystore_generation"] and participant["vc_count"] != 1:
fail(
"parallel_keystore_generation is only supported for 1 validator client per participant (for now)"
Expand Down Expand Up @@ -635,6 +666,9 @@ def parse_network_params(plan, input_args):
vc_extra_params = participant.get("vc_extra_params", [])
participant["vc_extra_params"] = vc_extra_params

remote_signer_extra_params = participant.get("remote_signer_extra_params", [])
participant["remote_signer_extra_params"] = remote_signer_extra_params

total_participant_count += participant["count"]

if total_participant_count == 1:
Expand Down Expand Up @@ -784,6 +818,7 @@ def default_input_args(input_args):
"apache_port": None,
"global_tolerations": [],
"global_node_selectors": {},
"use_remote_signer": False,
"keymanager_enabled": False,
"checkpoint_sync_enabled": False,
"checkpoint_sync_url": "",
Expand Down Expand Up @@ -902,6 +937,17 @@ def default_participant():
"vc_max_cpu": 0,
"vc_min_mem": 0,
"vc_max_mem": 0,
"use_remote_signer": None,
"remote_signer_type": "web3signer",
"remote_signer_image": "",
"remote_signer_extra_env_vars": {},
"remote_signer_extra_labels": {},
"remote_signer_extra_params": [],
"remote_signer_tolerations": [],
"remote_signer_min_cpu": 0,
"remote_signer_max_cpu": 0,
"remote_signer_min_mem": 0,
"remote_signer_max_mem": 0,
"validator_count": None,
"node_selectors": {},
"tolerations": [],
Expand Down Expand Up @@ -1061,7 +1107,8 @@ def get_port_publisher_params(parameter_type, input_args=None):
"el": {"enabled": False, "public_port_start": 32000},
"cl": {"enabled": False, "public_port_start": 33000},
"vc": {"enabled": False, "public_port_start": 34000},
"additional_services": {"enabled": False, "public_port_start": 35000},
"remote_signer": {"enabled": False, "public_port_start": 35000},
"additional_services": {"enabled": False, "public_port_start": 36000},
}
if parameter_type == "default":
return port_publisher_parameters
Expand Down
24 changes: 24 additions & 0 deletions src/package_io/sanity_check.star
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ PARTICIPANT_CATEGORIES = {
"vc_min_mem",
"vc_max_mem",
"validator_count",
"use_remote_signer",
"remote_signer_type",
"remote_signer_image",
"remote_signer_extra_env_vars",
"remote_signer_extra_labels",
"remote_signer_extra_params",
"remote_signer_tolerations",
"remote_signer_min_cpu",
"remote_signer_max_cpu",
"remote_signer_min_mem",
"remote_signer_max_mem",
"node_selectors",
"tolerations",
"count",
Expand Down Expand Up @@ -110,6 +121,18 @@ PARTICIPANT_MATRIX_PARAMS = {
"vc_min_mem",
"vc_max_mem",
],
"remote_signer": [
"remote_signer_type",
"remote_signer_image",
"remote_signer_extra_env_vars",
"remote_signer_extra_labels",
"remote_signer_extra_params",
"remote_signer_tolerations",
"remote_signer_min_cpu",
"remote_signer_max_cpu",
"remote_signer_min_mem",
"remote_signer_max_mem",
],
},
}

Expand Down Expand Up @@ -208,6 +231,7 @@ SUBCATEGORY_PARAMS = {
"el",
"cl",
"vc",
"remote_signer",
"additional_services",
],
}
Expand Down
4 changes: 4 additions & 0 deletions src/participant.star
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ def new_participant(
el_type,
cl_type,
vc_type,
remote_signer_type,
el_context,
cl_context,
vc_context,
remote_signer_context,
snooper_engine_context,
snooper_beacon_context,
ethereum_metrics_exporter_context,
Expand All @@ -14,9 +16,11 @@ def new_participant(
el_type=el_type,
cl_type=cl_type,
vc_type=vc_type,
remote_signer_type=remote_signer_type,
el_context=el_context,
cl_context=cl_context,
vc_context=vc_context,
remote_signer_context=remote_signer_context,
snooper_engine_context=snooper_engine_context,
snooper_beacon_context=snooper_beacon_context,
ethereum_metrics_exporter_context=ethereum_metrics_exporter_context,
Expand Down
Loading

0 comments on commit 9f1b6e9

Please sign in to comment.