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

Restrict internet access from siren container #286

Open
wants to merge 20 commits into
base: stable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a39f264
Restrict egress on siren container
magick93 Dec 13, 2024
fc6ae1a
siren container w/ no internet
magick93 Dec 15, 2024
ff3abc8
Enhance security and stability of docker-compose configuration
magick93 Dec 15, 2024
7a111b0
Update docker-compose to include BN_TARGET and VC_TARGET environment …
magick93 Dec 15, 2024
f032c1e
Update nginx proxy configuration to use BN_TARGET and VC_TARGET varia…
magick93 Dec 15, 2024
d0b9b21
Remove non-root user configuration from nginx-proxy service in docker…
magick93 Dec 15, 2024
e61f51f
Refactor nginx proxy configuration to use upstream blocks for BN_TARG…
magick93 Dec 15, 2024
e15cf87
Update nginx proxy configuration file path in docker-compose
magick93 Dec 16, 2024
3d22810
Update BN_TARGET and VC_TARGET environment variables to use placehold…
magick93 Dec 16, 2024
0fa9a88
Update README to include BN_TARGET and VC_TARGET configuration instru…
magick93 Dec 16, 2024
910e64e
Update docker-compose to configure SSL and use environment variables …
magick93 Dec 16, 2024
45b78c5
Update README to remove outdated BN_TARGET and VC_TARGET configuratio…
magick93 Dec 16, 2024
69224d1
switch to alpine-based nginx container
antondlr Dec 16, 2024
efef6d5
dont expose port 80, containers in same network can access regardless
antondlr Dec 16, 2024
104f010
update ssl config
antondlr Dec 16, 2024
58757e3
Update README to reflect correct URL
magick93 Dec 16, 2024
190ecd6
[Alpine] Change command in docker-compose to use /bin/sh instead of /…
magick93 Dec 16, 2024
40ef91e
Add DNS resolver configuration for beacon node and validator client p…
magick93 Dec 16, 2024
c9b515f
Add SSL certificate generation and update docker-compose for cert-ini…
magick93 Dec 18, 2024
01dd140
Update README with Docker Compose usage instructions and SSL access n…
magick93 Dec 18, 2024
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ certs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
/.yarn

build-storybook.log

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ RUN rm /etc/nginx/sites-enabled/default; \

COPY --from=intermediate /app /app/

ENTRYPOINT /app/docker-assets/docker-entrypoint.sh
ENTRYPOINT ["/app/docker-assets/docker-entrypoint.sh"]
44 changes: 38 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,49 @@ developers. Specifically the [Lighthouse UI](https://lighthouse-book.sigmaprime.

Docker is the recommended way to run Siren. This will expose Siren as a webapp.

Configuration is done through environment variables, the best way to get started is by copying `.env.example` to `.env` and editing the relevant sections (typically, this would at least include `BEACON_URL`, `VALIDATOR_URL` and `API_TOKEN`)
Configuration is done through environment variables, the best way to get started is by copying `.env.example` to `.env` and editing the relevant sections (typically, this would at least include `BEACON_URL`, `VALIDATOR_URL` and `API_TOKEN`).

Then to run the image:
#### Starting Siren with Docker Compose

`docker compose up`
or
1. Copy the environment file:
```bash
cp .env.example .env
```

2. Edit `.env` with your configuration (at minimum set `BEACON_URL`, `VALIDATOR_URL`, and `API_TOKEN`)

3. Start the services:
```bash
docker compose up -d
```
The `-d` flag runs the containers in the background. Remove it if you want to see the logs directly in your terminal.

4. Access Siren at https://localhost:4443

Note: When you first visit the site, your browser will show a security warning because Siren uses a self-signed SSL certificate. This is expected and safe for local development. You can proceed by:
- In Chrome: Click "Advanced" and then "Proceed to localhost (unsafe)"
- In Firefox: Click "Advanced..." and then "Accept the Risk and Continue"
- In Safari: Click "Show Details" and then "visit this website"

#### Stopping Siren

To stop the services:
```bash
docker compose down
```

To stop and remove all data (including certificates):
```bash
docker compose down -v
```

#### Alternative Docker Run Method

You can also run Siren using the docker run command:
`docker run --rm -ti --name siren -p 3443:443 --env-file $PWD/.env sigp/siren`

This will open port 3443 and allow your browser to connect.


To start Siren, visit `https://localhost:3443` in your web browser (ignore the certificate warning).

Advanced users can mount their own certificate (the config expects 3 files: `/certs/cert.pem` `/certs/key.pem` `/certs/key.pass`)
Expand All @@ -56,4 +88,4 @@ Navigate to the backend directory `cd backend`. Install all required Node packag
#### Build and run the frontend
After initializing the backend, return to the root directory. Install all frontend dependencies by executing `yarn`. Build the frontend using `yarn build`. Start the frontend production server with `yarn start`.

This will allow you to access siren at `http://localhost:3000` by default.
This will allow you to access siren at `http://localhost:3000` by default.
17 changes: 17 additions & 0 deletions docker-assets/generate-certs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh
set -e

# Create directory for certificates if it doesn't exist
mkdir -p /etc/nginx/certs

# Generate self-signed certificate and private key
openssl req -x509 -nodes -days 365 -newkey rsa:4096 \
-keyout /etc/nginx/certs/nginx.key \
-out /etc/nginx/certs/nginx.crt \
-subj "/C=AU/CN=siren/[email protected]"

# Set proper permissions
chmod 600 /etc/nginx/certs/nginx.key
chmod 644 /etc/nginx/certs/nginx.crt

echo "SSL certificates generated successfully"
93 changes: 93 additions & 0 deletions docker-assets/nginx_proxy.conf.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
user nginx;
worker_processes 8;

error_log /dev/stdout warn;
pid /var/run/nginx.pid;

events {
worker_connections 1024;
}

# HTTP configuration for Siren web interface
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;
access_log /dev/stdout main;

sendfile on;
keepalive_timeout 65;

# Resolve DNS for upstreams
resolver 127.0.0.11 ipv6=off;

# Siren web interface proxy
server {
listen 4080;
server_name localhost;

location / {
set $upstream_siren siren;
proxy_pass http://$upstream_siren:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300;
proxy_connect_timeout 300;
}
}
}

# TCP proxy configuration for beacon/validator
stream {
log_format main '$remote_addr - [$time_local] ';
access_log /var/log/nginx/access.log main;
access_log /dev/stdout main;

# Split BN_TARGET into host and port using shell parameter expansion
upstream beacon_node {
server ${BN_TARGET};
}

# Split VC_TARGET into host and port using shell parameter expansion
upstream validator_client {
server ${VC_TARGET};
}

# Beacon Node proxy
server {
listen 9001;
# Resolve DNS for upstreams
resolver 127.0.0.11;

# Proxy pass to the beacon node
proxy_pass beacon_node;
magick93 marked this conversation as resolved.
Show resolved Hide resolved
}

# Validator Client proxy
server {
listen 9002;
# Resolve DNS for upstreams
resolver 127.0.0.11;

# Proxy pass to the validator client
proxy_pass validator_client;
}

# Block all other outbound connections
server {
listen 80;
return 444; # Connection closed without response
}

server {
listen 443;
return 444; # Connection closed without response
}
}
18 changes: 18 additions & 0 deletions docker-assets/ssl-conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
ssl on;
ssl_session_timeout 5m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;

ssl_dhparam /etc/ssl/private/dhparam2048.pem;

# Enable HSTS (17280000s = 200 days)
add_header Strict-Transport-Security max-age=17280000;

# Enable OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.4.4;

# Enable SSL session cache
ssl_session_cache shared:SSL:10m;
82 changes: 76 additions & 6 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,81 @@
services:
cert-init:
container_name: cert-init
image: alpine/openssl:3.3.2
command: /usr/local/bin/generate-certs.sh
volumes:
- ./docker-assets/generate-certs.sh:/usr/local/bin/generate-certs.sh
- nginx-certs:/etc/nginx/certs
entrypoint: >
/bin/sh -c "
# Make script executable
chmod +x /usr/local/bin/generate-certs.sh &&
# Run script
/usr/local/bin/generate-certs.sh
"

nginx-proxy:
container_name: nginx-proxy
image: nginx:alpine
networks:
- internet
- no_internet
ports:
- "4080:4080" # For Siren web interface HTTP
- "4443:4443" # For Siren web interface HTTPS (fixed port mapping)
volumes:
- ./docker-assets/nginx_proxy.conf.template:/etc/nginx/nginx.conf.template:ro
- nginx-certs:/etc/nginx/certs:ro
command: /bin/sh -c "export BN_TARGET=$(echo $BEACON_URL | awk -F'[/:]' '{print $4 \":\" $5}') && export VC_TARGET=$(echo $VALIDATOR_URL | awk -F'[/:]' '{print $4 \":\" $5}') && envsubst '$$BN_TARGET $$VC_TARGET $$SIREN_HOST' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf && nginx -g 'daemon off;'"
env_file:
- .env
depends_on:
cert-init:
condition: service_completed_successfully
restart: unless-stopped # Don't restart if manually stopped

siren:
container_name: siren
image: sigp/siren
ports:
- "4443:443" # comment this line when using `SSL_ENABLED=false`
# - "4080:80" # uncomment this line when using `SSL_ENABLED=false`
networks:
- no_internet # Only on internal network
env_file:
- .env
# uncomment these 2 lines if you use docker on linux and want to use the special host `host.docker.internal` as your BN/VC address
# extra_hosts:
# - "host.docker.internal:host-gateway"
tmpfs:
- /tmp:noexec,nosuid # Mount tmp with restricted permissions
- /run:noexec,nosuid # Required for nginx pid file
environment:
- NODE_ENV=production
- BEACON_URL=http://nginx-proxy:9001
- VALIDATOR_URL=http://nginx-proxy:9002
- SSL_ENABLED=true
- PORT=3000
- BACKEND_URL=http://127.0.0.1:3001
# Security enhancements
security_opt:
- no-new-privileges:true # Prevent privilege escalation
depends_on:
- nginx-proxy
healthcheck: # Add health monitoring
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
restart: unless-stopped # Don't restart if manually stopped

networks:
internet:
name: internet
driver: bridge
no_internet:
name: no_internet
driver: bridge
internal: true # Prevents direct internet access
# Enable network encryption
driver_opts:
encrypted: "true"

volumes:
nginx-certs:
driver: local