Browse Source

Emit discovered certs

master
Chris Smith 5 years ago
parent
commit
5b86f8e545
4 changed files with 116 additions and 102 deletions
  1. 0
    99
      certs/certificate_manager.go
  2. 100
    0
      certs/monitor.go
  3. 5
    3
      dotege.go
  4. 11
    0
      model/model.go

+ 0
- 99
certs/certificate_manager.go View File

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

+ 100
- 0
certs/monitor.go View File

@@ -0,0 +1,100 @@
1
+package certs
2
+
3
+import (
4
+	"github.com/csmith/dotege/model"
5
+	"go.uber.org/zap"
6
+	"io/ioutil"
7
+	"path"
8
+	"strings"
9
+)
10
+
11
+// CertificateMonitor handles scanning for new/updated certificates
12
+type CertificateMonitor struct {
13
+	logger      *zap.SugaredLogger
14
+	channel     chan<- model.FoundCertificate
15
+	directories []string
16
+	certs       map[string]*model.FoundCertificate
17
+}
18
+
19
+// NewCertificateManager creates a new CertificateMonitor.
20
+func NewCertificateManager(logger *zap.SugaredLogger, channel chan<- model.FoundCertificate) *CertificateMonitor {
21
+	return &CertificateMonitor{
22
+		logger:  logger,
23
+		channel: channel,
24
+	}
25
+}
26
+
27
+// AddDirectory adds a new directory to monitor
28
+func (c *CertificateMonitor) AddDirectory(directory string) {
29
+	c.directories = append(c.directories, directory)
30
+	go c.scanForFolders(directory)
31
+}
32
+
33
+func (c *CertificateMonitor) 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
+
40
+	for _, d := range dirs {
41
+		if d.IsDir() {
42
+			c.scanForCerts(d.Name(), path.Join(dir, d.Name()))
43
+		}
44
+	}
45
+}
46
+
47
+func (c *CertificateMonitor) scanForCerts(vhost string, dir string) {
48
+	files, err := ioutil.ReadDir(dir)
49
+	if err != nil {
50
+		c.logger.Errorf("Unable to read directory %s - %s", dir, err.Error())
51
+		return
52
+	}
53
+
54
+	cert := model.FoundCertificate{}
55
+	for _, f := range files {
56
+		ext := path.Ext(f.Name())
57
+		base := path.Base(f.Name())
58
+		if ext == "pem" {
59
+			prefix := strings.Split(base, "-")[0]
60
+			added := maybeAddPart(&cert, prefix, path.Join(dir, f.Name()))
61
+			if added && f.ModTime().After(cert.ModTime) {
62
+				cert.ModTime = f.ModTime()
63
+			}
64
+		}
65
+	}
66
+
67
+	c.maybeAddCert(vhost, cert)
68
+}
69
+
70
+func maybeAddPart(cert *model.FoundCertificate, part string, path string) bool {
71
+	switch part {
72
+	case "cert":
73
+		cert.Cert = path
74
+	case "chain":
75
+		cert.Chain = path
76
+	case "fullchain":
77
+		cert.FullChain = path
78
+	case "privkey":
79
+		cert.PrivateKey = path
80
+	default:
81
+		return false
82
+	}
83
+	return true
84
+}
85
+
86
+func (c *CertificateMonitor) maybeAddCert(vhost string, cert model.FoundCertificate) {
87
+	if len(cert.Cert) > 0 && len(cert.Chain) > 0 && len(cert.FullChain) > 0 && len(cert.PrivateKey) > 0 {
88
+		if existing, ok := c.certs[vhost]; ok {
89
+			if cert.ModTime.After(existing.ModTime) {
90
+				c.logger.Debugf("Found newer certificate files for %s in %s", vhost, path.Dir(cert.Cert))
91
+				c.certs[vhost] = &cert
92
+				c.channel <- cert
93
+			}
94
+		} else {
95
+			c.logger.Debugf("Found new certificate files for %s in %s", vhost, path.Dir(cert.Cert))
96
+			c.certs[vhost] = &cert
97
+			c.channel <- cert
98
+		}
99
+	}
100
+}

+ 5
- 3
dotege.go View File

@@ -41,9 +41,11 @@ func main() {
41 41
 	sugar := logger.Sugar()
42 42
 	sugar.Info("Dotege is starting")
43 43
 
44
-	done := monitorSignals()
44
+	doneChan := monitorSignals()
45 45
 	containerChan := make(chan model.Container, 1)
46 46
 	expiryChan := make(chan string, 1)
47
+	certChan := make(chan model.FoundCertificate, 1)
48
+
47 49
 	config := model.Config{
48 50
 		Labels: model.LabelConfig{
49 51
 			Hostnames: "com.chameth.vhost",
@@ -57,7 +59,7 @@ func main() {
57 59
 		panic(err)
58 60
 	}
59 61
 
60
-	certMonitor := certs.NewCertificateManager(sugar)
62
+	certMonitor := certs.NewCertificateManager(sugar, certChan)
61 63
 	certMonitor.AddDirectory("/data/certrequests/certs")
62 64
 
63 65
 	templateGenerator := NewTemplateGenerator(sugar)
@@ -95,7 +97,7 @@ func main() {
95 97
 		}
96 98
 	}()
97 99
 
98
-	<-done
100
+	<-doneChan
99 101
 
100 102
 	err = cli.Close()
101 103
 	if err != nil {

+ 11
- 0
model/model.go View File

@@ -1,5 +1,7 @@
1 1
 package model
2 2
 
3
+import "time"
4
+
3 5
 // CertActions define what will be done with a certificate
4 6
 type CertActions uint8
5 7
 
@@ -47,3 +49,12 @@ type TemplateConfig struct {
47 49
 	Source      string
48 50
 	Destination string
49 51
 }
52
+
53
+// FoundCertificate describes a certificate we've located on disk.
54
+type FoundCertificate struct {
55
+	Cert       string
56
+	Chain      string
57
+	FullChain  string
58
+	PrivateKey string
59
+	ModTime    time.Time
60
+}

Loading…
Cancel
Save