Browse Source

Deploy certs

master
Chris Smith 5 years ago
parent
commit
93f6cdc494
4 changed files with 50 additions and 23 deletions
  1. 4
    4
      docker.go
  2. 44
    17
      dotege.go
  3. 1
    1
      model/model.go
  4. 1
    1
      template_generator.go

+ 4
- 4
docker.go View File

@@ -15,7 +15,7 @@ type DockerClient interface {
15 15
 	ContainerInspect(ctx context.Context, containerID string) (types.ContainerJSON, error)
16 16
 }
17 17
 
18
-func monitorContainers(client DockerClient, stop <-chan struct{}, addedFn func(model.Container), removedFn func(string)) error {
18
+func monitorContainers(client DockerClient, stop <-chan struct{}, addedFn func(*model.Container), removedFn func(string)) error {
19 19
 	ctx, cancel := context.WithCancel(context.Background())
20 20
 	stream, errors := startEventStream(client, ctx)
21 21
 
@@ -33,7 +33,7 @@ func monitorContainers(client DockerClient, stop <-chan struct{}, addedFn func(m
33 33
 					cancel()
34 34
 					return err
35 35
 				}
36
-				addedFn(container)
36
+				addedFn(&container)
37 37
 			} else {
38 38
 				removedFn(event.Actor.Attributes["name"])
39 39
 			}
@@ -57,14 +57,14 @@ func startEventStream(client DockerClient, ctx context.Context) (<-chan events.M
57 57
 	return client.Events(ctx, types.EventsOptions{Filters: args})
58 58
 }
59 59
 
60
-func publishExistingContainers(client DockerClient, ctx context.Context, addedFn func(model.Container)) error {
60
+func publishExistingContainers(client DockerClient, ctx context.Context, addedFn func(*model.Container)) error {
61 61
 	containers, err := client.ContainerList(ctx, types.ContainerListOptions{})
62 62
 	if err != nil {
63 63
 		return fmt.Errorf("unable to list containers: %s", err.Error())
64 64
 	}
65 65
 
66 66
 	for _, container := range containers {
67
-		addedFn(model.Container{
67
+		addedFn(&model.Container{
68 68
 			Id:     container.ID,
69 69
 			Name:   container.Names[0][1:],
70 70
 			Labels: container.Labels,

+ 44
- 17
dotege.go View File

@@ -8,8 +8,10 @@ import (
8 8
 	"github.com/xenolf/lego/lego"
9 9
 	"go.uber.org/zap"
10 10
 	"go.uber.org/zap/zapcore"
11
+	"io/ioutil"
11 12
 	"os"
12 13
 	"os/signal"
14
+	"path"
13 15
 	"strings"
14 16
 	"syscall"
15 17
 	"time"
@@ -31,6 +33,12 @@ const (
31 33
 	envTemplateSourceDefault      = "./templates/haproxy.cfg.tpl"
32 34
 )
33 35
 
36
+var (
37
+	logger             *zap.SugaredLogger
38
+	certificateManager *CertificateManager
39
+	config             *model.Config
40
+)
41
+
34 42
 func requiredVar(key string) (value string) {
35 43
 	value, ok := os.LookupEnv(key)
36 44
 	if !ok {
@@ -73,8 +81,8 @@ func createLogger() *zap.SugaredLogger {
73 81
 	return logger.Sugar()
74 82
 }
75 83
 
76
-func createConfig() *model.Config {
77
-	return &model.Config{
84
+func createConfig() {
85
+	config = &model.Config{
78 86
 		Templates: []model.TemplateConfig{
79 87
 			{
80 88
 				Source:      optionalVar(envTemplateSourceKey, envTemplateSourceDefault),
@@ -97,7 +105,7 @@ func createConfig() *model.Config {
97 105
 	}
98 106
 }
99 107
 
100
-func createTemplateGenerator(logger *zap.SugaredLogger, templates []model.TemplateConfig) *TemplateGenerator {
108
+func createTemplateGenerator(templates []model.TemplateConfig) *TemplateGenerator {
101 109
 	templateGenerator := NewTemplateGenerator(logger)
102 110
 	for _, template := range templates {
103 111
 		templateGenerator.AddTemplate(template)
@@ -105,21 +113,20 @@ func createTemplateGenerator(logger *zap.SugaredLogger, templates []model.Templa
105 113
 	return templateGenerator
106 114
 }
107 115
 
108
-func createCertificateManager(logger *zap.SugaredLogger, config model.AcmeConfig) *CertificateManager {
109
-	certificateManager := NewCertificateManager(logger, config.Endpoint, config.KeyType, config.DnsProvider, config.CacheLocation)
116
+func createCertificateManager(config model.AcmeConfig) {
117
+	certificateManager = NewCertificateManager(logger, config.Endpoint, config.KeyType, config.DnsProvider, config.CacheLocation)
110 118
 	err := certificateManager.Init(config.Email)
111 119
 	if err != nil {
112 120
 		panic(err)
113 121
 	}
114
-	return certificateManager
115 122
 }
116 123
 
117 124
 func main() {
118
-	logger := createLogger()
125
+	logger = createLogger()
119 126
 	logger.Info("Dotege is starting")
120 127
 
121 128
 	doneChan := monitorSignals()
122
-	config := createConfig()
129
+	createConfig()
123 130
 
124 131
 	dockerStopChan := make(chan struct{})
125 132
 	dockerClient, err := client.NewEnvClient()
@@ -127,18 +134,18 @@ func main() {
127 134
 		panic(err)
128 135
 	}
129 136
 
130
-	templateGenerator := createTemplateGenerator(logger, config.Templates)
131
-	certificateManager := createCertificateManager(logger, config.Acme)
137
+	templateGenerator := createTemplateGenerator(config.Templates)
138
+	createCertificateManager(config.Acme)
132 139
 
133 140
 	jitterTimer := time.NewTimer(time.Minute)
134 141
 	redeployTimer := time.NewTicker(time.Hour * 24)
135
-	containers := make(map[string]model.Container)
142
+	containers := make(map[string]*model.Container)
136 143
 
137 144
 	go func() {
138
-		err := monitorContainers(dockerClient, dockerStopChan, func(container model.Container) {
145
+		err := monitorContainers(dockerClient, dockerStopChan, func(container *model.Container) {
139 146
 			containers[container.Name] = container
140 147
 			jitterTimer.Reset(100 * time.Millisecond)
141
-			err, _ = certificateManager.GetCertificate(getHostnamesForContainer(container, *config))
148
+			deployCertForContainer(container)
142 149
 		}, func(name string) {
143 150
 			delete(containers, name)
144 151
 			jitterTimer.Reset(100 * time.Millisecond)
@@ -161,7 +168,7 @@ func main() {
161 168
 			case <-redeployTimer.C:
162 169
 				logger.Info("Performing periodic certificate refresh")
163 170
 				for _, container := range containers {
164
-					err, _ = certificateManager.GetCertificate(getHostnamesForContainer(container, *config))
171
+					deployCertForContainer(container)
165 172
 				}
166 173
 			}
167 174
 		}
@@ -176,7 +183,7 @@ func main() {
176 183
 	}
177 184
 }
178 185
 
179
-func getHostnamesForContainer(container model.Container, config model.Config) []string {
186
+func getHostnamesForContainer(container *model.Container) []string {
180 187
 	if label, ok := container.Labels[config.Labels.Hostnames]; ok {
181 188
 		return strings.Split(strings.Replace(label, ",", " ", -1), " ")
182 189
 	} else {
@@ -184,7 +191,7 @@ func getHostnamesForContainer(container model.Container, config model.Config) []
184 191
 	}
185 192
 }
186 193
 
187
-func getHostnames(containers map[string]model.Container, config model.Config) (hostnames map[string]*model.Hostname) {
194
+func getHostnames(containers map[string]*model.Container, config model.Config) (hostnames map[string]*model.Hostname) {
188 195
 	hostnames = make(map[string]*model.Hostname)
189 196
 	for _, container := range containers {
190 197
 		if label, ok := container.Labels[config.Labels.Hostnames]; ok {
@@ -195,7 +202,7 @@ func getHostnames(containers map[string]model.Container, config model.Config) (h
195 202
 				hostnames[names[0]] = &model.Hostname{
196 203
 					Name:            names[0],
197 204
 					Alternatives:    make(map[string]bool),
198
-					Containers:      []model.Container{container},
205
+					Containers:      []*model.Container{container},
199 206
 					CertActions:     config.DefaultCertActions,
200 207
 					CertDestination: config.DefaultCertDestination,
201 208
 				}
@@ -216,3 +223,23 @@ func addAlternatives(hostname *model.Hostname, alternatives []string) {
216 223
 		hostname.Alternatives[alternative] = true
217 224
 	}
218 225
 }
226
+
227
+func deployCertForContainer(container *model.Container) {
228
+	err, cert := certificateManager.GetCertificate(getHostnamesForContainer(container))
229
+	if err != nil {
230
+		logger.Warnf("Unable to generate certificate for %s: %s", container.Name, err.Error())
231
+	} else {
232
+		deployCert(cert)
233
+	}
234
+}
235
+
236
+func deployCert(certificate *SavedCertificate) {
237
+	target := path.Join(config.DefaultCertDestination, fmt.Sprintf("%s.pem", certificate.Domains[0]))
238
+
239
+	err := ioutil.WriteFile(target, append(certificate.Certificate, certificate.PrivateKey...), 0700)
240
+	if err != nil {
241
+		logger.Warnf("Unable to write certificate %s - %s", target, err.Error())
242
+	} else {
243
+		logger.Infof("Updated certificate file %s", target)
244
+	}
245
+}

+ 1
- 1
model/model.go View File

@@ -44,7 +44,7 @@ type AcmeConfig struct {
44 44
 type Hostname struct {
45 45
 	Name            string
46 46
 	Alternatives    map[string]bool
47
-	Containers      []Container
47
+	Containers      []*Container
48 48
 	CertActions     CertActions
49 49
 	CertDestination string
50 50
 	RequiresAuth    bool

+ 1
- 1
template_generator.go View File

@@ -11,7 +11,7 @@ import (
11 11
 )
12 12
 
13 13
 type Context struct {
14
-	Containers map[string]model.Container
14
+	Containers map[string]*model.Container
15 15
 	Hostnames  map[string]*model.Hostname
16 16
 }
17 17
 

Loading…
Cancel
Save