The main Bubble source repository. Contains the Bubble API server, the web UI, documentation and utilities. https://getbubblenow.com
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 

235 satır
7.8 KiB

  1. #!/bin/bash
  2. #
  3. # Copyright (c) 2020 Bubble, Inc. All rights reserved. For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/
  4. #
  5. # Connect a Linux system to a Bubble
  6. #
  7. # Usage:
  8. #
  9. # bubble_linux_connect [hostname]
  10. #
  11. # hostname : hostname of the bubble to connect this Linux system to
  12. #
  13. # Environment Variables
  14. #
  15. # BUBBLE_API : which Bubble API to use. Typically this ends with /api
  16. # BUBBLE_USER : account to use
  17. # BUBBLE_PASS : password for account
  18. #
  19. # What this command does:
  20. # * Disconnects from any current Bubble
  21. # * Checks if the device already exists for the Bubble. If not, creates the device.
  22. # * Checks if we have a local copy of the certificate and vpn.conf files. If not, download them.
  23. # * Ensures routing configuration is correct
  24. # * Installs the certificate (this step requires your interaction)
  25. # * Installs the VPN config
  26. # * Starts the VPN
  27. #
  28. function die() {
  29. echo 1>&2 "$0: fatal error: ${1}"
  30. exit 1
  31. }
  32. SCRIPT_DIR="$(cd "$(dirname "${0}")" && pwd)"
  33. API_HOST="${1}"
  34. if [[ -z "${API_HOST}" ]] ; then
  35. if [[ -z "${BUBBLE_API}" ]]; then
  36. echo -n "No hostname argument provided and BUBBLE_API env var not defined. Enter Bubble hostname: "
  37. read -r API_HOST
  38. if [[ -z "${API_HOST}" ]] ; then
  39. die "Empty Bubble hostname"
  40. fi
  41. BUBBLE_API="https://${API_HOST}/api"
  42. fi
  43. else
  44. BUBBLE_API="https://${API_HOST}/api"
  45. fi
  46. if [[ -z "${BUBBLE_USER}" ]]; then
  47. echo -n "BUBBLE_USER env var not defined. Enter Bubble username: "
  48. read -r BUBBLE_USER
  49. fi
  50. if [[ -z "${BUBBLE_PASS}" ]]; then
  51. echo -n "BUBBLE_PASS env var not defined. Enter Bubble password: "
  52. read -r BUBBLE_PASS
  53. fi
  54. BUBBLE_HOST="$(echo -n "${BUBBLE_API}" | awk -F '/' '{print $3}' | awk -F ':' '{print $1}')"
  55. if [[ -z "${BUBBLE_HOST}" ]]; then
  56. die "No hostname could be determined from BUBBLE_API = ${BUBBLE_API}"
  57. fi
  58. if [[ -z "$(which wg)" ]]; then
  59. die "No wg command found - is WireGuard installed?"
  60. fi
  61. if [[ -z "$(which wg-quick)" ]]; then
  62. die "No wg-quick command found - is WireGuard installed?"
  63. fi
  64. if [[ -z "$(which bget)" ]]; then
  65. export PATH=${PATH}:${SCRIPT_DIR}
  66. if [[ -z "$(which bget)" ]]; then
  67. die "bget command not found, even after adding ${SCRIPT_DIR} to PATH"
  68. fi
  69. fi
  70. bget me || die "Error logging into Bubble with API: ${BUBBLE_API}"
  71. # Ensure WireGuard is not running
  72. if [[ ! -z "$(wg show)" ]]; then
  73. wg-quick down wg0
  74. fi
  75. BUBBLE_DEVICE_BASE="${HOME}/bubble_devices"
  76. BUBBLE_DIR="${BUBBLE_DEVICE_BASE}/${BUBBLE_HOST}"
  77. mkdir -p "${BUBBLE_DIR}" || die "Error creating directory: ${BUBBLE_DIR}"
  78. CERT_FILE="${BUBBLE_DIR}"/bubble-cert.crt
  79. VPN_FILE="${BUBBLE_DIR}"/vpn.conf
  80. DEVICE_NAME_FILE=${BUBBLE_DIR}/bubble_device_name
  81. if [[ ! -f "${DEVICE_NAME_FILE}" ]]; then
  82. DISTRO="$(cat /etc/os-release | grep ^NAME= | awk -F '=' '{print $2}' | tr -d '"')"
  83. echo -n "Linux_${DISTRO}_$(hostname -s)" >"${DEVICE_NAME_FILE}"
  84. echo "Initialized device: ${DEVICE_NAME_FILE}"
  85. fi
  86. DEVICE_NAME="$(cat "${DEVICE_NAME_FILE}")"
  87. # Check API to see if device is already registered
  88. if [[ $(bgetn me/devices | grep -c "${DEVICE_NAME}") -eq 0 ]]; then
  89. echo "Device not found, registering now: ${DEVICE_NAME}"
  90. echo "{
  91. \"name\": \"${DEVICE_NAME}\",
  92. \"deviceType\": \"Linux\"
  93. }" | bput me/devices - || die "Error creating device"
  94. rm -f "${VPN_FILE}" "${CERT_FILE}" || die "Error removing obsolete vpn.conf and cert files"
  95. else
  96. echo "Device already registered: ${DEVICE_NAME}"
  97. fi
  98. # Do we have both a cert file and a vpn.conf? If so, we are done
  99. if [[ ! -f "${CERT_FILE}" ]]; then
  100. # Download cert file
  101. echo "Downloading certificate ..."
  102. if [[ ! -f "${CERT_FILE}" ]]; then
  103. bget auth/cacert?deviceType=Linux --raw >"${CERT_FILE}" || die "Error downloading certificate file"
  104. fi
  105. fi
  106. if [[ ! -f "${VPN_FILE}" ]]; then
  107. # Download vpn.conf file
  108. echo "Downloading vpn.conf ..."
  109. if [[ ! -f "${VPN_FILE}" ]]; then
  110. bget "me/devices/${DEVICE_NAME}/vpn/vpn.conf" --raw >"${VPN_FILE}" || die "Error downloading vpn.conf file"
  111. fi
  112. fi
  113. echo "Marking ${BUBBLE_HOST} as current Bubble ..."
  114. cd "${BUBBLE_DEVICE_BASE}" && ln -sf "${BUBBLE_HOST}" current || die "Error creating symlink ${BUBBLE_DEVICE_BASE}/current -> ${BUBBLE_DEVICE_BASE}/${BUBBLE_HOST}"
  115. EXTRA_CERTS_DIR=/usr/share/ca-certificates/extra/
  116. CERT_DEST="${EXTRA_CERTS_DIR}/${CERT_FILE}"
  117. echo "Copying certificate to ${CERT_DEST} ..."
  118. sudo cp "${CERT_FILE}" "${CERT_DEST}" || die "Error copying certificate: ${CERT_FILE} -> ${CERT_DEST}"
  119. echo "
  120. ### Finishing Certificate Installation for Ubuntu
  121. We're going to run the Ubuntu certificate wizard via:
  122. sudo dpkg-reconfigure ca-certificates
  123. When the wizard opens, check the box for your Bubble certificate and press OK.
  124. To continue, press Enter
  125. "
  126. read -r DUMMY
  127. sudo dpkg-reconfigure ca-certificates || die "Error reconfiguring system CA certificates"
  128. # Ensure ssh route table exists
  129. if [[ $(cat /etc/iproute2/rt_tables | grep -c ssh) -eq 0 ]] ; then
  130. sudo echo "2 ssh" >> /etc/iproute2/rt_tables
  131. else
  132. echo "ssh table already exists in rt_tables"
  133. fi
  134. REBOOT_FILE=/tmp/reboot-required.bubble
  135. # Set sysctl vars
  136. SYSCTL="/etc/sysctl.conf"
  137. SYS_RP_FILTER="net.ipv4.conf.all.rp_filter"
  138. if [[ $(cat ${SYSCTL} | grep -v '^#' | grep -c "${SYS_RP_FILTER}") -eq 0 ]] ; then
  139. echo "${SYS_RP_FILTER} = 2" >> ${SYSCTL}
  140. touch ${REBOOT_FILE}
  141. else
  142. echo "${SYS_RP_FILTER} already defined in ${SYSCTL}"
  143. fi
  144. SYS_IP_FORWARD="net.ipv4.ip_forward"
  145. if [[ $(cat ${SYSCTL} | grep -v '^#' | grep -c "${SYS_IP_FORWARD}") -eq 0 ]] ; then
  146. echo "${SYS_IP_FORWARD} = 1" >> ${SYSCTL}
  147. touch ${REBOOT_FILE}
  148. else
  149. echo "${SYS_IP_FORWARD} already defined in ${SYSCTL}"
  150. fi
  151. WG_CONF=/etc/wireguard/wg0.conf
  152. echo "Copying vpn.conf to ${WG_CONF} ..."
  153. sudo cp "${VPN_FILE}" ${WG_CONF} || die "Error copying vpn.conf: ${VPN_FILE} -> ${WG_CONF}"
  154. if [[ $(sudo cat "${WG_CONF}" | grep -c PostUp) -ne 0 ]] ; then
  155. echo "${WG_CONF} already contains PostUp directives"
  156. else
  157. GATEWAY=$(route -n | grep "^0.0.0.0" | awk '{print $2}')
  158. if [[ -z "${GATEWAY}" ]] ; then
  159. die "Error determining gateway IP using 'route -n'"
  160. fi
  161. IFACE=$(route -n | grep "^0.0.0.0" | awk '{print $8}')
  162. if [[ -z "${IFACE}" ]] ; then
  163. die "Error determining gateway interface using 'route -n'"
  164. fi
  165. WG_TEMP=$(mktemp /tmp/wg.conf.XXXXXXX)
  166. cat ${WG_CONF} | grep -A 3 '\[Interface\]' >> "${WG_TEMP}"
  167. echo "PostUp = ip route add default via ${GATEWAY} dev ${IFACE} table ssh
  168. PostUp = ip rule add fwmark 0x2 table ssh
  169. PostUp = /sbin/iptables -A OUTPUT -t mangle -o wg0 -p tcp --sport 22 -j MARK --set-mark 2
  170. PreDown = /sbin/iptables -D OUTPUT -t mangle -o wg0 -p tcp --sport 22 -j MARK --set-mark 2
  171. PreDown = ip rule del fwmark 0x2 table ssh
  172. PreDown = ip route del default via ${GATEWAY} dev ${IFACE} table ssh
  173. " >> "${WG_TEMP}"
  174. cat ${WG_CONF} | grep -A 10 '\[Peer\]' >> "${WG_TEMP}"
  175. mv "${WG_TEMP}" ${WG_CONF} || die "Error installing updated ${WG_CONF} file"
  176. fi
  177. echo "Starting WireGuard VPN ..."
  178. sudo wg-quick up wg0 || die "Error starting WireGuard"
  179. echo "
  180. ======= Linux device successfully connected to Bubble! =======
  181. Device Name : ${DEVICE_NAME}
  182. Bubble Host : ${BUBBLE_HOST}
  183. Certificate : ${CERT_FILE} - installed: ${CERT_DEST}
  184. VPN Config : ${VPN_FILE} - configured and installed: ${WG_CONF}
  185. "
  186. if [[ ! -z "$(which firefox)" ]] ; then
  187. echo "
  188. ###### WARNING: Firefox will not properly connect to most websites until you install
  189. the Bubble certificate in Firefox
  190. To install the Bubble Certificate in Firefox:
  191. * Open Firefox
  192. * In the search box (top right of page), enter \"certificate\"
  193. * Scroll down, click \"View Certificates\" button
  194. * Click \"Import\" button
  195. * Select your certificate file: ${CERT_FILE}
  196. * Check the box \"Trust this CA to identify websites\" and click OK.
  197. More detailed instructions, with screenshots, can be found here:
  198. https://git.bubblev.org/bubblev/bubble-docs/src/branch/master/cert_instructions/firefox_cert.md"
  199. fi