Browse Source

Flesh out cert handling a bit more

master
Chris Smith 5 years ago
parent
commit
0bbfd5f075
3 changed files with 66 additions and 35 deletions
  1. 21
    13
      certs/certificate_manager.go
  2. 23
    17
      dotege.go
  3. 22
    5
      model/model.go

+ 21
- 13
certs/certificate_manager.go View File

12
 type CertificateManager struct {
12
 type CertificateManager struct {
13
 	logger      *zap.SugaredLogger
13
 	logger      *zap.SugaredLogger
14
 	directories []string
14
 	directories []string
15
+	certs       map[string]*foundCertificate
15
 }
16
 }
16
 
17
 
17
 type foundCertificate struct {
18
 type foundCertificate struct {
29
 	}
30
 	}
30
 }
31
 }
31
 
32
 
33
+// AddDirectory adds a new directory to monitor
32
 func (c *CertificateManager) AddDirectory(directory string) {
34
 func (c *CertificateManager) AddDirectory(directory string) {
33
 	c.directories = append(c.directories, directory)
35
 	c.directories = append(c.directories, directory)
34
 	go c.scanForFolders(directory)
36
 	go c.scanForFolders(directory)
63
 			switch parts := strings.Split(base, "-"); parts[0] {
65
 			switch parts := strings.Split(base, "-"); parts[0] {
64
 			case "cert":
66
 			case "cert":
65
 				cert.cert = path.Join(dir, f.Name())
67
 				cert.cert = path.Join(dir, f.Name())
66
-				if f.ModTime().After(cert.modTime) {
67
-					cert.modTime = f.ModTime()
68
-				}
69
 			case "chain":
68
 			case "chain":
70
 				cert.chain = path.Join(dir, f.Name())
69
 				cert.chain = path.Join(dir, f.Name())
71
-				if f.ModTime().After(cert.modTime) {
72
-					cert.modTime = f.ModTime()
73
-				}
74
 			case "fullchain":
70
 			case "fullchain":
75
 				cert.fullChain = path.Join(dir, f.Name())
71
 				cert.fullChain = path.Join(dir, f.Name())
76
-				if f.ModTime().After(cert.modTime) {
77
-					cert.modTime = f.ModTime()
78
-				}
79
 			case "privkey":
72
 			case "privkey":
80
 				cert.privateKey = path.Join(dir, f.Name())
73
 				cert.privateKey = path.Join(dir, f.Name())
81
-				if f.ModTime().After(cert.modTime) {
82
-					cert.modTime = f.ModTime()
83
-				}
74
+			default:
75
+				continue
76
+			}
77
+
78
+			if f.ModTime().After(cert.modTime) {
79
+				cert.modTime = f.ModTime()
84
 			}
80
 			}
85
 		}
81
 		}
86
 	}
82
 	}
87
 
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 {
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)
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
+		}
90
 	}
98
 	}
91
 }
99
 }

+ 23
- 17
dotege.go View File

31
 }
31
 }
32
 
32
 
33
 func main() {
33
 func main() {
34
-	config := zap.NewDevelopmentConfig()
35
-	config.DisableCaller = true
36
-	config.DisableStacktrace = true
37
-	config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
38
-	config.OutputPaths = []string{"stdout"}
39
-	config.ErrorOutputPaths = []string{"stdout"}
40
-	logger, _ := config.Build()
34
+	zapConfig := zap.NewDevelopmentConfig()
35
+	zapConfig.DisableCaller = true
36
+	zapConfig.DisableStacktrace = true
37
+	zapConfig.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
38
+	zapConfig.OutputPaths = []string{"stdout"}
39
+	zapConfig.ErrorOutputPaths = []string{"stdout"}
40
+	logger, _ := zapConfig.Build()
41
 	sugar := logger.Sugar()
41
 	sugar := logger.Sugar()
42
 	sugar.Info("Dotege is starting")
42
 	sugar.Info("Dotege is starting")
43
 
43
 
44
 	done := monitorSignals()
44
 	done := monitorSignals()
45
 	containerChan := make(chan model.Container, 1)
45
 	containerChan := make(chan model.Container, 1)
46
 	expiryChan := make(chan string, 1)
46
 	expiryChan := make(chan string, 1)
47
-	labelConfig := model.LabelConfig{
48
-		Hostnames: "com.chameth.vhost",
47
+	config := model.Config{
48
+		Labels: model.LabelConfig{
49
+			Hostnames: "com.chameth.vhost",
50
+		},
51
+		DefaultCertActions:     model.COMBINE | model.FLATTEN,
52
+		DefaultCertDestination: "/data/certs/",
49
 	}
53
 	}
50
 
54
 
51
 	cli, err := client.NewEnvClient()
55
 	cli, err := client.NewEnvClient()
54
 	}
58
 	}
55
 
59
 
56
 	certMonitor := certs.NewCertificateManager(sugar)
60
 	certMonitor := certs.NewCertificateManager(sugar)
57
-	certMonitor.AddDirectory("/certs/certs")
61
+	certMonitor.AddDirectory("/data/certrequests/certs")
58
 
62
 
59
 	templateGenerator := NewTemplateGenerator(sugar)
63
 	templateGenerator := NewTemplateGenerator(sugar)
60
 	templateGenerator.AddTemplate(model.TemplateConfig{
64
 	templateGenerator.AddTemplate(model.TemplateConfig{
61
 		Source:      "./templates/domains.txt.tpl",
65
 		Source:      "./templates/domains.txt.tpl",
62
-		Destination: "domains.txt",
66
+		Destination: "/data/certrequests/domains.txt",
63
 	})
67
 	})
64
 	templateGenerator.AddTemplate(model.TemplateConfig{
68
 	templateGenerator.AddTemplate(model.TemplateConfig{
65
 		Source:      "./templates/haproxy.cfg.tpl",
69
 		Source:      "./templates/haproxy.cfg.tpl",
85
 			case <-timer.C:
89
 			case <-timer.C:
86
 				templateGenerator.Generate(Context{
90
 				templateGenerator.Generate(Context{
87
 					Containers: containers,
91
 					Containers: containers,
88
-					Hostnames:  getHostnames(containers, labelConfig),
92
+					Hostnames:  getHostnames(containers, config),
89
 				})
93
 				})
90
 			}
94
 			}
91
 		}
95
 		}
99
 	}
103
 	}
100
 }
104
 }
101
 
105
 
102
-func getHostnames(containers map[string]model.Container, config model.LabelConfig) (hostnames map[string]*model.Hostname) {
106
+func getHostnames(containers map[string]model.Container, config model.Config) (hostnames map[string]*model.Hostname) {
103
 	hostnames = make(map[string]*model.Hostname)
107
 	hostnames = make(map[string]*model.Hostname)
104
 	for _, container := range containers {
108
 	for _, container := range containers {
105
-		if label, ok := container.Labels[config.Hostnames]; ok {
109
+		if label, ok := container.Labels[config.Labels.Hostnames]; ok {
106
 			names := strings.Split(strings.Replace(label, ",", " ", -1), " ")
110
 			names := strings.Split(strings.Replace(label, ",", " ", -1), " ")
107
 			if hostname, ok := hostnames[names[0]]; ok {
111
 			if hostname, ok := hostnames[names[0]]; ok {
108
 				hostname.Containers = append(hostname.Containers, container)
112
 				hostname.Containers = append(hostname.Containers, container)
109
 			} else {
113
 			} else {
110
 				hostnames[names[0]] = &model.Hostname{
114
 				hostnames[names[0]] = &model.Hostname{
111
-					Name:         names[0],
112
-					Alternatives: make(map[string]bool),
113
-					Containers:   []model.Container{container},
115
+					Name:            names[0],
116
+					Alternatives:    make(map[string]bool),
117
+					Containers:      []model.Container{container},
118
+					CertActions:     config.DefaultCertActions,
119
+					CertDestination: config.DefaultCertDestination,
114
 				}
120
 				}
115
 			}
121
 			}
116
 			addAlternatives(hostnames[names[0]], names[1:])
122
 			addAlternatives(hostnames[names[0]], names[1:])

+ 22
- 5
model/model.go View File

1
 package model
1
 package model
2
 
2
 
3
+// CertActions define what will be done with a certificate
4
+type CertActions uint8
5
+
6
+// constants defining CertActions
7
+const (
8
+	// COMBINE the full chain and private key into one file
9
+	COMBINE CertActions = 1 << iota
10
+	// FLATTEN the directory structure so all files are in one dir
11
+	FLATTEN
12
+	// CHMOD the files so they are world readable (potentially dangerous!)
13
+	CHMOD
14
+)
15
+
3
 // Container models a docker container that is running on the system.
16
 // Container models a docker container that is running on the system.
4
 type Container struct {
17
 type Container struct {
5
 	Id     string
18
 	Id     string
14
 
27
 
15
 // Hostname describes a DNS name used for proxying, retrieving certificates, etc.
28
 // Hostname describes a DNS name used for proxying, retrieving certificates, etc.
16
 type Hostname struct {
29
 type Hostname struct {
17
-	Name         string
18
-	Alternatives map[string]bool
19
-	Containers   []Container
30
+	Name            string
31
+	Alternatives    map[string]bool
32
+	Containers      []Container
33
+	CertActions     CertActions
34
+	CertDestination string
20
 }
35
 }
21
 
36
 
22
 // Config is the user-definable configuration for Dotege.
37
 // Config is the user-definable configuration for Dotege.
23
 type Config struct {
38
 type Config struct {
24
-	Templates []TemplateConfig
25
-	Labels    LabelConfig
39
+	Templates              []TemplateConfig
40
+	Labels                 LabelConfig
41
+	DefaultCertActions     CertActions
42
+	DefaultCertDestination string
26
 }
43
 }
27
 
44
 
28
 // TemplateConfig configures a single template for the generator.
45
 // TemplateConfig configures a single template for the generator.

Loading…
Cancel
Save