vpn.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. //go:generate go-bindata -pkg bindata -o bindata/bindata.go template/
  2. package ovpm
  3. import (
  4. "bytes"
  5. "fmt"
  6. "math/big"
  7. "net"
  8. "os"
  9. "os/exec"
  10. "strings"
  11. "text/template"
  12. "github.com/Sirupsen/logrus"
  13. "github.com/asaskevich/govalidator"
  14. "github.com/cad/ovpm/bindata"
  15. "github.com/google/uuid"
  16. "github.com/jinzhu/gorm"
  17. )
  18. // DBNetwork is database model for external networks on the VPN server.
  19. type DBNetwork struct {
  20. gorm.Model
  21. ServerID uint
  22. Server DBServer
  23. Name string
  24. NetworkCIDR string
  25. }
  26. // DBServer is database model for storing VPN server related stuff.
  27. type DBServer struct {
  28. gorm.Model
  29. Name string `gorm:"unique_index"` // Server name.
  30. SerialNumber string
  31. Hostname string // Server's ip address or FQDN
  32. Port string // Server's listening port
  33. Cert string // Server RSA certificate.
  34. Key string // Server RSA private key.
  35. CACert string // Root CA RSA certificate.
  36. CAKey string // Root CA RSA key.
  37. Net string // VPN network.
  38. Mask string // VPN network mask.
  39. CRL string // Certificate Revocation List
  40. }
  41. // CheckSerial takes a serial number and checks it against the current server's serial number.
  42. func (s *DBServer) CheckSerial(serialNo string) bool {
  43. return serialNo == s.SerialNumber
  44. }
  45. type _VPNServerConfig struct {
  46. CertPath string
  47. KeyPath string
  48. CACertPath string
  49. CAKeyPath string
  50. CCDPath string
  51. CRLPath string
  52. DHParamsPath string
  53. Net string
  54. Mask string
  55. Port string
  56. }
  57. // Initialize regenerates keys and certs for a Root CA, and saves them in the database.
  58. func Initialize(serverName string, hostname string, port string) error {
  59. if IsInitialized() {
  60. if err := DeInitialize("default"); err != nil {
  61. logrus.Errorf("server can not be deleted: %v", err)
  62. return err
  63. }
  64. }
  65. if !govalidator.IsHost(hostname) {
  66. return fmt.Errorf("validation error: hostname:`%s` should be either an ip address or a FQDN", hostname)
  67. }
  68. ca, err := NewCA()
  69. if err != nil {
  70. return fmt.Errorf("can not create ca creds: %s", err)
  71. }
  72. srv, err := NewServerCertHolder(ca)
  73. if err != nil {
  74. return fmt.Errorf("can not create server cert creds: %s", err)
  75. }
  76. serialNumber := uuid.New().String()
  77. serverInstance := DBServer{
  78. Name: serverName,
  79. SerialNumber: serialNumber,
  80. Hostname: hostname,
  81. Port: port,
  82. Cert: srv.Cert,
  83. Key: srv.Key,
  84. CACert: ca.Cert,
  85. CAKey: ca.Key,
  86. Net: DefaultServerNetwork,
  87. Mask: DefaultServerNetMask,
  88. }
  89. db.Create(&serverInstance)
  90. if db.NewRecord(&serverInstance) {
  91. return fmt.Errorf("can not create server instance on database")
  92. }
  93. users, err := GetAllUsers()
  94. if err != nil {
  95. return err
  96. }
  97. // Sign all users in the db with the new server
  98. for _, user := range users {
  99. err := user.Sign()
  100. logrus.Infof("user certificate changed for %s, you should run: $ ovpm user export-config --user %s", user.Username, user.Username)
  101. if err != nil {
  102. logrus.Errorf("can not sign user %s: %v", user.Username, err)
  103. continue
  104. }
  105. }
  106. return nil
  107. }
  108. // DeInitialize deletes the server with the given serverName from the database and frees the allocated resources.
  109. func DeInitialize(serverName string) error {
  110. if !IsInitialized() {
  111. return fmt.Errorf("server not found")
  112. }
  113. db.Unscoped().Delete(&DBServer{})
  114. db.Unscoped().Delete(&DBRevoked{})
  115. return nil
  116. }
  117. // DumpsClientConfig generates .ovpn file for the given vpn user and returns it as a string.
  118. func DumpsClientConfig(username string) (string, error) {
  119. var result bytes.Buffer
  120. user, err := GetUser(username)
  121. if err != nil {
  122. return "", err
  123. }
  124. server, err := GetServerInstance()
  125. if err != nil {
  126. return "", err
  127. }
  128. params := struct {
  129. Hostname string
  130. Port string
  131. CA string
  132. Key string
  133. Cert string
  134. }{
  135. Hostname: server.Hostname,
  136. Port: server.Port,
  137. CA: server.CACert,
  138. Key: user.Key,
  139. Cert: user.Cert,
  140. }
  141. data, err := bindata.Asset("template/client.ovpn.tmpl")
  142. if err != nil {
  143. return "", err
  144. }
  145. t, err := template.New("client.ovpn").Parse(string(data))
  146. if err != nil {
  147. return "", fmt.Errorf("can not parse client.ovpn.tmpl template: %s", err)
  148. }
  149. err = t.Execute(&result, params)
  150. if err != nil {
  151. return "", fmt.Errorf("can not render client.ovpn: %s", err)
  152. }
  153. return result.String(), nil
  154. }
  155. // DumpClientConfig generates .ovpn file for the given vpn user and dumps it to outPath.
  156. func DumpClientConfig(username, outPath string) error {
  157. result, err := DumpsClientConfig(username)
  158. if err != nil {
  159. return err
  160. }
  161. // Wite rendered content into openvpn server conf.
  162. return emitToFile(outPath, result, 0)
  163. }
  164. // GetSystemCA returns the system CA from the database if available.
  165. func GetSystemCA() (*CA, error) {
  166. server := DBServer{}
  167. db.First(&server)
  168. if db.NewRecord(&server) {
  169. return nil, fmt.Errorf("server record does not exists in db")
  170. }
  171. return &CA{
  172. CertHolder: CertHolder{
  173. Cert: server.CACert,
  174. Key: server.CAKey,
  175. },
  176. }, nil
  177. }
  178. // Emit generates all needed files for the OpenVPN server and dumps them to their corresponding paths defined in the config.
  179. func Emit() error {
  180. // Check dependencies
  181. if !checkOpenVPNExecutable() {
  182. return fmt.Errorf("openvpn executable can not be found! you should install OpenVPN on this machine")
  183. }
  184. if !checkOpenSSLExecutable() {
  185. return fmt.Errorf("openssl executable can not be found! you should install openssl on this machine")
  186. }
  187. if !checkIptablesExecutable() {
  188. return fmt.Errorf("iptables executable can not be found")
  189. }
  190. if !IsInitialized() {
  191. return fmt.Errorf("you should create a server first. e.g. $ ovpm vpn create-server")
  192. }
  193. if err := emitServerConf(); err != nil {
  194. return fmt.Errorf("can not emit server conf: %s", err)
  195. }
  196. if err := emitServerCert(); err != nil {
  197. return fmt.Errorf("can not emit server cert: %s", err)
  198. }
  199. if err := emitServerKey(); err != nil {
  200. return fmt.Errorf("can not emit server key: %s", err)
  201. }
  202. if err := emitCACert(); err != nil {
  203. return fmt.Errorf("can not emit ca cert : %s", err)
  204. }
  205. if err := emitCAKey(); err != nil {
  206. return fmt.Errorf("can not emit ca key: %s", err)
  207. }
  208. if err := emitDHParams(); err != nil {
  209. return fmt.Errorf("can not emit dhparams: %s", err)
  210. }
  211. if err := emitCCD(); err != nil {
  212. return fmt.Errorf("can not emit ccd: %s", err)
  213. }
  214. if err := emitIptables(); err != nil {
  215. return fmt.Errorf("can not emit iptables conf: %s", err)
  216. }
  217. if err := emitCRL(); err != nil {
  218. return fmt.Errorf("can not emit crl: %s", err)
  219. }
  220. logrus.Info("changes are applied to the filesystem")
  221. return nil
  222. }
  223. func emitToFile(filePath, content string, mode uint) error {
  224. file, err := os.Create(filePath)
  225. if err != nil {
  226. return fmt.Errorf("Cannot create file %s: %v", filePath, err)
  227. }
  228. if mode != 0 {
  229. file.Chmod(os.FileMode(mode))
  230. }
  231. defer file.Close()
  232. fmt.Fprintf(file, content)
  233. return nil
  234. }
  235. func emitServerConf() error {
  236. serverInstance, err := GetServerInstance()
  237. if err != nil {
  238. return fmt.Errorf("can not retrieve server: %v", err)
  239. }
  240. port := DefaultVPNPort
  241. if serverInstance.Port != "" {
  242. port = serverInstance.Port
  243. }
  244. var result bytes.Buffer
  245. server := _VPNServerConfig{
  246. CertPath: DefaultCertPath,
  247. KeyPath: DefaultKeyPath,
  248. CACertPath: DefaultCACertPath,
  249. CAKeyPath: DefaultCAKeyPath,
  250. CCDPath: DefaultVPNCCDPath,
  251. CRLPath: DefaultCRLPath,
  252. DHParamsPath: DefaultDHParamsPath,
  253. Net: DefaultServerNetwork,
  254. Mask: DefaultServerNetMask,
  255. Port: port,
  256. }
  257. data, err := bindata.Asset("template/server.conf.tmpl")
  258. if err != nil {
  259. return err
  260. }
  261. t, err := template.New("server.conf").Parse(string(data))
  262. if err != nil {
  263. return fmt.Errorf("can not parse server.conf.tmpl template: %s", err)
  264. }
  265. err = t.Execute(&result, server)
  266. if err != nil {
  267. return fmt.Errorf("can not render server.conf: %s", err)
  268. }
  269. // Wite rendered content into openvpn server conf.
  270. return emitToFile(DefaultVPNConfPath, result.String(), 0)
  271. }
  272. // GetServerInstance returns the default server from the database.
  273. func GetServerInstance() (*DBServer, error) {
  274. var server DBServer
  275. db.First(&server)
  276. if db.NewRecord(server) {
  277. return nil, fmt.Errorf("can not retrieve server from db")
  278. }
  279. return &server, nil
  280. }
  281. // IsInitialized checks if there is a default server in the database or not.
  282. func IsInitialized() bool {
  283. var server DBServer
  284. db.First(&server)
  285. if db.NewRecord(server) {
  286. return false
  287. }
  288. return true
  289. }
  290. func emitServerKey() error {
  291. server, err := GetServerInstance()
  292. if err != nil {
  293. return err
  294. }
  295. // Write rendered content into key file.
  296. return emitToFile(DefaultKeyPath, server.Key, 0600)
  297. }
  298. func emitServerCert() error {
  299. server, err := GetServerInstance()
  300. if err != nil {
  301. return err
  302. }
  303. // Write rendered content into the cert file.
  304. return emitToFile(DefaultCertPath, server.Cert, 0)
  305. }
  306. func emitCRL() error {
  307. var revokedDBItems []*DBRevoked
  308. db.Find(&revokedDBItems)
  309. var revokedCertSerials []*big.Int
  310. for _, item := range revokedDBItems {
  311. bi := big.NewInt(0)
  312. bi.SetString(item.SerialNumber, 16)
  313. revokedCertSerials = append(revokedCertSerials, bi)
  314. }
  315. systemCA, err := GetSystemCA()
  316. if err != nil {
  317. return fmt.Errorf("can not emit CRL: %v", err)
  318. }
  319. crl, err := NewCRL(revokedCertSerials, systemCA)
  320. if err != nil {
  321. return fmt.Errorf("can not emit crl: %v", err)
  322. }
  323. return emitToFile(DefaultCRLPath, crl, 0)
  324. }
  325. func emitCACert() error {
  326. server, err := GetServerInstance()
  327. if err != nil {
  328. return err
  329. }
  330. // Write rendered content into the ca cert file.
  331. return emitToFile(DefaultCACertPath, server.CACert, 0)
  332. }
  333. func emitCAKey() error {
  334. server, err := GetServerInstance()
  335. if err != nil {
  336. return err
  337. }
  338. // Write rendered content into the ca key file.
  339. return emitToFile(DefaultCAKeyPath, server.CAKey, 0600)
  340. }
  341. func emitCCD() error {
  342. users, err := GetAllUsers()
  343. if err != nil {
  344. return err
  345. }
  346. // Create and write rendered ccd data.
  347. os.Mkdir(DefaultVPNCCDPath, 0755)
  348. clientsNetMask := net.IPMask(net.ParseIP(DefaultServerNetMask))
  349. clientsNetPrefix := net.ParseIP(DefaultServerNetwork)
  350. clientNet := clientsNetPrefix.Mask(clientsNetMask).To4()
  351. counter := 2
  352. for _, user := range users {
  353. var result bytes.Buffer
  354. clientNet[3] = byte(counter)
  355. params := struct {
  356. IP string
  357. NetMask string
  358. }{IP: clientNet.String(), NetMask: DefaultServerNetMask}
  359. data, err := bindata.Asset("template/ccd.file.tmpl")
  360. if err != nil {
  361. return err
  362. }
  363. t, err := template.New("ccd.file.tmpl").Parse(string(data))
  364. if err != nil {
  365. return fmt.Errorf("can not parse ccd.file.tmpl template: %s", err)
  366. }
  367. err = t.Execute(&result, params)
  368. if err != nil {
  369. return fmt.Errorf("can not render ccd file %s: %s", user.Username, err)
  370. }
  371. err = emitToFile(DefaultVPNCCDPath+user.Username, result.String(), 0)
  372. if err != nil {
  373. return err
  374. }
  375. counter++
  376. }
  377. return nil
  378. }
  379. func emitDHParams() error {
  380. var result bytes.Buffer
  381. data, err := bindata.Asset("template/dh4096.pem.tmpl")
  382. if err != nil {
  383. return err
  384. }
  385. t, err := template.New("dh4096.pem.tmpl").Parse(string(data))
  386. if err != nil {
  387. return fmt.Errorf("can not parse dh4096.pem template: %s", err)
  388. }
  389. err = t.Execute(&result, nil)
  390. if err != nil {
  391. return fmt.Errorf("can not render dh4096.pem file: %s", err)
  392. }
  393. err = emitToFile(DefaultDHParamsPath, result.String(), 0)
  394. if err != nil {
  395. return err
  396. }
  397. return nil
  398. }
  399. func emitIptables() error {
  400. return nil
  401. }
  402. func checkOpenVPNExecutable() bool {
  403. cmd := exec.Command("which", "openvpn")
  404. output, err := cmd.Output()
  405. if err != nil {
  406. logrus.Errorf("openvpn is not installed: %s ✘", err)
  407. return false
  408. }
  409. logrus.Infof("openvpn executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  410. return true
  411. }
  412. func checkOpenSSLExecutable() bool {
  413. cmd := exec.Command("which", "openssl")
  414. output, err := cmd.Output()
  415. if err != nil {
  416. logrus.Errorf("openssl is not installed: %s ✘", err)
  417. return false
  418. }
  419. logrus.Infof("openssl executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  420. return true
  421. }
  422. func checkIptablesExecutable() bool {
  423. cmd := exec.Command("which", "iptables")
  424. output, err := cmd.Output()
  425. if err != nil {
  426. logrus.Errorf("iptables is not installed: %s ✘", err)
  427. return false
  428. }
  429. logrus.Infof("iptables executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  430. return true
  431. }