This repository has been archived by the owner on Oct 10, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
183 lines (156 loc) · 4.45 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Command autogcdns provides cli tool to generate letsencrypt certificates
// using DNS-01 challenges for Google Cloud DNS managed zones.
package main
import (
"context"
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"strings"
"time"
"github.com/kenshaw/jwt/gserviceaccount"
"golang.org/x/crypto/acme/autocert"
dns "google.golang.org/api/dns/v2beta1"
"github.com/brankas/autocertdns"
"github.com/brankas/autocertdns/gcdnsp"
)
var (
flagCreds = flag.String("creds", "", "path to credentials")
flagDomain = flag.String("d", "", "domain to generate a certificate for")
flagZone = flag.String("z", "", "managed zone name")
flagCerts = flag.String("certs", "certs", "certificates path")
flagEmail = flag.String("email", "", "registration email account")
flagProject = flag.String("project", "", "project id")
flagWait = flag.Duration("wait", 180*time.Second, "propagation wait")
flagDelay = flag.Duration("delay", 20*time.Second, "provision delay")
flagTimeout = flag.Duration("timeout", 5*time.Minute, "timeout")
)
func main() {
flag.Parse()
ctxt, cancel := context.WithTimeout(context.Background(), *flagTimeout)
defer cancel()
if err := run(ctxt); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
}
func run(ctxt context.Context) error {
// normalize domain and validate domain and creds have been passed
*flagDomain = strings.TrimSuffix(*flagDomain, ".")
if *flagDomain == "" || *flagCreds == "" {
return errors.New("must specify domain and creds")
}
*flagDomain += "."
var err error
// load credentials
buf, err := ioutil.ReadFile(*flagCreds)
if err != nil {
return err
}
// build service account token source
gsa, err := gserviceaccount.FromJSON(buf, gserviceaccount.WithTransport(transportFromEnv()))
if err != nil {
return err
}
// create gsa client
gsaClient, err := gsa.Client(
ctxt,
dns.CloudPlatformScope,
dns.NdevClouddnsReadwriteScope,
)
// create dns service client
dnsService, err := dns.New(gsaClient)
if err != nil {
return err
}
// copy project id if none specified
if *flagProject == "" {
*flagProject = gsa.ProjectID
}
// determine the managed zone name
if *flagZone == "" {
if *flagZone, err = loadZone(ctxt, gsa, dnsService); err != nil {
return err
}
}
// force an email address
if *flagEmail == "" {
*flagEmail = "admin@" + *flagDomain
}
// create provisioner
p, err := gcdnsp.New(
gcdnsp.Domain(*flagDomain),
gcdnsp.ManagedZone(*flagZone),
gcdnsp.ProjectID(*flagProject),
gcdnsp.DNSService(dnsService),
gcdnsp.PropagationWait(*flagWait),
gcdnsp.ProvisionDelay(*flagDelay),
gcdnsp.IgnorePropagationErrors,
gcdnsp.Logf(log.Printf),
gcdnsp.Errorf(func(string, ...interface{}) {}),
)
if err != nil {
return err
}
// ensure directory exists
if err = os.MkdirAll(*flagCerts, 0700); err != nil {
return err
}
// create manager
m := &autocertdns.Manager{
Prompt: autocert.AcceptTOS,
Domain: *flagDomain,
Email: *flagEmail,
CacheDir: *flagCerts,
Provisioner: p,
Logf: log.Printf,
Errorf: func(string, ...interface{}) {},
}
// run
if err = m.Run(ctxt); err != nil {
return err
}
return nil
}
// loadZone determines the managed zone for the provided domain and
// credentials.
func loadZone(ctxt context.Context, gsa *gserviceaccount.GServiceAccount, dnsService *dns.Service) (string, error) {
// list managed zones
res, err := dnsService.ManagedZones.List(*flagProject).Do()
if err != nil {
return "", err
}
if len(res.ManagedZones) == 0 {
return "", fmt.Errorf("no managed zones in project %q", *flagProject)
}
// find the managed zone with the longest dns name matching the domain flag
zone := res.ManagedZones[0]
for _, z := range res.ManagedZones {
if strings.HasSuffix(*flagDomain, zone.DnsName) && len(z.DnsName) > len(zone.DnsName) {
zone = z
}
}
if !strings.HasSuffix(*flagDomain, zone.DnsName) {
return "", fmt.Errorf("can not find the managed zone name in project %q for domain %q", *flagProject, *flagDomain)
}
return zone.Name, nil
}
// transportFromEnv builds a http transport from environment variables, adding
// a HTTP proxy if HTTP_PROXY or HTTPS_PROXY has been set.
func transportFromEnv() http.RoundTripper {
for _, v := range []string{"HTTPS_PROXY", "HTTP_PROXY"} {
if proxy := os.Getenv(v); proxy != "" {
if u, err := url.Parse(proxy); err == nil {
return &http.Transport{
Proxy: http.ProxyURL(u),
}
}
}
}
return nil
}