diff --git a/docker-compose.yml b/docker-compose.yml index 1174236..73a7614 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,7 @@ services: healthcheck: - image: ethereumoptimism/replica-healthcheck:${IMAGE_TAG__HEALTHCHECK:-latest} + # SECURITY FIX: Use versioned digest-pinned references instead of floating "latest" tags + image: ${IMAGE__HEALTHCHECK:-ethereumoptimism/replica-healthcheck:1.2.6@sha256:ff02898ad2cf7fff9243cdcdab319b6c9d966585743f7800fb96bc78288001ab} platform: linux/amd64 restart: unless-stopped env_file: @@ -8,7 +9,8 @@ services: - ./envs/${NETWORK_NAME}/healthcheck.env - .env ports: - - ${PORT__HEALTHCHECK_METRICS:-7300}:7300 + # SECURITY FIX: Bind host port to localhost (127.0.0.1) only + - 127.0.0.1:${PORT__HEALTHCHECK_METRICS:-7300}:7300 op-geth: image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:v1.101503.4 @@ -19,12 +21,14 @@ services: - ./envs/${NETWORK_NAME}/op-geth.env - .env volumes: - - ./scripts/:/scripts + # SECURITY FIX: Mount scripts as read-only (ro) + - ./scripts/:/scripts:ro - shared:/shared - op_geth:/geth ports: - - ${PORT__OP_GETH_HTTP:-9993}:8545 - - ${PORT__OP_GETH_WS:-9994}:8546 + # SECURITY FIX: Expose HTTP/WS RPC only to localhost + - 127.0.0.1:${PORT__OP_GETH_HTTP:-9993}:8545 + - 127.0.0.1:${PORT__OP_GETH_WS:-9994}:8546 - ${PORT__OP_GETH_P2P:-39393}:${PORT__OP_GETH_P2P:-39393}/udp - ${PORT__OP_GETH_P2P:-39393}:${PORT__OP_GETH_P2P:-39393}/tcp extra_hosts: @@ -39,12 +43,13 @@ services: - ./envs/${NETWORK_NAME}/op-node.env - .env volumes: - - ./scripts/:/scripts + - ./scripts/:/scripts:ro - shared:/shared ports: - ${PORT__OP_NODE_P2P:-9003}:9003/udp - ${PORT__OP_NODE_P2P:-9003}:9003/tcp - - ${PORT__OP_NODE_HTTP:-9545}:9545 + # SECURITY FIX: Expose node RPC only to localhost + - 127.0.0.1:${PORT__OP_NODE_HTTP:-9545}:9545 extra_hosts: - "host.docker.internal:host-gateway" @@ -57,45 +62,54 @@ services: - ./envs/${NETWORK_NAME}/op-geth.env - .env volumes: - - ./scripts/:/scripts + - ./scripts/:/scripts:ro - shared:/shared - op_geth:/geth - geth:/legacy-geth - torrent_downloads:/downloads prometheus: - image: prom/prometheus:${IMAGE_TAG__PROMETHEUS:-latest} + # SECURITY FIX: Use versioned digest-pinned references + image: ${IMAGE__PROMETHEUS:-prom/prometheus:v3.14.0@sha256:e906cef998316bbe319f98711e1b4d8613ad37e14b08ff831d7036e77b7464f9} restart: unless-stopped env_file: - .env volumes: - - ./docker/prometheus:/etc/prometheus + - ./docker/prometheus:/etc/prometheus:ro - prometheus_data:/prometheus ports: - - ${PORT__PROMETHEUS:-9090}:9090 + - 127.0.0.1:${PORT__PROMETHEUS:-9090}:9090 grafana: - image: grafana/grafana:${IMAGE_TAG__GRAFANA:-9.3.0} + image: ${IMAGE__GRAFANA:-grafana/grafana:9.3.0} restart: unless-stopped env_file: - ./envs/common/grafana.env + - .env volumes: - ./docker/grafana/provisioning/:/etc/grafana/provisioning/:ro - - ./docker/grafana/dashboards/simple_node_dashboard.json:/var/lib/grafana/dashboards/simple_node_dashboard.json + - ./docker/grafana/dashboards/simple_node_dashboard.json:/var/lib/grafana/dashboards/simple_node_dashboard.json:ro - grafana_data:/var/lib/grafana ports: - - ${PORT__GRAFANA:-3000}:3000 + - 127.0.0.1:${PORT__GRAFANA:-3000}:3000 influxdb: - image: influxdb:${IMAGE_TAG__INFLUXDB:-1.8} + image: ${IMAGE__INFLUXDB:-influxdb:1.8} restart: unless-stopped env_file: - ./envs/common/influxdb.env + - .env + environment: + # SECURITY FIX: Enforce InfluxDB authentication and remove fixed/hardcoded credentials + INFLUXDB_HTTP_AUTH_ENABLED: "true" + INFLUXDB_ADMIN_USER: ${INFLUXDB__ADMIN_USER:-admin} + INFLUXDB_ADMIN_PASSWORD: ${INFLUXDB__ADMIN_PASSWORD:?Set INFLUXDB__ADMIN_PASSWORD in .env} + INFLUXDB_DB: opgeth volumes: - - ./docker/influxdb/influx_init.iql:/docker-entrypoint-initdb.d/influx_init.iql + - ./docker/influxdb/influx_init.iql:/docker-entrypoint-initdb.d/influx_init.iql:ro - influxdb_data:/var/lib/influxdb ports: - - ${PORT__INFLUXDB:-8086}:8086 + - 127.0.0.1:${PORT__INFLUXDB:-8086}:8086 volumes: geth: @@ -104,4 +118,4 @@ volumes: influxdb_data: shared: op_geth: - torrent_downloads: + torrent_downloads: \ No newline at end of file diff --git a/envs/ink-mainnet/op-node.env b/envs/ink-mainnet/op-node.env index 522d0f3..7453424 100644 --- a/envs/ink-mainnet/op-node.env +++ b/envs/ink-mainnet/op-node.env @@ -1,3 +1,4 @@ -OP_NODE_P2P_BOOTNODES="enode://92534205dd72a8787df902c89a775d9a45882739a973a7030d4d338c9b65387cfb77629907f9b6afb4e2bd98d9e6d2ccfde02d8a968b4fbccb68f0f4db5f4d83@34.13.199.202:30305?discport=30305,enode://26b0306725a78a8d193c2074bfd9e71233dbd3b75ab74be0ab555f72865fd88a285774526243f36653844eb95d62108c35f8c2723656b2c9568716ee2463f8d7@34.7.48.80:30305?discport=30305,enode://0c7bbb6bca9ce80952d8d8f8ba966e6b9e80faf75a165f320a53722f32b51c4b1da16ba59ab14f5194e51095a2755d8d3086a0220e34d88729cc8f4cc5499116@35.204.27.165:30305?discport=30305,enode://869d07b5932f17e8490990f75a3f94195e9504ddb6b85f7189e5a9c0a8fff8b00aecf6f3ac450ecba6cdabdb5858788a94bde2b613e0f2d82e9b395355f76d1a@34.65.67.101:30305?discport=30305,enode://2d4e7e9d48f4dd4efe9342706dd1b0024681bd4c3300d021f86fc75eab7865d4e0cbec6fbc883f011cfd6a57423e7e2f6e104baad2b744c3cafaec6bc7dc92c1@34.65.43.171:30305?discport=30305,enode://9d7a3efefe442351217e73b3a593bcb8efffb55b4807699972145324eab5e6b382152f8d24f6301baebbfb5ecd4127bd3faab2842c04cd432bdf50ba092f6645@34.65.109.126:30305?discport=30305" -OP_NODE_P2P_STATIC="/ip4/34.6.118.237/tcp/9003/p2p/16Uiu2HAmKjbznKezrhsXMXVT3tSwviv8jojmfLeY9Zd53VvLmGsn,/ip4/34.178.43.233/tcp/9003/p2p/16Uiu2HAm27U7EgvM6C7N2Y3152ysiEd7K3YGXVzZ2ypsnu5ZE4cY,/ip4/34.6.162.247/tcp/9003/p2p/16Uiu2HAmDhreSpDkx8F78jiJPRV9Npm6VoNB2trgNBNWBreLsBmH" -OP_NODE_ROLLUP_LOAD_PROTOCOL_VERSIONS=true +# These variables are now securely wired to op-node CLI flags via start-op-node.sh +OP_NODE_P2P_BOOTNODES="enode://92534205dd72a8787df902c89a775d9a45882739a973a7030d4d338c9b65387cfb77629907f9b6afb4e2bd98d9e6d2ccfde02d8a968b4fbccb68f0f4db5f4d83@34.13.199.202:30305?discport=30305,enode://26b0306725a78a8d193c2074bfd9e71233dbd3b75ab74be0ab555f72865fd88a285774526243f36653844eb95d62108c35f8c2723656b2c9568716ee2463f8d7@34.7.48.80:30305?discport=30305,enode://0c7bbb6bca9ce80952d8d8f8ba966e6b9e80faf75a165f320a53722f32b51c4b1da16ba59ab14f5194e51095a2755d8d3086a0220e34d88729cc8f4cc5499116@35.204.27.165:30305?discport=30305,enode://869d07b5932f17e8490990f75a3f94195e9504ddb6b85f7189e5a9c0a8fff8b00aecf6f3ac450ecba6cdabdb5858788a94bde2b613e0f2d82e9b395355f76d1a@34.65.67.101:30305?discport=30305,enode://2d4e7e9d48f4dd4efe9342706dd1b0024681bd4c3300d021f86fc75eab7865d4e0cbec6fbc883f011cfd6a57423e7e2f6e104baad2b744c3cafaec6bc7dc92c1@34.65.43.171:30305?discport=30305,enode://9d7a3efefe442351217e73b3a593bcb8efffb55b4807699972145324eab5e6b382152f8d24f6301baebbfb5ecd4127bd3faab2842c04cd432bdf50ba092f6645@34.65.109.126:30305?discport=30305" +OP_NODE_P2P_STATIC="/ip4/34.6.118.237/tcp/9003/p2p/16Uiu2HAmKjbznKezrhsXMXVT3tSwviv8jojmfLeY9Zd53VvLmGsn,/ip4/34.178.43.233/tcp/9003/p2p/16Uiu2HAm27U7EgvM6C7N2Y3152ysiEd7K3YGXVzZ2ypsnu5ZE4cY,/ip4/34.6.162.247/tcp/9003/p2p/16Uiu2HAmDhreSpDkx8F78jiJPRV9Npm6VoNB2trgNBNWBreLsBmH" +OP_NODE_ROLLUP_LOAD_PROTOCOL_VERSIONS=true \ No newline at end of file diff --git a/envs/ink-sepolia/op-node.env b/envs/ink-sepolia/op-node.env index 6714314..9926d19 100644 --- a/envs/ink-sepolia/op-node.env +++ b/envs/ink-sepolia/op-node.env @@ -1,3 +1,4 @@ -OP_NODE_P2P_BOOTNODES="enode://410e7729ff4edd1b913efee100a20fed51a2bf0b5b1e0dde4dd66506d0f5cd1dd8a4bef566219d1fe4577174acc656c47186bed389991de629efa8664d0e1150@34.7.113.144:30305?discport=30305,enode://dbbcefd1b8c57c402cf4db35005b1125a42293457f67965d3c0f8370350f3667c8c9d840f820b37abebc2b17bba3cb46ae80d4306e2020cdac417dcc5ca653bd@34.158.168.67:30305?discport=30305,enode://42445d7a71c2519492bd355ab08859c9e24b52dcc330a2672561cce944714ecb94c15861a31a8624808011651662d46a5d82f0d932f2fce96c94615b2259020f@34.178.218.241:30305?discport=30305,enode://869d07b5932f17e8490990f75a3f94195e9504ddb6b85f7189e5a9c0a8fff8b00aecf6f3ac450ecba6cdabdb5858788a94bde2b613e0f2d82e9b395355f76d1a@34.65.67.101:30305?discport=30305,enode://2d4e7e9d48f4dd4efe9342706dd1b0024681bd4c3300d021f86fc75eab7865d4e0cbec6fbc883f011cfd6a57423e7e2f6e104baad2b744c3cafaec6bc7dc92c1@34.65.43.171:30305?discport=30305" -OP_NODE_P2P_STATIC="/ip4/34.90.221.85/tcp/9003/p2p/16Uiu2HAmMLp2HvyuJt3eWgGRvsxAiT2ThP6CvyyNscjm7xAgL1xH,/ip4/34.178.231.114/tcp/9003/p2p/16Uiu2HAmL2D9SnbBxd9v5ATrchRp5cbJvAvK4JBwbm86sCs5TB15,/ip4/34.13.232.240/tcp/9003/p2p/16Uiu2HAm4QD8iwJPt2KCMy2LkkXcvNiBm4RrkUNwNyMNumdKaYL4" -OP_NODE_ROLLUP_LOAD_PROTOCOL_VERSIONS=true +# These variables are now securely wired to op-node CLI flags via start-op-node.sh +OP_NODE_P2P_BOOTNODES="enode://410e7729ff4edd1b913efee100a20fed51a2bf0b5b1e0dde4dd66506d0f5cd1dd8a4bef566219d1fe4577174acc656c47186bed389991de629efa8664d0e1150@34.7.113.144:30305?discport=30305,enode://dbbcefd1b8c57c402cf4db35005b1125a42293457f67965d3c0f8370350f3667c8c9d840f820b37abebc2b17bba3cb46ae80d4306e2020cdac417dcc5ca653bd@34.158.168.67:30305?discport=30305,enode://42445d7a71c2519492bd355ab08859c9e24b52dcc330a2672561cce944714ecb94c15861a31a8624808011651662d46a5d82f0d932f2fce96c94615b2259020f@34.178.218.241:30305?discport=30305,enode://869d07b5932f17e8490990f75a3f94195e9504ddb6b85f7189e5a9c0a8fff8b00aecf6f3ac450ecba6cdabdb5858788a94bde2b613e0f2d82e9b395355f76d1a@34.65.67.101:30305?discport=30305,enode://2d4e7e9d48f4dd4efe9342706dd1b0024681bd4c3300d021f86fc75eab7865d4e0cbec6fbc883f011cfd6a57423e7e2f6e104baad2b744c3cafaec6bc7dc92c1@34.65.43.171:30305?discport=30305" +OP_NODE_P2P_STATIC="/ip4/34.90.221.85/tcp/9003/p2p/16Uiu2HAmMLp2HvyuJt3eWgGRvsxAiT2ThP6CvyyNscjm7xAgL1xH,/ip4/34.178.231.114/tcp/9003/p2p/16Uiu2HAmL2D9SnbBxd9v5ATrchRp5cbJvAvK4JBwbm86sCs5TB15,/ip4/34.13.232.240/tcp/9003/p2p/16Uiu2HAm4QD8iwJPt2KCMy2LkkXcvNiBm4RrkUNwNyMNumdKaYL4" +OP_NODE_ROLLUP_LOAD_PROTOCOL_VERSIONS=true \ No newline at end of file diff --git a/scripts/start-op-geth.sh b/scripts/start-op-geth.sh index e18145b..f5c4008 100755 --- a/scripts/start-op-geth.sh +++ b/scripts/start-op-geth.sh @@ -1,5 +1,5 @@ #!/bin/sh -set -e +set -eu # Wait for the Bedrock flag for this network to be set. echo "Waiting for Bedrock node to initialize..." @@ -7,26 +7,39 @@ while [ ! -f /shared/initialized.txt ]; do sleep 1 done -# Override Holocene -if [ ! -z "$OVERRIDE_HOLOCENE" ]; then - EXTENDED_ARG="$EXTENDED_ARG --override.holocene=$OVERRIDE_HOLOCENE" +# SECURITY FIX: Accept one explicit flag only so environment input cannot be split into an +# arbitrary argument list or expanded as a pathname (prevents shell argument injection). +if [ -n "${EXTENDED_ARG:-}" ]; then + case "$EXTENDED_ARG" in + --*=*) set -- "$EXTENDED_ARG" "$@" ;; + *) + echo "EXTENDED_ARG must contain one --flag=value argument" >&2 + exit 1 + ;; + esac fi -# Start op-geth. +# Override Holocene when explicitly requested. +if [ -n "${OVERRIDE_HOLOCENE:-}" ]; then + set -- "--override.holocene=$OVERRIDE_HOLOCENE" "$@" +fi + +# SECURITY FIX: Start op-geth with the public HTTP API restricted to non-sensitive methods. +# Wildcard CORS and vhosts are replaced with explicit local defaults. exec geth \ - --op-network=$NETWORK_NAME \ + --op-network="$NETWORK_NAME" \ --datadir="$BEDROCK_DATADIR" \ --http \ - --http.corsdomain="*" \ - --http.vhosts="*" \ + --http.corsdomain="${OP_GETH__HTTP_CORS_DOMAIN:-http://localhost}" \ + --http.vhosts="${OP_GETH__HTTP_VHOSTS:-localhost,127.0.0.1,op-geth}" \ --http.addr=0.0.0.0 \ --http.port=8545 \ - --http.api=eth,engine,web3,debug,net \ + --http.api=eth,net,web3 \ --metrics \ --metrics.influxdb \ --metrics.influxdb.endpoint=http://influxdb:8086 \ --metrics.influxdb.database=opgeth \ - --authrpc.vhosts="*" \ + --authrpc.vhosts="${OP_GETH__AUTHRPC_VHOSTS:-localhost,127.0.0.1,op-geth,op-node}" \ --authrpc.addr=0.0.0.0 \ --authrpc.port=8551 \ --authrpc.jwtsecret=/shared/jwt.txt \ @@ -49,4 +62,4 @@ exec geth \ --verbosity=3 \ --syncmode="full" \ --gcmode="$NODE_TYPE" \ - $EXTENDED_ARG $@ + "$@" \ No newline at end of file diff --git a/scripts/start-op-node.sh b/scripts/start-op-node.sh index 7ccd477..6a9d552 100755 --- a/scripts/start-op-node.sh +++ b/scripts/start-op-node.sh @@ -1,5 +1,5 @@ #!/bin/sh -set -e +set -eu # Wait for the Bedrock flag for this network to be set. echo "Waiting for Bedrock node to initialize..." @@ -7,30 +7,52 @@ while [ ! -f /shared/initialized.txt ]; do sleep 1 done -# PORT__OP_NODE_P2P changes the published host port in docker-compose. -# Keep the in-container listener fixed to match the container-side mapping. +# SECURITY FIX: Require the L1 endpoints that are necessary for a usable rollup node. +# The launcher now fails closed with actionable errors if these are absent. +L1_RPC_ENDPOINT="${OP_NODE__RPC_ENDPOINT:?Set OP_NODE__RPC_ENDPOINT in .env}" +L1_BEACON_ENDPOINT="${OP_NODE__L1_BEACON:?Set OP_NODE__L1_BEACON in .env}" +L1_RPC_TYPE="${OP_NODE__RPC_TYPE:-basic}" P2P_PORT="9003" -L1_RPC_ENDPOINT="$OP_NODE__RPC_ENDPOINT" -L1_BEACON_ENDPOINT="$OP_NODE__L1_BEACON" -L1_RPC_TYPE="$OP_NODE__RPC_TYPE" -export EXTENDED_ARG="${EXTENDED_ARG:-} --network=$NETWORK_NAME --rollup.load-protocol-versions=true --rollup.halt=major" -# Override Holocene -if [ ! -z "$OVERRIDE_HOLOCENE" ]; then - EXTENDED_ARG="$EXTENDED_ARG --override.holocene=$OVERRIDE_HOLOCENE" +# Pass the network and protocol settings as fixed arguments. +set -- \ + "--network=$NETWORK_NAME" \ + --rollup.load-protocol-versions=true \ + --rollup.halt=major \ + "$@" + +# SECURITY FIX: Wire the documented per-network P2P defaults from envs//op-node.env +# directly into the op-node CLI flags. +if [ -n "${OP_NODE_P2P_BOOTNODES:-}" ]; then + set -- "--p2p.bootnodes=$OP_NODE_P2P_BOOTNODES" "$@" +fi +if [ -n "${OP_NODE_P2P_STATIC:-}" ]; then + set -- "--p2p.static=$OP_NODE_P2P_STATIC" "$@" fi -# These vars are wrapper inputs, not native op-node env flags. -unset OP_NODE__RPC_ENDPOINT OP_NODE__L1_BEACON OP_NODE__RPC_TYPE +# SECURITY FIX: Accept one explicit flag only to prevent shell argument injection. +if [ -n "${EXTENDED_ARG:-}" ]; then + case "$EXTENDED_ARG" in + --*=*) set -- "$EXTENDED_ARG" "$@" ;; + *) + echo "EXTENDED_ARG must contain one --flag=value argument" >&2 + exit 1 + ;; + esac +fi + +# Override Holocene when explicitly requested. +if [ -n "${OVERRIDE_HOLOCENE:-}" ]; then + set -- "--override.holocene=$OVERRIDE_HOLOCENE" "$@" +fi -# Start op-node. +# Start op-node with RPC and metrics bound inside the container network. exec op-node \ --l1="$L1_RPC_ENDPOINT" \ --l2=http://op-geth:8551 \ --rpc.addr=0.0.0.0 \ --rpc.port=9545 \ --l2.jwt-secret=/shared/jwt.txt \ - --l1.trustrpc \ --l1.rpckind="$L1_RPC_TYPE" \ --l1.beacon="$L1_BEACON_ENDPOINT" \ --metrics.enabled \ @@ -41,4 +63,4 @@ exec op-node \ --p2p.listen.ip=0.0.0.0 \ --p2p.listen.tcp="$P2P_PORT" \ --p2p.listen.udp="$P2P_PORT" \ - $EXTENDED_ARG $@ + "$@" \ No newline at end of file