Browse Source

Support for wildcard domains

master
Chris Smith 5 years ago
parent
commit
232c3ec4f4
3 changed files with 58 additions and 3 deletions
  1. 4
    0
      README.adoc
  2. 15
    0
      config.go
  3. 39
    3
      dotege.go

+ 4
- 0
README.adoc View File

52
 Path to a template to use to generate configuration. Defaults to `./templates/haproxy.cfg.tpl`,
52
 Path to a template to use to generate configuration. Defaults to `./templates/haproxy.cfg.tpl`,
53
 which is a bundled basic template for generating HAProxy configurations.
53
 which is a bundled basic template for generating HAProxy configurations.
54
 
54
 
55
+`DOTEGE_WILDCARD_DOMAINS`::
56
+A space or comma separated list of domains that should use wildcard certificates.
57
+Defaults to an empty list.
58
+
55
 === Docker labels
59
 === Docker labels
56
 
60
 
57
 Dotege operates by parsing labels applied to docker containers. It understands the following:
61
 Dotege operates by parsing labels applied to docker containers. It understands the following:

+ 15
- 0
config.go View File

5
 	"github.com/xenolf/lego/certcrypto"
5
 	"github.com/xenolf/lego/certcrypto"
6
 	"github.com/xenolf/lego/lego"
6
 	"github.com/xenolf/lego/lego"
7
 	"os"
7
 	"os"
8
+	"strings"
8
 )
9
 )
9
 
10
 
10
 const (
11
 const (
25
 	envTemplateDestinationDefault = "/data/output/haproxy.cfg"
26
 	envTemplateDestinationDefault = "/data/output/haproxy.cfg"
26
 	envTemplateSourceKey          = "DOTEGE_TEMPLATE_SOURCE"
27
 	envTemplateSourceKey          = "DOTEGE_TEMPLATE_SOURCE"
27
 	envTemplateSourceDefault      = "./templates/haproxy.cfg.tpl"
28
 	envTemplateSourceDefault      = "./templates/haproxy.cfg.tpl"
29
+	envWildcardDomainsKey         = "DOTEGE_WILDCARD_DOMAINS"
30
+	envWildcardDomainsDefault     = ""
28
 )
31
 )
29
 
32
 
30
 // Config is the user-definable configuration for Dotege.
33
 // Config is the user-definable configuration for Dotege.
34
 	Labels                 LabelConfig
37
 	Labels                 LabelConfig
35
 	DefaultCertDestination string
38
 	DefaultCertDestination string
36
 	Acme                   AcmeConfig
39
 	Acme                   AcmeConfig
40
+	WildCardDomains        []string
37
 }
41
 }
38
 
42
 
39
 // TemplateConfig configures a single template for the generator.
43
 // TemplateConfig configures a single template for the generator.
114
 		},
118
 		},
115
 		Signals:                createSignalConfig(),
119
 		Signals:                createSignalConfig(),
116
 		DefaultCertDestination: optionalVar(envCertDestinationKey, envCertDestinationDefault),
120
 		DefaultCertDestination: optionalVar(envCertDestinationKey, envCertDestinationDefault),
121
+		WildCardDomains:        splitList(optionalVar(envWildcardDomainsKey, envWildcardDomainsDefault)),
117
 	}
122
 	}
118
 }
123
 }
124
+
125
+func splitList(input string) (result []string) {
126
+	result = []string{}
127
+	for _, part := range strings.Split(strings.ReplaceAll(input, " ", ","), ",") {
128
+		if len(part) > 0 {
129
+			result = append(result, part)
130
+		}
131
+	}
132
+	return
133
+}

+ 39
- 3
dotege.go View File

175
 
175
 
176
 func getHostnamesForContainer(container *Container) []string {
176
 func getHostnamesForContainer(container *Container) []string {
177
 	if label, ok := container.Labels[config.Labels.Hostnames]; ok {
177
 	if label, ok := container.Labels[config.Labels.Hostnames]; ok {
178
-		return strings.Split(strings.Replace(label, ",", " ", -1), " ")
178
+		return applyWildcards(splitList(label), config.WildCardDomains)
179
 	} else {
179
 	} else {
180
 		return []string{}
180
 		return []string{}
181
 	}
181
 	}
182
 }
182
 }
183
 
183
 
184
+func applyWildcards(domains []string, wildcards []string) (result []string) {
185
+	result = []string{}
186
+	required := make(map[string]bool)
187
+	for _, domain := range domains {
188
+		found := false
189
+		for _, wildcard := range wildcards {
190
+			if wildcardMatches(wildcard, domain) {
191
+				if !required["*."+wildcard] {
192
+					result = append(result, "*."+wildcard)
193
+					required["*."+wildcard] = true
194
+				}
195
+				found = true
196
+				break
197
+			}
198
+		}
199
+
200
+		if !found && !required[domain] {
201
+			result = append(result, domain)
202
+			required[domain] = true
203
+		}
204
+	}
205
+	return
206
+}
207
+
208
+func wildcardMatches(wildcard, domain string) bool {
209
+	if len(domain) <= len(wildcard) {
210
+		return false
211
+	}
212
+
213
+	pivot := len(domain) - len(wildcard) - 1
214
+	start := domain[:pivot]
215
+	end := domain[pivot+1:]
216
+	return domain[pivot] == '.' && end == wildcard && !strings.ContainsRune(start, '.')
217
+}
218
+
184
 func getHostnames(containers map[string]*Container) (hostnames map[string]*Hostname) {
219
 func getHostnames(containers map[string]*Container) (hostnames map[string]*Hostname) {
185
 	hostnames = make(map[string]*Hostname)
220
 	hostnames = make(map[string]*Hostname)
186
 	for _, container := range containers {
221
 	for _, container := range containers {
187
 		if label, ok := container.Labels[config.Labels.Hostnames]; ok {
222
 		if label, ok := container.Labels[config.Labels.Hostnames]; ok {
188
-			names := strings.Split(strings.Replace(label, ",", " ", -1), " ")
223
+			names := splitList(label)
189
 			if hostname, ok := hostnames[names[0]]; ok {
224
 			if hostname, ok := hostnames[names[0]]; ok {
190
 				hostname.Containers = append(hostname.Containers, container)
225
 				hostname.Containers = append(hostname.Containers, container)
191
 			} else {
226
 			} else {
230
 }
265
 }
231
 
266
 
232
 func deployCert(certificate *SavedCertificate) bool {
267
 func deployCert(certificate *SavedCertificate) bool {
233
-	target := path.Join(config.DefaultCertDestination, fmt.Sprintf("%s.pem", certificate.Domains[0]))
268
+	name := fmt.Sprintf("%s.pem", strings.ReplaceAll("*", "_", certificate.Domains[0]))
269
+	target := path.Join(config.DefaultCertDestination, name)
234
 	content := append(certificate.Certificate, certificate.PrivateKey...)
270
 	content := append(certificate.Certificate, certificate.PrivateKey...)
235
 
271
 
236
 	buf, _ := ioutil.ReadFile(target)
272
 	buf, _ := ioutil.ReadFile(target)

Loading…
Cancel
Save