mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-16 07:16:38 +00:00
407 lines
10 KiB
Bash
Executable File
407 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -e
|
|
|
|
# NetBird Getting Started with Embedded IdP (Dex)
|
|
# This script sets up NetBird with the embedded Dex identity provider
|
|
# No separate Dex container or reverse proxy needed - IdP is built into management server
|
|
|
|
# Sed pattern to strip base64 padding characters
|
|
SED_STRIP_PADDING='s/=//g'
|
|
|
|
check_docker_compose() {
|
|
if command -v docker-compose &> /dev/null
|
|
then
|
|
echo "docker-compose"
|
|
return
|
|
fi
|
|
if docker compose --help &> /dev/null
|
|
then
|
|
echo "docker compose"
|
|
return
|
|
fi
|
|
|
|
echo "docker-compose is not installed or not in PATH. Please follow the steps from the official guide: https://docs.docker.com/engine/install/" > /dev/stderr
|
|
exit 1
|
|
}
|
|
|
|
check_jq() {
|
|
if ! command -v jq &> /dev/null
|
|
then
|
|
echo "jq is not installed or not in PATH, please install with your package manager. e.g. sudo apt install jq" > /dev/stderr
|
|
exit 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
get_main_ip_address() {
|
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
interface=$(route -n get default | grep 'interface:' | awk '{print $2}')
|
|
ip_address=$(ifconfig "$interface" | grep 'inet ' | awk '{print $2}')
|
|
else
|
|
interface=$(ip route | grep default | awk '{print $5}' | head -n 1)
|
|
ip_address=$(ip addr show "$interface" | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1)
|
|
fi
|
|
|
|
echo "$ip_address"
|
|
return 0
|
|
}
|
|
|
|
check_nb_domain() {
|
|
DOMAIN=$1
|
|
if [[ "$DOMAIN-x" == "-x" ]]; then
|
|
echo "The NETBIRD_DOMAIN variable cannot be empty." > /dev/stderr
|
|
return 1
|
|
fi
|
|
|
|
if [[ "$DOMAIN" == "netbird.example.com" ]]; then
|
|
echo "The NETBIRD_DOMAIN cannot be netbird.example.com" > /dev/stderr
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
read_nb_domain() {
|
|
READ_NETBIRD_DOMAIN=""
|
|
echo -n "Enter the domain you want to use for NetBird (e.g. netbird.my-domain.com): " > /dev/stderr
|
|
read -r READ_NETBIRD_DOMAIN < /dev/tty
|
|
if ! check_nb_domain "$READ_NETBIRD_DOMAIN"; then
|
|
read_nb_domain
|
|
fi
|
|
echo "$READ_NETBIRD_DOMAIN"
|
|
return 0
|
|
}
|
|
|
|
get_turn_external_ip() {
|
|
TURN_EXTERNAL_IP_CONFIG="#external-ip="
|
|
IP=$(curl -s -4 https://jsonip.com | jq -r '.ip')
|
|
if [[ "x-$IP" != "x-" ]]; then
|
|
TURN_EXTERNAL_IP_CONFIG="external-ip=$IP"
|
|
fi
|
|
echo "$TURN_EXTERNAL_IP_CONFIG"
|
|
return 0
|
|
}
|
|
|
|
wait_management() {
|
|
set +e
|
|
echo -n "Waiting for Management server to become ready"
|
|
counter=1
|
|
while true; do
|
|
# Check the embedded IdP endpoint
|
|
if curl -sk -f -o /dev/null "$NETBIRD_HTTP_PROTOCOL://$NETBIRD_DOMAIN/oauth2/.well-known/openid-configuration" 2>/dev/null; then
|
|
break
|
|
fi
|
|
if [[ $counter -eq 60 ]]; then
|
|
echo ""
|
|
echo "Taking too long. Checking logs..."
|
|
$DOCKER_COMPOSE_COMMAND logs --tail=20 caddy
|
|
$DOCKER_COMPOSE_COMMAND logs --tail=20 management
|
|
fi
|
|
echo -n " ."
|
|
sleep 2
|
|
counter=$((counter + 1))
|
|
done
|
|
echo " done"
|
|
set -e
|
|
return 0
|
|
}
|
|
|
|
init_environment() {
|
|
CADDY_SECURE_DOMAIN=""
|
|
NETBIRD_PORT=80
|
|
NETBIRD_HTTP_PROTOCOL="http"
|
|
NETBIRD_RELAY_PROTO="rel"
|
|
TURN_USER="self"
|
|
TURN_PASSWORD=$(openssl rand -base64 32 | sed "$SED_STRIP_PADDING")
|
|
NETBIRD_RELAY_AUTH_SECRET=$(openssl rand -base64 32 | sed "$SED_STRIP_PADDING")
|
|
# Note: DataStoreEncryptionKey must keep base64 padding (=) for Go's base64.StdEncoding
|
|
DATASTORE_ENCRYPTION_KEY=$(openssl rand -base64 32)
|
|
TURN_MIN_PORT=49152
|
|
TURN_MAX_PORT=65535
|
|
TURN_EXTERNAL_IP_CONFIG=$(get_turn_external_ip)
|
|
|
|
if ! check_nb_domain "$NETBIRD_DOMAIN"; then
|
|
NETBIRD_DOMAIN=$(read_nb_domain)
|
|
fi
|
|
|
|
if [[ "$NETBIRD_DOMAIN" == "use-ip" ]]; then
|
|
NETBIRD_DOMAIN=$(get_main_ip_address)
|
|
else
|
|
NETBIRD_PORT=443
|
|
CADDY_SECURE_DOMAIN=", $NETBIRD_DOMAIN:$NETBIRD_PORT"
|
|
NETBIRD_HTTP_PROTOCOL="https"
|
|
NETBIRD_RELAY_PROTO="rels"
|
|
fi
|
|
|
|
check_jq
|
|
|
|
DOCKER_COMPOSE_COMMAND=$(check_docker_compose)
|
|
|
|
if [[ -f management.json ]]; then
|
|
echo "Generated files already exist, if you want to reinitialize the environment, please remove them first."
|
|
echo "You can use the following commands:"
|
|
echo " $DOCKER_COMPOSE_COMMAND down --volumes # to remove all containers and volumes"
|
|
echo " rm -f docker-compose.yml Caddyfile dashboard.env turnserver.conf management.json relay.env"
|
|
echo "Be aware that this will remove all data from the database, and you will have to reconfigure the dashboard."
|
|
exit 1
|
|
fi
|
|
|
|
echo Rendering initial files...
|
|
render_docker_compose > docker-compose.yml
|
|
render_caddyfile > Caddyfile
|
|
render_dashboard_env > dashboard.env
|
|
render_management_json > management.json
|
|
render_turn_server_conf > turnserver.conf
|
|
render_relay_env > relay.env
|
|
|
|
echo -e "\nStarting NetBird services\n"
|
|
$DOCKER_COMPOSE_COMMAND up -d
|
|
|
|
# Wait for management (and embedded IdP) to be ready
|
|
sleep 3
|
|
wait_management
|
|
|
|
echo -e "\nDone!\n"
|
|
echo "You can access the NetBird dashboard at $NETBIRD_HTTP_PROTOCOL://$NETBIRD_DOMAIN"
|
|
echo "Follow the onboarding steps to set up your NetBird instance."
|
|
return 0
|
|
}
|
|
|
|
render_caddyfile() {
|
|
cat <<EOF
|
|
{
|
|
servers :80,:443 {
|
|
protocols h1 h2c h2 h3
|
|
}
|
|
}
|
|
|
|
(security_headers) {
|
|
header * {
|
|
Strict-Transport-Security "max-age=3600; includeSubDomains; preload"
|
|
X-Content-Type-Options "nosniff"
|
|
X-Frame-Options "SAMEORIGIN"
|
|
X-XSS-Protection "1; mode=block"
|
|
-Server
|
|
Referrer-Policy strict-origin-when-cross-origin
|
|
}
|
|
}
|
|
|
|
:80${CADDY_SECURE_DOMAIN} {
|
|
import security_headers
|
|
# relay
|
|
reverse_proxy /relay* relay:80
|
|
# Signal
|
|
reverse_proxy /ws-proxy/signal* signal:80
|
|
reverse_proxy /signalexchange.SignalExchange/* h2c://signal:10000
|
|
# Management
|
|
reverse_proxy /api/* management:80
|
|
reverse_proxy /ws-proxy/management* management:80
|
|
reverse_proxy /management.ManagementService/* h2c://management:80
|
|
reverse_proxy /oauth2/* management:80
|
|
# Dashboard
|
|
reverse_proxy /* dashboard:80
|
|
}
|
|
EOF
|
|
return 0
|
|
}
|
|
|
|
render_turn_server_conf() {
|
|
cat <<EOF
|
|
listening-port=3478
|
|
$TURN_EXTERNAL_IP_CONFIG
|
|
tls-listening-port=5349
|
|
min-port=$TURN_MIN_PORT
|
|
max-port=$TURN_MAX_PORT
|
|
fingerprint
|
|
lt-cred-mech
|
|
user=$TURN_USER:$TURN_PASSWORD
|
|
realm=wiretrustee.com
|
|
cert=/etc/coturn/certs/cert.pem
|
|
pkey=/etc/coturn/private/privkey.pem
|
|
log-file=stdout
|
|
no-software-attribute
|
|
pidfile="/var/tmp/turnserver.pid"
|
|
no-cli
|
|
EOF
|
|
return 0
|
|
}
|
|
|
|
render_management_json() {
|
|
cat <<EOF
|
|
{
|
|
"Stuns": [
|
|
{
|
|
"Proto": "udp",
|
|
"URI": "stun:$NETBIRD_DOMAIN:3478"
|
|
}
|
|
],
|
|
"Relay": {
|
|
"Addresses": ["$NETBIRD_RELAY_PROTO://$NETBIRD_DOMAIN:$NETBIRD_PORT"],
|
|
"CredentialsTTL": "24h",
|
|
"Secret": "$NETBIRD_RELAY_AUTH_SECRET"
|
|
},
|
|
"Signal": {
|
|
"Proto": "$NETBIRD_HTTP_PROTOCOL",
|
|
"URI": "$NETBIRD_DOMAIN:$NETBIRD_PORT"
|
|
},
|
|
"Datadir": "/var/lib/netbird",
|
|
"DataStoreEncryptionKey": "$DATASTORE_ENCRYPTION_KEY",
|
|
"EmbeddedIdP": {
|
|
"Enabled": true,
|
|
"Issuer": "$NETBIRD_HTTP_PROTOCOL://$NETBIRD_DOMAIN/oauth2",
|
|
"DashboardRedirectURIs": [
|
|
"$NETBIRD_HTTP_PROTOCOL://$NETBIRD_DOMAIN/nb-auth",
|
|
"$NETBIRD_HTTP_PROTOCOL://$NETBIRD_DOMAIN/nb-silent-auth"
|
|
]
|
|
}
|
|
}
|
|
EOF
|
|
return 0
|
|
}
|
|
|
|
render_dashboard_env() {
|
|
cat <<EOF
|
|
# Endpoints
|
|
NETBIRD_MGMT_API_ENDPOINT=$NETBIRD_HTTP_PROTOCOL://$NETBIRD_DOMAIN
|
|
NETBIRD_MGMT_GRPC_API_ENDPOINT=$NETBIRD_HTTP_PROTOCOL://$NETBIRD_DOMAIN
|
|
# OIDC - using embedded IdP
|
|
AUTH_AUDIENCE=netbird-dashboard
|
|
AUTH_CLIENT_ID=netbird-dashboard
|
|
AUTH_CLIENT_SECRET=
|
|
AUTH_AUTHORITY=$NETBIRD_HTTP_PROTOCOL://$NETBIRD_DOMAIN/oauth2
|
|
USE_AUTH0=false
|
|
AUTH_SUPPORTED_SCOPES=openid profile email offline_access
|
|
AUTH_REDIRECT_URI=/nb-auth
|
|
AUTH_SILENT_REDIRECT_URI=/nb-silent-auth
|
|
# SSL
|
|
NGINX_SSL_PORT=443
|
|
# Letsencrypt
|
|
LETSENCRYPT_DOMAIN=none
|
|
EOF
|
|
return 0
|
|
}
|
|
|
|
render_relay_env() {
|
|
cat <<EOF
|
|
NB_LOG_LEVEL=info
|
|
NB_LISTEN_ADDRESS=:80
|
|
NB_EXPOSED_ADDRESS=$NETBIRD_RELAY_PROTO://$NETBIRD_DOMAIN:$NETBIRD_PORT
|
|
NB_AUTH_SECRET=$NETBIRD_RELAY_AUTH_SECRET
|
|
EOF
|
|
return 0
|
|
}
|
|
|
|
render_docker_compose() {
|
|
cat <<EOF
|
|
services:
|
|
# Caddy reverse proxy
|
|
caddy:
|
|
image: caddy
|
|
container_name: netbird-caddy
|
|
restart: unless-stopped
|
|
networks: [netbird]
|
|
ports:
|
|
- '443:443'
|
|
- '443:443/udp'
|
|
- '80:80'
|
|
volumes:
|
|
- netbird_caddy_data:/data
|
|
- ./Caddyfile:/etc/caddy/Caddyfile
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "500m"
|
|
max-file: "2"
|
|
|
|
# UI dashboard
|
|
dashboard:
|
|
image: netbirdio/dashboard:latest
|
|
container_name: netbird-dashboard
|
|
restart: unless-stopped
|
|
networks: [netbird]
|
|
env_file:
|
|
- ./dashboard.env
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "500m"
|
|
max-file: "2"
|
|
|
|
# Signal
|
|
signal:
|
|
image: netbirdio/signal:latest
|
|
container_name: netbird-signal
|
|
restart: unless-stopped
|
|
networks: [netbird]
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "500m"
|
|
max-file: "2"
|
|
|
|
# Relay
|
|
relay:
|
|
image: netbirdio/relay:latest
|
|
container_name: netbird-relay
|
|
restart: unless-stopped
|
|
networks: [netbird]
|
|
env_file:
|
|
- ./relay.env
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "500m"
|
|
max-file: "2"
|
|
|
|
# Management (includes embedded IdP)
|
|
management:
|
|
image: netbirdio/management:latest
|
|
container_name: netbird-management
|
|
restart: unless-stopped
|
|
networks: [netbird]
|
|
volumes:
|
|
- netbird_management:/var/lib/netbird
|
|
- ./management.json:/etc/netbird/management.json
|
|
command: [
|
|
"--port", "80",
|
|
"--log-file", "console",
|
|
"--log-level", "info",
|
|
"--disable-anonymous-metrics=false",
|
|
"--single-account-mode-domain=netbird.selfhosted",
|
|
"--dns-domain=netbird.selfhosted",
|
|
"--idp-sign-key-refresh-enabled",
|
|
]
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "500m"
|
|
max-file: "2"
|
|
|
|
# Coturn, AKA TURN server
|
|
coturn:
|
|
image: coturn/coturn
|
|
container_name: netbird-coturn
|
|
restart: unless-stopped
|
|
volumes:
|
|
- ./turnserver.conf:/etc/turnserver.conf:ro
|
|
network_mode: host
|
|
command:
|
|
- -c /etc/turnserver.conf
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "500m"
|
|
max-file: "2"
|
|
|
|
volumes:
|
|
netbird_caddy_data:
|
|
netbird_management:
|
|
|
|
networks:
|
|
netbird:
|
|
EOF
|
|
return 0
|
|
}
|
|
|
|
init_environment
|