-
Notifications
You must be signed in to change notification settings - Fork 1
/
letsencryptseprovider.go
129 lines (115 loc) · 3.42 KB
/
letsencryptseprovider.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
package letsencrypts3provider
import (
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"regexp"
"strings"
"github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/certificate"
"github.com/go-acme/lego/v4/lego"
"github.com/go-acme/lego/v4/registration"
)
const (
stagingDirectoryURL = lego.LEDirectoryStaging
directoryURL = lego.LEDirectoryProduction
RootDST = "DST Root CA X3"
RootISRG = "ISRG Root X1"
)
var helpReg = regexp.MustCompile(`^--?h(?:elp)?$`)
func help() string {
return "Usage: go-letsencrypt-s3provider {email} {domain1,domain2,..} {production|staging} {out privatekey} {out cert}"
}
// Run the letsencrypts3provider cli
func Run(argv []string, stdout, stderr io.Writer) error {
if len(argv) != 5 || helpReg.MatchString(argv[0]) {
fmt.Fprintln(stdout, help())
}
log.SetFlags(log.Lmicroseconds | log.Lshortfile)
email := argv[0]
domains := strings.Split(argv[1], ",")
directory := argv[2]
privkeyFile := argv[3]
certFile := argv[4]
if directory == "production" {
directory = directoryURL
} else {
directory = stagingDirectoryURL
}
bucket := os.Getenv("AWS_LETSENCRYPT_S3PROVIDER_BUCKET")
if bucket == "" {
return fmt.Errorf("AWS_LETSENCRYPT_S3PROVIDER_BUCKET required")
}
certificates, err := Obtain(&ObtainRequest{
Domains: domains,
Directory: directory,
Email: email,
Bucket: bucket,
})
if err != nil {
return err
}
if err := ioutil.WriteFile(privkeyFile, certificates.PrivateKey, 0644); err != nil {
return err
}
return ioutil.WriteFile(certFile, certificates.Certificate, 0644)
}
type ObtainRequest struct {
Domains []string
Directory string
Email string
Bucket string
Bundle, MustStaple bool
PreferredChain string
}
// Obtain server key and certificates
func Obtain(ob *ObtainRequest) (*certificate.Resource, error) {
u, err := newUser(ob.Email)
if err != nil {
return nil, fmt.Errorf("Failed to NewUser, error: %s", err)
}
directory := ob.Directory
if directory == "" {
directory = directoryURL
}
// A client facilitates communication with the CA server.
client, err := lego.NewClient(&lego.Config{
HTTPClient: http.DefaultClient,
CADirURL: directory,
User: u,
Certificate: lego.CertificateConfig{
KeyType: certcrypto.RSA2048,
},
})
if err != nil {
return nil, fmt.Errorf("Failed to NewClient, error: %s", err)
}
// New users will need to register
if _, err := client.Registration.Register(registration.RegisterOptions{
// The client has a URL to the current Let's Encrypt Subscriber
// Agreement. The user will need to agree to it.
TermsOfServiceAgreed: true,
}); err != nil {
return nil, fmt.Errorf("Failed to Register, error: %s", err)
}
provider, err := newS3UploadingProvider(ob.Bucket)
if err != nil {
return nil, fmt.Errorf("Failed to NewS3UploadingPrivider: %w", err)
}
// We only use HTTP01
if err := client.Challenge.SetHTTP01Provider(provider); err != nil {
return nil, fmt.Errorf("Failed to SetChallengeProvider failed, error: %s", err)
}
return client.Certificate.Obtain(certificate.ObtainRequest{
Domains: ob.Domains,
// The acme library takes care of completing the challenges to obtain the certificate(s).
// The domains must resolve to this machine or you have to use the DNS challenge.
Bundle: ob.Bundle,
// ELB doesn't support OCSP stapling
MustStaple: ob.MustStaple,
PreferredChain: ob.PreferredChain,
})
}