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.

certificate_manager.go 2.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package certs
  2. import (
  3. "go.uber.org/zap"
  4. "io/ioutil"
  5. "path"
  6. "strings"
  7. "time"
  8. )
  9. // CertificateManager handles scanning for new/updated certificates and deploying them to a destination.
  10. type CertificateManager struct {
  11. logger *zap.SugaredLogger
  12. directories []string
  13. certs map[string]*foundCertificate
  14. }
  15. type foundCertificate struct {
  16. cert string
  17. chain string
  18. fullChain string
  19. privateKey string
  20. modTime time.Time
  21. }
  22. // NewCertificateManager creates a new CertificateManager.
  23. func NewCertificateManager(logger *zap.SugaredLogger) *CertificateManager {
  24. return &CertificateManager{
  25. logger: logger,
  26. }
  27. }
  28. // AddDirectory adds a new directory to monitor
  29. func (c *CertificateManager) AddDirectory(directory string) {
  30. c.directories = append(c.directories, directory)
  31. go c.scanForFolders(directory)
  32. }
  33. func (c *CertificateManager) scanForFolders(dir string) {
  34. dirs, err := ioutil.ReadDir(dir)
  35. if err != nil {
  36. c.logger.Errorf("Unable to read directory %s - %s", dir, err.Error())
  37. return
  38. }
  39. for _, d := range dirs {
  40. if d.IsDir() {
  41. c.scanForCerts(d.Name(), path.Join(dir, d.Name()))
  42. }
  43. }
  44. }
  45. func (c *CertificateManager) scanForCerts(vhost string, dir string) {
  46. files, err := ioutil.ReadDir(dir)
  47. if err != nil {
  48. c.logger.Errorf("Unable to read directory %s - %s", dir, err.Error())
  49. return
  50. }
  51. cert := foundCertificate{}
  52. for _, f := range files {
  53. ext := path.Ext(f.Name())
  54. base := path.Base(f.Name())
  55. if ext == "" && strings.Contains(base, "-") {
  56. switch parts := strings.Split(base, "-"); parts[0] {
  57. case "cert":
  58. cert.cert = path.Join(dir, f.Name())
  59. case "chain":
  60. cert.chain = path.Join(dir, f.Name())
  61. case "fullchain":
  62. cert.fullChain = path.Join(dir, f.Name())
  63. case "privkey":
  64. cert.privateKey = path.Join(dir, f.Name())
  65. default:
  66. continue
  67. }
  68. if f.ModTime().After(cert.modTime) {
  69. cert.modTime = f.ModTime()
  70. }
  71. }
  72. }
  73. c.maybeAddCert(vhost, cert)
  74. }
  75. func (c *CertificateManager) maybeAddCert(vhost string, cert foundCertificate) {
  76. if len(cert.cert) > 0 && len(cert.chain) > 0 && len(cert.fullChain) > 0 && len(cert.privateKey) > 0 {
  77. if existing, ok := c.certs[vhost]; ok {
  78. if cert.modTime.After(existing.modTime) {
  79. c.logger.Debugf("Found newer certificate files for %s in %s", vhost, path.Dir(cert.cert))
  80. c.certs[vhost] = &cert
  81. }
  82. } else {
  83. c.logger.Debugf("Found new certificate files for %s in %s", vhost, path.Dir(cert.cert))
  84. c.certs[vhost] = &cert
  85. }
  86. }
  87. }