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
 	ContainerInspect(ctx context.Context, containerID string) (types.ContainerJSON, error)
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
 	ctx, cancel := context.WithCancel(context.Background())
19
 	ctx, cancel := context.WithCancel(context.Background())
20
 	stream, errors := startEventStream(client, ctx)
20
 	stream, errors := startEventStream(client, ctx)
21
 
21
 
33
 					cancel()
33
 					cancel()
34
 					return err
34
 					return err
35
 				}
35
 				}
36
-				addedFn(container)
36
+				addedFn(&container)
37
 			} else {
37
 			} else {
38
 				removedFn(event.Actor.Attributes["name"])
38
 				removedFn(event.Actor.Attributes["name"])
39
 			}
39
 			}
57
 	return client.Events(ctx, types.EventsOptions{Filters: args})
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
 	containers, err := client.ContainerList(ctx, types.ContainerListOptions{})
61
 	containers, err := client.ContainerList(ctx, types.ContainerListOptions{})
62
 	if err != nil {
62
 	if err != nil {
63
 		return fmt.Errorf("unable to list containers: %s", err.Error())
63
 		return fmt.Errorf("unable to list containers: %s", err.Error())
64
 	}
64
 	}
65
 
65
 
66
 	for _, container := range containers {
66
 	for _, container := range containers {
67
-		addedFn(model.Container{
67
+		addedFn(&model.Container{
68
 			Id:     container.ID,
68
 			Id:     container.ID,
69
 			Name:   container.Names[0][1:],
69
 			Name:   container.Names[0][1:],
70
 			Labels: container.Labels,
70
 			Labels: container.Labels,

+ 44
- 17
dotege.go View File

8
 	"github.com/xenolf/lego/lego"
8
 	"github.com/xenolf/lego/lego"
9
 	"go.uber.org/zap"
9
 	"go.uber.org/zap"
10
 	"go.uber.org/zap/zapcore"
10
 	"go.uber.org/zap/zapcore"
11
+	"io/ioutil"
11
 	"os"
12
 	"os"
12
 	"os/signal"
13
 	"os/signal"
14
+	"path"
13
 	"strings"
15
 	"strings"
14
 	"syscall"
16
 	"syscall"
15
 	"time"
17
 	"time"
31
 	envTemplateSourceDefault      = "./templates/haproxy.cfg.tpl"
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
 func requiredVar(key string) (value string) {
42
 func requiredVar(key string) (value string) {
35
 	value, ok := os.LookupEnv(key)
43
 	value, ok := os.LookupEnv(key)
36
 	if !ok {
44
 	if !ok {
73
 	return logger.Sugar()
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
 		Templates: []model.TemplateConfig{
86
 		Templates: []model.TemplateConfig{
79
 			{
87
 			{
80
 				Source:      optionalVar(envTemplateSourceKey, envTemplateSourceDefault),
88
 				Source:      optionalVar(envTemplateSourceKey, envTemplateSourceDefault),
97
 	}
105
 	}
98
 }
106
 }
99
 
107
 
100
-func createTemplateGenerator(logger *zap.SugaredLogger, templates []model.TemplateConfig) *TemplateGenerator {
108
+func createTemplateGenerator(templates []model.TemplateConfig) *TemplateGenerator {
101
 	templateGenerator := NewTemplateGenerator(logger)
109
 	templateGenerator := NewTemplateGenerator(logger)
102
 	for _, template := range templates {
110
 	for _, template := range templates {
103
 		templateGenerator.AddTemplate(template)
111
 		templateGenerator.AddTemplate(template)
105
 	return templateGenerator
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
 	err := certificateManager.Init(config.Email)
118
 	err := certificateManager.Init(config.Email)
111
 	if err != nil {
119
 	if err != nil {
112
 		panic(err)
120
 		panic(err)
113
 	}
121
 	}
114
-	return certificateManager
115
 }
122
 }
116
 
123
 
117
 func main() {
124
 func main() {
118
-	logger := createLogger()
125
+	logger = createLogger()
119
 	logger.Info("Dotege is starting")
126
 	logger.Info("Dotege is starting")
120
 
127
 
121
 	doneChan := monitorSignals()
128
 	doneChan := monitorSignals()
122
-	config := createConfig()
129
+	createConfig()
123
 
130
 
124
 	dockerStopChan := make(chan struct{})
131
 	dockerStopChan := make(chan struct{})
125
 	dockerClient, err := client.NewEnvClient()
132
 	dockerClient, err := client.NewEnvClient()
127
 		panic(err)
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
 	jitterTimer := time.NewTimer(time.Minute)
140
 	jitterTimer := time.NewTimer(time.Minute)
134
 	redeployTimer := time.NewTicker(time.Hour * 24)
141
 	redeployTimer := time.NewTicker(time.Hour * 24)
135
-	containers := make(map[string]model.Container)
142
+	containers := make(map[string]*model.Container)
136
 
143
 
137
 	go func() {
144
 	go func() {
138
-		err := monitorContainers(dockerClient, dockerStopChan, func(container model.Container) {
145
+		err := monitorContainers(dockerClient, dockerStopChan, func(container *model.Container) {
139
 			containers[container.Name] = container
146
 			containers[container.Name] = container
140
 			jitterTimer.Reset(100 * time.Millisecond)
147
 			jitterTimer.Reset(100 * time.Millisecond)
141
-			err, _ = certificateManager.GetCertificate(getHostnamesForContainer(container, *config))
148
+			deployCertForContainer(container)
142
 		}, func(name string) {
149
 		}, func(name string) {
143
 			delete(containers, name)
150
 			delete(containers, name)
144
 			jitterTimer.Reset(100 * time.Millisecond)
151
 			jitterTimer.Reset(100 * time.Millisecond)
161
 			case <-redeployTimer.C:
168
 			case <-redeployTimer.C:
162
 				logger.Info("Performing periodic certificate refresh")
169
 				logger.Info("Performing periodic certificate refresh")
163
 				for _, container := range containers {
170
 				for _, container := range containers {
164
-					err, _ = certificateManager.GetCertificate(getHostnamesForContainer(container, *config))
171
+					deployCertForContainer(container)
165
 				}
172
 				}
166
 			}
173
 			}
167
 		}
174
 		}
176
 	}
183
 	}
177
 }
184
 }
178
 
185
 
179
-func getHostnamesForContainer(container model.Container, config model.Config) []string {
186
+func getHostnamesForContainer(container *model.Container) []string {
180
 	if label, ok := container.Labels[config.Labels.Hostnames]; ok {
187
 	if label, ok := container.Labels[config.Labels.Hostnames]; ok {
181
 		return strings.Split(strings.Replace(label, ",", " ", -1), " ")
188
 		return strings.Split(strings.Replace(label, ",", " ", -1), " ")
182
 	} else {
189
 	} else {
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
 	hostnames = make(map[string]*model.Hostname)
195
 	hostnames = make(map[string]*model.Hostname)
189
 	for _, container := range containers {
196
 	for _, container := range containers {
190
 		if label, ok := container.Labels[config.Labels.Hostnames]; ok {
197
 		if label, ok := container.Labels[config.Labels.Hostnames]; ok {
195
 				hostnames[names[0]] = &model.Hostname{
202
 				hostnames[names[0]] = &model.Hostname{
196
 					Name:            names[0],
203
 					Name:            names[0],
197
 					Alternatives:    make(map[string]bool),
204
 					Alternatives:    make(map[string]bool),
198
-					Containers:      []model.Container{container},
205
+					Containers:      []*model.Container{container},
199
 					CertActions:     config.DefaultCertActions,
206
 					CertActions:     config.DefaultCertActions,
200
 					CertDestination: config.DefaultCertDestination,
207
 					CertDestination: config.DefaultCertDestination,
201
 				}
208
 				}
216
 		hostname.Alternatives[alternative] = true
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
 type Hostname struct {
44
 type Hostname struct {
45
 	Name            string
45
 	Name            string
46
 	Alternatives    map[string]bool
46
 	Alternatives    map[string]bool
47
-	Containers      []Container
47
+	Containers      []*Container
48
 	CertActions     CertActions
48
 	CertActions     CertActions
49
 	CertDestination string
49
 	CertDestination string
50
 	RequiresAuth    bool
50
 	RequiresAuth    bool

+ 1
- 1
template_generator.go View File

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

Loading…
Cancel
Save