Browse Source

Skeleton certificate scanning

Fix bug in hostname generation not adding additional containers
master
Chris Smith 5 years ago
parent
commit
4b014b272b
4 changed files with 102 additions and 8 deletions
  1. 0
    1
      certificate_manager.go
  2. 91
    0
      certs/certificate_manager.go
  3. 9
    4
      dotege.go
  4. 2
    3
      template_generator.go

+ 0
- 1
certificate_manager.go View File

@@ -1 +0,0 @@
1
-package main

+ 91
- 0
certs/certificate_manager.go View File

@@ -0,0 +1,91 @@
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
+}
16
+
17
+type foundCertificate struct {
18
+	cert       string
19
+	chain      string
20
+	fullChain  string
21
+	privateKey string
22
+	modTime    time.Time
23
+}
24
+
25
+// NewCertificateManager creates a new CertificateManager.
26
+func NewCertificateManager(logger *zap.SugaredLogger) *CertificateManager {
27
+	return &CertificateManager{
28
+		logger: logger,
29
+	}
30
+}
31
+
32
+func (c *CertificateManager) AddDirectory(directory string) {
33
+	c.directories = append(c.directories, directory)
34
+	go c.scanForFolders(directory)
35
+}
36
+
37
+func (c *CertificateManager) scanForFolders(dir string) {
38
+	dirs, err := ioutil.ReadDir(dir)
39
+	if err != nil {
40
+		c.logger.Errorf("Unable to read directory %s - %s", dir, err.Error())
41
+		return
42
+	}
43
+
44
+	for _, d := range dirs {
45
+		if d.IsDir() {
46
+			c.scanForCerts(d.Name(), path.Join(dir, d.Name()))
47
+		}
48
+	}
49
+}
50
+
51
+func (c *CertificateManager) scanForCerts(vhost string, dir string) {
52
+	files, err := ioutil.ReadDir(dir)
53
+	if err != nil {
54
+		c.logger.Errorf("Unable to read directory %s - %s", dir, err.Error())
55
+		return
56
+	}
57
+
58
+	cert := foundCertificate{}
59
+	for _, f := range files {
60
+		ext := path.Ext(f.Name())
61
+		base := path.Base(f.Name())
62
+		if ext == "" && strings.Contains(base, "-") {
63
+			switch parts := strings.Split(base, "-"); parts[0] {
64
+			case "cert":
65
+				cert.cert = path.Join(dir, f.Name())
66
+				if f.ModTime().After(cert.modTime) {
67
+					cert.modTime = f.ModTime()
68
+				}
69
+			case "chain":
70
+				cert.chain = path.Join(dir, f.Name())
71
+				if f.ModTime().After(cert.modTime) {
72
+					cert.modTime = f.ModTime()
73
+				}
74
+			case "fullchain":
75
+				cert.fullChain = path.Join(dir, f.Name())
76
+				if f.ModTime().After(cert.modTime) {
77
+					cert.modTime = f.ModTime()
78
+				}
79
+			case "privkey":
80
+				cert.privateKey = path.Join(dir, f.Name())
81
+				if f.ModTime().After(cert.modTime) {
82
+					cert.modTime = f.ModTime()
83
+				}
84
+			}
85
+		}
86
+	}
87
+
88
+	if len(cert.cert) > 0 && len(cert.chain) > 0 && len(cert.fullChain) > 0 && len(cert.privateKey) > 0 {
89
+		c.logger.Debugf("Found certificate files for %s in %s", vhost, dir)
90
+	}
91
+}

+ 9
- 4
dotege.go View File

@@ -2,6 +2,7 @@ package main
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"github.com/csmith/dotege/certs"
5 6
 	"github.com/csmith/dotege/docker"
6 7
 	"github.com/csmith/dotege/model"
7 8
 	"github.com/docker/docker/client"
@@ -32,6 +33,7 @@ func monitorSignals() <-chan bool {
32 33
 func main() {
33 34
 	config := zap.NewDevelopmentConfig()
34 35
 	config.DisableCaller = true
36
+	config.DisableStacktrace = true
35 37
 	config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
36 38
 	config.OutputPaths = []string{"stdout"}
37 39
 	config.ErrorOutputPaths = []string{"stdout"}
@@ -51,6 +53,9 @@ func main() {
51 53
 		panic(err)
52 54
 	}
53 55
 
56
+	certMonitor := certs.NewCertificateManager(sugar)
57
+	certMonitor.AddDirectory("/certs/certs")
58
+
54 59
 	templateGenerator := NewTemplateGenerator(sugar)
55 60
 	templateGenerator.AddTemplate(model.TemplateConfig{
56 61
 		Source:      "./templates/domains.txt.tpl",
@@ -94,15 +99,15 @@ func main() {
94 99
 	}
95 100
 }
96 101
 
97
-func getHostnames(containers map[string]model.Container, config model.LabelConfig) (hostnames map[string]model.Hostname) {
98
-	hostnames = make(map[string]model.Hostname)
102
+func getHostnames(containers map[string]model.Container, config model.LabelConfig) (hostnames map[string]*model.Hostname) {
103
+	hostnames = make(map[string]*model.Hostname)
99 104
 	for _, container := range containers {
100 105
 		if label, ok := container.Labels[config.Hostnames]; ok {
101 106
 			names := strings.Split(strings.Replace(label, ",", " ", -1), " ")
102 107
 			if hostname, ok := hostnames[names[0]]; ok {
103 108
 				hostname.Containers = append(hostname.Containers, container)
104 109
 			} else {
105
-				hostnames[names[0]] = model.Hostname{
110
+				hostnames[names[0]] = &model.Hostname{
106 111
 					Name:         names[0],
107 112
 					Alternatives: make(map[string]bool),
108 113
 					Containers:   []model.Container{container},
@@ -114,7 +119,7 @@ func getHostnames(containers map[string]model.Container, config model.LabelConfi
114 119
 	return
115 120
 }
116 121
 
117
-func addAlternatives(hostname model.Hostname, alternatives []string) {
122
+func addAlternatives(hostname *model.Hostname, alternatives []string) {
118 123
 	for _, alternative := range alternatives {
119 124
 		hostname.Alternatives[alternative] = true
120 125
 	}

+ 2
- 3
template_generator.go View File

@@ -12,7 +12,7 @@ import (
12 12
 
13 13
 type Context struct {
14 14
 	Containers map[string]model.Container
15
-	Hostnames  map[string]model.Hostname
15
+	Hostnames  map[string]*model.Hostname
16 16
 }
17 17
 
18 18
 type Template struct {
@@ -67,8 +67,7 @@ func (t *TemplateGenerator) Generate(context Context) {
67 67
 			panic(err)
68 68
 		}
69 69
 		if tmpl.content != builder.String() {
70
-			t.logger.Debugf("%s has been updated, writing to %s", tmpl.config.Source, tmpl.config.Destination)
71
-			t.logger.Debug(builder.String())
70
+			t.logger.Infof("Writing updated template to %s", tmpl.config.Destination)
72 71
 			tmpl.content = builder.String()
73 72
 			err = ioutil.WriteFile(tmpl.config.Destination, []byte(builder.String()), 0666)
74 73
 			if err != nil {

Loading…
Cancel
Save