vpn.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. //go:generate go-bindata -pkg bindata -o bindata/bindata.go template/
  2. //go:generate protoc -I pb/ pb/user.proto pb/vpn.proto --go_out=plugins=grpc:pb
  3. package ovpm
  4. import (
  5. "bytes"
  6. "fmt"
  7. "math/big"
  8. "os"
  9. "os/exec"
  10. "strings"
  11. "text/template"
  12. "time"
  13. "github.com/Sirupsen/logrus"
  14. "github.com/asaskevich/govalidator"
  15. "github.com/cad/ovpm/bindata"
  16. "github.com/cad/ovpm/pki"
  17. "github.com/cad/ovpm/supervisor"
  18. "github.com/google/uuid"
  19. "github.com/jinzhu/gorm"
  20. )
  21. // DBNetwork is database model for external networks on the VPN server.
  22. type DBNetwork struct {
  23. gorm.Model
  24. ServerID uint
  25. Server DBServer
  26. Name string
  27. NetworkCIDR string
  28. }
  29. // DBServer is database model for storing VPN server related stuff.
  30. type DBServer struct {
  31. gorm.Model
  32. Name string `gorm:"unique_index"` // Server name.
  33. SerialNumber string
  34. Hostname string // Server's ip address or FQDN
  35. Port string // Server's listening port
  36. Cert string // Server RSA certificate.
  37. Key string // Server RSA private key.
  38. CACert string // Root CA RSA certificate.
  39. CAKey string // Root CA RSA key.
  40. Net string // VPN network.
  41. Mask string // VPN network mask.
  42. CRL string // Certificate Revocation List
  43. }
  44. // CheckSerial takes a serial number and checks it against the current server's serial number.
  45. func (s *DBServer) CheckSerial(serial string) bool {
  46. return serial == s.SerialNumber
  47. }
  48. type _VPNServerConfig struct {
  49. CertPath string
  50. KeyPath string
  51. CACertPath string
  52. CAKeyPath string
  53. CCDPath string
  54. CRLPath string
  55. DHParamsPath string
  56. Net string
  57. Mask string
  58. Port string
  59. }
  60. // Init regenerates keys and certs for a Root CA, and saves them in the database.
  61. func Init(hostname string, port string) error {
  62. if port == "" {
  63. port = DefaultVPNPort
  64. }
  65. if !govalidator.IsNumeric(port) {
  66. return fmt.Errorf("validation error: port:`%s` should be numeric", port)
  67. }
  68. serverName := "default"
  69. if IsInitialized() {
  70. if err := Deinit(); err != nil {
  71. logrus.Errorf("server can not be deleted: %v", err)
  72. return err
  73. }
  74. }
  75. if !govalidator.IsHost(hostname) {
  76. return fmt.Errorf("validation error: hostname:`%s` should be either an ip address or a FQDN", hostname)
  77. }
  78. ca, err := pki.NewCA()
  79. if err != nil {
  80. return fmt.Errorf("can not create ca creds: %s", err)
  81. }
  82. srv, err := pki.NewServerCertHolder(ca)
  83. if err != nil {
  84. return fmt.Errorf("can not create server cert creds: %s", err)
  85. }
  86. serialNumber := uuid.New().String()
  87. serverInstance := DBServer{
  88. Name: serverName,
  89. SerialNumber: serialNumber,
  90. Hostname: hostname,
  91. Port: port,
  92. Cert: srv.Cert,
  93. Key: srv.Key,
  94. CACert: ca.Cert,
  95. CAKey: ca.Key,
  96. Net: _DefaultServerNetwork,
  97. Mask: _DefaultServerNetMask,
  98. }
  99. db.Create(&serverInstance)
  100. if db.NewRecord(&serverInstance) {
  101. return fmt.Errorf("can not create server instance on database")
  102. }
  103. users, err := GetAllUsers()
  104. if err != nil {
  105. return err
  106. }
  107. // Sign all users in the db with the new server
  108. for _, user := range users {
  109. err := user.Renew()
  110. logrus.Infof("user certificate changed for %s, you should run: $ ovpm user export-config --user %s", user.Username, user.Username)
  111. if err != nil {
  112. logrus.Errorf("can not sign user %s: %v", user.Username, err)
  113. continue
  114. }
  115. }
  116. Emit()
  117. logrus.Infof("server initialized")
  118. return nil
  119. }
  120. // Deinit deletes the server with the given serverName from the database and frees the allocated resources.
  121. func Deinit() error {
  122. if !IsInitialized() {
  123. return fmt.Errorf("server not found")
  124. }
  125. db.Unscoped().Delete(&DBServer{})
  126. db.Unscoped().Delete(&DBRevoked{})
  127. Emit()
  128. return nil
  129. }
  130. // DumpsClientConfig generates .ovpn file for the given vpn user and returns it as a string.
  131. func DumpsClientConfig(username string) (string, error) {
  132. var result bytes.Buffer
  133. user, err := GetUser(username)
  134. if err != nil {
  135. return "", err
  136. }
  137. server, err := GetServerInstance()
  138. if err != nil {
  139. return "", err
  140. }
  141. params := struct {
  142. Hostname string
  143. Port string
  144. CA string
  145. Key string
  146. Cert string
  147. }{
  148. Hostname: server.Hostname,
  149. Port: server.Port,
  150. CA: server.CACert,
  151. Key: user.Key,
  152. Cert: user.Cert,
  153. }
  154. data, err := bindata.Asset("template/client.ovpn.tmpl")
  155. if err != nil {
  156. return "", err
  157. }
  158. t, err := template.New("client.ovpn").Parse(string(data))
  159. if err != nil {
  160. return "", fmt.Errorf("can not parse client.ovpn.tmpl template: %s", err)
  161. }
  162. err = t.Execute(&result, params)
  163. if err != nil {
  164. return "", fmt.Errorf("can not render client.ovpn: %s", err)
  165. }
  166. return result.String(), nil
  167. }
  168. // DumpClientConfig generates .ovpn file for the given vpn user and dumps it to outPath.
  169. func DumpClientConfig(username, path string) error {
  170. result, err := DumpsClientConfig(username)
  171. if err != nil {
  172. return err
  173. }
  174. // Wite rendered content into openvpn server conf.
  175. return emitToFile(path, result, 0)
  176. }
  177. // GetSystemCA returns the system CA from the database if available.
  178. func GetSystemCA() (*pki.CA, error) {
  179. server := DBServer{}
  180. db.First(&server)
  181. if db.NewRecord(&server) {
  182. return nil, fmt.Errorf("server record does not exists in db")
  183. }
  184. return &pki.CA{
  185. CertHolder: pki.CertHolder{
  186. Cert: server.CACert,
  187. Key: server.CAKey,
  188. },
  189. }, nil
  190. }
  191. // vpnProc represents the OpenVPN process that is managed by the ovpm supervisor globally OpenVPN.
  192. var vpnProc supervisor.Supervisable
  193. // StartVPNProc starts the OpenVPN process.
  194. func StartVPNProc() {
  195. if !IsInitialized() {
  196. logrus.Error("can not launch OpenVPN because system is not initialized")
  197. return
  198. }
  199. if vpnProc == nil {
  200. panic(fmt.Sprintf("vpnProc is not initialized!"))
  201. }
  202. if vpnProc.Status() == supervisor.RUNNING {
  203. logrus.Error("OpenVPN is already started")
  204. return
  205. }
  206. vpnProc.Start()
  207. ensureNatEnabled()
  208. }
  209. // RestartVPNProc restarts the OpenVPN process.
  210. func RestartVPNProc() {
  211. if !IsInitialized() {
  212. logrus.Error("can not launch OpenVPN because system is not initialized")
  213. return
  214. }
  215. if vpnProc == nil {
  216. panic(fmt.Sprintf("vpnProc is not initialized!"))
  217. }
  218. vpnProc.Restart()
  219. }
  220. // StopVPNProc stops the OpenVPN process.
  221. func StopVPNProc() {
  222. if vpnProc == nil {
  223. panic(fmt.Sprintf("vpnProc is not initialized!"))
  224. }
  225. if vpnProc.Status() != supervisor.RUNNING {
  226. logrus.Error("OpenVPN is already not running")
  227. return
  228. }
  229. vpnProc.Stop()
  230. }
  231. // Emit generates all needed files for the OpenVPN server and dumps them to their corresponding paths defined in the config.
  232. func Emit() error {
  233. // Check dependencies
  234. if !checkOpenVPNExecutable() {
  235. return fmt.Errorf("openvpn executable can not be found! you should install OpenVPN on this machine")
  236. }
  237. if !checkOpenSSLExecutable() {
  238. return fmt.Errorf("openssl executable can not be found! you should install openssl on this machine")
  239. }
  240. if !checkIptablesExecutable() {
  241. return fmt.Errorf("iptables executable can not be found")
  242. }
  243. if !IsInitialized() {
  244. return fmt.Errorf("you should create a server first. e.g. $ ovpm vpn create-server")
  245. }
  246. if err := emitServerConf(); err != nil {
  247. return fmt.Errorf("can not emit server conf: %s", err)
  248. }
  249. if err := emitServerCert(); err != nil {
  250. return fmt.Errorf("can not emit server cert: %s", err)
  251. }
  252. if err := emitServerKey(); err != nil {
  253. return fmt.Errorf("can not emit server key: %s", err)
  254. }
  255. if err := emitCACert(); err != nil {
  256. return fmt.Errorf("can not emit ca cert : %s", err)
  257. }
  258. if err := emitCAKey(); err != nil {
  259. return fmt.Errorf("can not emit ca key: %s", err)
  260. }
  261. if err := emitDHParams(); err != nil {
  262. return fmt.Errorf("can not emit dhparams: %s", err)
  263. }
  264. if err := emitCCD(); err != nil {
  265. return fmt.Errorf("can not emit ccd: %s", err)
  266. }
  267. if err := emitIptables(); err != nil {
  268. return fmt.Errorf("can not emit iptables conf: %s", err)
  269. }
  270. if err := emitCRL(); err != nil {
  271. return fmt.Errorf("can not emit crl: %s", err)
  272. }
  273. logrus.Info("configurations emitted to the filesystem")
  274. if IsInitialized() {
  275. for {
  276. if vpnProc.Status() == supervisor.RUNNING || vpnProc.Status() == supervisor.STOPPED {
  277. logrus.Info("OpenVPN process is restarting")
  278. RestartVPNProc()
  279. break
  280. }
  281. time.Sleep(1 * time.Second)
  282. }
  283. }
  284. return nil
  285. }
  286. func emitToFile(path, content string, mode uint) error {
  287. // When testing don't emit files to the filesystem. Just pretend you did.
  288. if Testing {
  289. return nil
  290. }
  291. file, err := os.Create(path)
  292. if err != nil {
  293. return fmt.Errorf("Cannot create file %s: %v", path, err)
  294. }
  295. if mode != 0 {
  296. file.Chmod(os.FileMode(mode))
  297. }
  298. defer file.Close()
  299. fmt.Fprintf(file, content)
  300. return nil
  301. }
  302. func emitServerConf() error {
  303. serverInstance, err := GetServerInstance()
  304. if err != nil {
  305. return fmt.Errorf("can not retrieve server: %v", err)
  306. }
  307. port := DefaultVPNPort
  308. if serverInstance.Port != "" {
  309. port = serverInstance.Port
  310. }
  311. var result bytes.Buffer
  312. server := _VPNServerConfig{
  313. CertPath: _DefaultCertPath,
  314. KeyPath: _DefaultKeyPath,
  315. CACertPath: _DefaultCACertPath,
  316. CAKeyPath: _DefaultCAKeyPath,
  317. CCDPath: _DefaultVPNCCDPath,
  318. CRLPath: _DefaultCRLPath,
  319. DHParamsPath: _DefaultDHParamsPath,
  320. Net: _DefaultServerNetwork,
  321. Mask: _DefaultServerNetMask,
  322. Port: port,
  323. }
  324. data, err := bindata.Asset("template/server.conf.tmpl")
  325. if err != nil {
  326. return err
  327. }
  328. t, err := template.New("server.conf").Parse(string(data))
  329. if err != nil {
  330. return fmt.Errorf("can not parse server.conf.tmpl template: %s", err)
  331. }
  332. err = t.Execute(&result, server)
  333. if err != nil {
  334. return fmt.Errorf("can not render server.conf: %s", err)
  335. }
  336. // Wite rendered content into openvpn server conf.
  337. return emitToFile(_DefaultVPNConfPath, result.String(), 0)
  338. }
  339. // GetServerInstance returns the default server from the database.
  340. func GetServerInstance() (*DBServer, error) {
  341. var server DBServer
  342. db.First(&server)
  343. if db.NewRecord(server) {
  344. return nil, fmt.Errorf("can not retrieve server from db")
  345. }
  346. return &server, nil
  347. }
  348. // IsInitialized checks if there is a default server in the database or not.
  349. func IsInitialized() bool {
  350. var server DBServer
  351. db.First(&server)
  352. if db.NewRecord(server) {
  353. return false
  354. }
  355. return true
  356. }
  357. func emitServerKey() error {
  358. server, err := GetServerInstance()
  359. if err != nil {
  360. return err
  361. }
  362. // Write rendered content into key file.
  363. return emitToFile(_DefaultKeyPath, server.Key, 0600)
  364. }
  365. func emitServerCert() error {
  366. server, err := GetServerInstance()
  367. if err != nil {
  368. return err
  369. }
  370. // Write rendered content into the cert file.
  371. return emitToFile(_DefaultCertPath, server.Cert, 0)
  372. }
  373. func emitCRL() error {
  374. var revokedDBItems []*DBRevoked
  375. db.Find(&revokedDBItems)
  376. var revokedCertSerials []*big.Int
  377. for _, item := range revokedDBItems {
  378. bi := big.NewInt(0)
  379. bi.SetString(item.SerialNumber, 16)
  380. revokedCertSerials = append(revokedCertSerials, bi)
  381. }
  382. systemCA, err := GetSystemCA()
  383. if err != nil {
  384. return fmt.Errorf("can not emit CRL: %v", err)
  385. }
  386. crl, err := pki.NewCRL(systemCA, revokedCertSerials...)
  387. if err != nil {
  388. return fmt.Errorf("can not emit crl: %v", err)
  389. }
  390. return emitToFile(_DefaultCRLPath, crl, 0)
  391. }
  392. func emitCACert() error {
  393. server, err := GetServerInstance()
  394. if err != nil {
  395. return err
  396. }
  397. // Write rendered content into the ca cert file.
  398. return emitToFile(_DefaultCACertPath, server.CACert, 0)
  399. }
  400. func emitCAKey() error {
  401. server, err := GetServerInstance()
  402. if err != nil {
  403. return err
  404. }
  405. // Write rendered content into the ca key file.
  406. return emitToFile(_DefaultCAKeyPath, server.CAKey, 0600)
  407. }
  408. func emitCCD() error {
  409. users, err := GetAllUsers()
  410. if err != nil {
  411. return err
  412. }
  413. // Create and write rendered ccd data.
  414. os.Mkdir(_DefaultVPNCCDPath, 0755)
  415. counter := 2
  416. for _, user := range users {
  417. var result bytes.Buffer
  418. params := struct {
  419. IP string
  420. NetMask string
  421. }{IP: user.getIP().String(), NetMask: _DefaultServerNetMask}
  422. data, err := bindata.Asset("template/ccd.file.tmpl")
  423. if err != nil {
  424. return err
  425. }
  426. t, err := template.New("ccd.file.tmpl").Parse(string(data))
  427. if err != nil {
  428. return fmt.Errorf("can not parse ccd.file.tmpl template: %s", err)
  429. }
  430. err = t.Execute(&result, params)
  431. if err != nil {
  432. return fmt.Errorf("can not render ccd file %s: %s", user.Username, err)
  433. }
  434. err = emitToFile(_DefaultVPNCCDPath+user.Username, result.String(), 0)
  435. if err != nil {
  436. return err
  437. }
  438. counter++
  439. }
  440. return nil
  441. }
  442. func emitDHParams() error {
  443. var result bytes.Buffer
  444. data, err := bindata.Asset("template/dh4096.pem.tmpl")
  445. if err != nil {
  446. return err
  447. }
  448. t, err := template.New("dh4096.pem.tmpl").Parse(string(data))
  449. if err != nil {
  450. return fmt.Errorf("can not parse dh4096.pem template: %s", err)
  451. }
  452. err = t.Execute(&result, nil)
  453. if err != nil {
  454. return fmt.Errorf("can not render dh4096.pem file: %s", err)
  455. }
  456. err = emitToFile(_DefaultDHParamsPath, result.String(), 0)
  457. if err != nil {
  458. return err
  459. }
  460. return nil
  461. }
  462. func emitIptables() error {
  463. return nil
  464. }
  465. func checkOpenVPNExecutable() bool {
  466. executable := getOpenVPNExecutable()
  467. if executable == "" {
  468. logrus.Error("openvpn is not installed ✘")
  469. return false
  470. }
  471. logrus.Debugf("openvpn executable detected: %s ✔", executable)
  472. return true
  473. }
  474. func getOpenVPNExecutable() string {
  475. cmd := exec.Command("which", "openvpn")
  476. output, err := cmd.Output()
  477. if err != nil {
  478. logrus.Errorf("openvpn is not installed: %s ✘", err)
  479. return ""
  480. }
  481. logrus.Debugf("openvpn executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  482. return strings.TrimSpace(string(output[:]))
  483. }
  484. func checkOpenSSLExecutable() bool {
  485. cmd := exec.Command("which", "openssl")
  486. output, err := cmd.Output()
  487. if err != nil {
  488. logrus.Errorf("openssl is not installed: %s ✘", err)
  489. return false
  490. }
  491. logrus.Debugf("openssl executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  492. return true
  493. }
  494. func checkIptablesExecutable() bool {
  495. cmd := exec.Command("which", "iptables")
  496. output, err := cmd.Output()
  497. if err != nil {
  498. logrus.Errorf("iptables is not installed: %s ✘", err)
  499. return false
  500. }
  501. logrus.Debugf("iptables executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  502. return true
  503. }
  504. func ensureBaseDir() {
  505. if Testing {
  506. return
  507. }
  508. os.Mkdir(varBasePath, 0755)
  509. }
  510. func init() {
  511. ensureBaseDir()
  512. var err error
  513. vpnProc, err = supervisor.NewProcess(getOpenVPNExecutable(), varBasePath, []string{"--config", _DefaultVPNConfPath})
  514. if err != nil {
  515. logrus.Errorf("can not create process: %v", err)
  516. }
  517. }