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.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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. } else {
  48. c.logger.Warnf("No certificate found for %s", hostname.Name)
  49. }
  50. }
  51. }
  52. }
  53. }
  54. func (c *CertificateDeployer) deploySingle(cert model.FoundCertificate, hostname *model.Hostname) {
  55. if (hostname.CertActions & model.COMBINE) == model.COMBINE {
  56. chain := c.readFile(cert.FullChain)
  57. pkey := c.readFile(cert.PrivateKey)
  58. c.deployFile("combined.pem", append(chain, pkey...), cert.ModTime, hostname)
  59. } else {
  60. c.deployFile("cert.pem", c.readFile(cert.Cert), cert.ModTime, hostname)
  61. c.deployFile("chain.pem", c.readFile(cert.Chain), cert.ModTime, hostname)
  62. c.deployFile("fullchain.pem", c.readFile(cert.FullChain), cert.ModTime, hostname)
  63. c.deployFile("privkey.pem", c.readFile(cert.PrivateKey), cert.ModTime, hostname)
  64. }
  65. }
  66. func (c *CertificateDeployer) deployFile(name string, content []byte, modTime time.Time, hostname *model.Hostname) {
  67. var target string
  68. if (hostname.CertActions & model.FLATTEN) == model.FLATTEN {
  69. target = path.Join(hostname.CertDestination, hostname.Name+".pem")
  70. } else {
  71. target = path.Join(hostname.CertDestination, hostname.Name, name)
  72. }
  73. info, err := os.Stat(target)
  74. if err == nil && info.ModTime().After(modTime) {
  75. c.logger.Debugf("Not writing %s as it was modified more recently than our cert", target)
  76. return
  77. }
  78. err = ioutil.WriteFile(target, content, 0700)
  79. if err != nil {
  80. c.logger.Warnf("Unable to write certificate %s - %s", target, err.Error())
  81. } else {
  82. c.logger.Infof("Updated certificate file %s", target)
  83. }
  84. }
  85. func (c *CertificateDeployer) readFile(name string) []byte {
  86. data, err := ioutil.ReadFile(name)
  87. if err != nil {
  88. c.logger.Errorf("Unable to read certificate file %s - %s", name, err.Error())
  89. }
  90. return data
  91. }
  92. func (c *CertificateDeployer) UpdateHostnames(hostnames map[string]*model.Hostname) {
  93. c.hostnames = hostnames
  94. c.deployChannel <- true
  95. }