Docker template generator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

deployer.go 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package certs
  2. import (
  3. "github.com/csmith/dotege/model"
  4. "go.uber.org/zap"
  5. "io/ioutil"
  6. "os"
  7. "path"
  8. "time"
  9. )
  10. // CertificateDeployer deploys certificates according to their configuration.
  11. type CertificateDeployer struct {
  12. logger *zap.SugaredLogger
  13. certChannel <-chan model.FoundCertificate
  14. deployChannel chan bool
  15. certs map[string]model.FoundCertificate
  16. hostnames map[string]*model.Hostname
  17. }
  18. // NewCertificateDeployer creates a new CertificateDeployer.
  19. func NewCertificateDeployer(logger *zap.SugaredLogger, channel <-chan model.FoundCertificate) *CertificateDeployer {
  20. deployer := &CertificateDeployer{
  21. logger: logger,
  22. certChannel: channel,
  23. deployChannel: make(chan bool, 1),
  24. certs: make(map[string]model.FoundCertificate),
  25. }
  26. go deployer.monitor()
  27. go deployer.deployAll()
  28. return deployer
  29. }
  30. func (c *CertificateDeployer) monitor() {
  31. for {
  32. select {
  33. case cert := <-c.certChannel:
  34. c.certs[cert.Hostname] = cert
  35. c.deployChannel <- true
  36. }
  37. }
  38. }
  39. func (c *CertificateDeployer) deployAll() {
  40. for {
  41. select {
  42. case <-c.deployChannel:
  43. c.logger.Debug("Checking for certificates requiring deployment")
  44. for _, hostname := range c.hostnames {
  45. if cert, ok := c.certs[hostname.Name]; ok {
  46. c.deploySingle(cert, hostname)
  47. }
  48. }
  49. }
  50. }
  51. }
  52. func (c *CertificateDeployer) deploySingle(cert model.FoundCertificate, hostname *model.Hostname) {
  53. if (hostname.CertActions & model.COMBINE) == model.COMBINE {
  54. chain := c.readFile(cert.FullChain)
  55. pkey := c.readFile(cert.PrivateKey)
  56. c.deployFile("combined.pem", append(chain, pkey...), cert.ModTime, hostname)
  57. } else {
  58. c.deployFile("cert.pem", c.readFile(cert.Cert), cert.ModTime, hostname)
  59. c.deployFile("chain.pem", c.readFile(cert.Chain), cert.ModTime, hostname)
  60. c.deployFile("fullchain.pem", c.readFile(cert.FullChain), cert.ModTime, hostname)
  61. c.deployFile("privkey.pem", c.readFile(cert.PrivateKey), cert.ModTime, hostname)
  62. }
  63. }
  64. func (c *CertificateDeployer) deployFile(name string, content []byte, modTime time.Time, hostname *model.Hostname) {
  65. var target string
  66. if (hostname.CertActions & model.FLATTEN) == model.FLATTEN {
  67. target = path.Join(hostname.CertDestination, hostname.Name+".pem")
  68. } else {
  69. target = path.Join(hostname.CertDestination, hostname.Name, name)
  70. }
  71. info, err := os.Stat(target)
  72. if err != nil && info.ModTime().After(modTime) {
  73. c.logger.Debugf("Not writing %s as it was modified more recently than our cert", target)
  74. return
  75. }
  76. err = ioutil.WriteFile(target, content, 0700)
  77. if err != nil {
  78. c.logger.Warnf("Unable to write certificate %s - %s", target, err.Error())
  79. } else {
  80. c.logger.Info("Updated certificate file %s", target)
  81. }
  82. }
  83. func (c *CertificateDeployer) readFile(name string) []byte {
  84. data, err := ioutil.ReadFile(name)
  85. if err != nil {
  86. c.logger.Errorf("Unable to read certificate file %s - %s", name, err.Error())
  87. }
  88. return data
  89. }
  90. func (c *CertificateDeployer) UpdateHostnames(hostnames map[string]*model.Hostname) {
  91. c.hostnames = hostnames
  92. c.deployChannel <- true
  93. }