Skip to content

Commit ad3f748

Browse files
authored
Merge pull request #11 from pkg6/deploy
Deploy
2 parents 57190b5 + 1043d18 commit ad3f748

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1789
-132
lines changed

.cli/elego/main.go

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ type Flags struct {
2121
HttpWebroot elego.HTTPWebrootChallenge
2222
DNS elego.DNSChallenge
2323

24-
Path string
24+
Deploy string
25+
Path string
2526
}
2627

2728
var (
@@ -49,6 +50,8 @@ func init() {
4950

5051
flag.StringVar(&args.DNS.DNS, "dns", "", "Enter your DNS name, please refer to https://go-acme.github.io/lego/dns/index.html")
5152

53+
flag.StringVar(&args.Deploy, "deploy", "local", "Where do you want to deploy your certificate")
54+
5255
flag.StringVar(&args.Path, "path", "/etc/nginx/ssl/", "Path for saving certificates")
5356
}
5457
func main() {
@@ -60,26 +63,29 @@ func main() {
6063
log.Fatal("Need to set either --dns or --webroot")
6164
}
6265
log.Printf("Accepted data : %#v", args)
63-
6466
if strings.HasPrefix(args.Domain, "*") {
6567
//https://github.com/go-acme/lego/issues/1867
6668
_ = os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", strconv.FormatBool(true))
6769
}
68-
certificatesStorage, err := elego.NewCertificatesStorage(args.CachePath, "RC2")
70+
sanitizedDomain, err := elego.SanitizedDomain(args.Domain)
6971
if err != nil {
70-
log.Fatal(err)
72+
log.Fatal(fmt.Errorf("sanitizing domain: %v", err))
7173
}
72-
day, err := certificatesStorage.CheckExpire(args.Domain)
74+
cStorage, err := elego.NewCertificatesStorage(args.CachePath, "RC2")
75+
if err != nil {
76+
log.Fatal(fmt.Errorf("error creating certificates storage: %v", err))
77+
}
78+
day, err := cStorage.CheckExpire(args.Domain)
7379
if day > 0 && args.Force == false {
7480
log.Printf("%s will expire in %.0f days", args.Domain, day)
81+
savePath, _ := cStorage.GetSavePath(args.Domain)
82+
log.Printf("we will back up the data in the %s directory", savePath)
7583
return
7684
}
77-
78-
accountStorage, err := elego.NewAccountsStorage(args.CachePath, args.Email, args.CADirURL)
85+
aStorage, err := elego.NewAccountsStorage(args.CachePath, args.Email, args.CADirURL)
7986
if err != nil {
80-
log.Fatal(err)
87+
log.Fatal(fmt.Errorf("error creating accounts storage: %v", err))
8188
}
82-
8389
var register elego.IRegister
8490
kid := os.Getenv("ELEGO_REGISTER_KID")
8591
hmacEncoded := os.Getenv("ELEGO_REGISTER_HMAC")
@@ -92,9 +98,9 @@ func main() {
9298
} else {
9399
register = &elego.Register{}
94100
}
95-
_, client, err := elego.NewLegoClient(accountStorage, register)
101+
_, client, err := elego.NewLegoClient(aStorage, register)
96102
if err != nil {
97-
log.Fatal(err)
103+
log.Fatal(fmt.Errorf("error creating lego client: %w", err))
98104
}
99105
if args.DNS.DNS != "" {
100106
err = elego.SetChallenge(client, &args.DNS)
@@ -104,19 +110,29 @@ func main() {
104110
err = fmt.Errorf("we are working hard to support other ways")
105111
}
106112
if err != nil {
107-
log.Fatal(err)
113+
log.Fatal(fmt.Errorf("elego SetChallenge: %w", err))
108114
}
109115
certificate, err := elego.ObtainCertificate(client, []string{args.Domain})
110116
if err != nil {
111-
log.Fatal(err)
117+
log.Fatal(fmt.Errorf("error obtaining certificate: %w", err))
112118
}
113-
if err := certificatesStorage.SaveResource(certificate); err != nil {
114-
log.Fatal(err)
119+
if err := cStorage.SaveResource(certificate); err != nil {
120+
log.Fatal(fmt.Errorf("error saving certificate: %w", err))
115121
}
116-
cerPath, keyPath, err := certificatesStorage.SaveNginx(args.Path, args.Domain)
122+
resource, err := cStorage.ReadResource(args.Domain)
117123
if err != nil {
118124
log.Fatal(err)
119125
}
120-
log.Printf("save key: %s", keyPath)
121-
log.Printf("save cer: %s", cerPath)
126+
switch args.Deploy {
127+
case "local":
128+
keyPath := path.Join(args.Path, fmt.Sprintf("%s%s", sanitizedDomain, elego.PemExt))
129+
_ = os.Setenv("LOCAL_CERT_PATH", keyPath)
130+
cerPath := path.Join(args.Path, fmt.Sprintf("%s%s", sanitizedDomain, elego.KeyExt))
131+
_ = os.Setenv("LOCAL_KEY_PATH", cerPath)
132+
break
133+
}
134+
if err := elego.Deploy(args.Deploy, resource); err != nil {
135+
log.Fatal(fmt.Errorf("error deploying certificate: %w", err))
136+
}
137+
log.Printf("You successfully deployed your number through %s deployment method", args.Deploy)
122138
}

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ go.work.sum
2626

2727
/.idea
2828
/ssl
29-
coverage.txt
29+
coverage.txt
30+
elego

Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
TAG_VERSION := $(shell git describe --tags --always)
22

3+
build:
4+
go build -ldflags='-s -w -X main.TAG_version=${TAG_VERSION}' -o elego ./.cli/elego/main.go
5+
36
check:
47
go install github.com/golangci/golangci-lint/cmd/[email protected]
58
golangci-lint run ./...
69

710
test:
811
go test -v -coverpkg=./... -race -covermode=atomic -coverprofile=coverage.txt ./... -run . -timeout=2m
912

10-
build:
11-
go build -ldflags='-s -w -X main.TAG_version=${TAG_VERSION}' -o elego ./.cli/elego/main.go
13+
1214

certificates_storage.go

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"github.com/go-acme/lego/v4/certificate"
1313
"golang.org/x/net/idna"
1414
"os"
15-
"path"
1615
"path/filepath"
1716
"software.sslmate.com/src/go-pkcs12"
1817
"strings"
@@ -74,26 +73,6 @@ func (s *CertificatesStorage) CheckExpire(inputDomain string) (day float64, err
7473
return day, errors.New("certificate not found")
7574
}
7675

77-
func (s *CertificatesStorage) SaveNginx(nginxPath, domain string) (certificate, privateKey string, err error) {
78-
resource, err := s.ReadResource(domain)
79-
if err != nil {
80-
return "", "", err
81-
}
82-
sanitizedDomain, err := SanitizedDomain(resource.Domain)
83-
if err != nil {
84-
return "", "", err
85-
}
86-
certificate = path.Join(nginxPath, fmt.Sprintf("%s%s", sanitizedDomain, PemExt))
87-
privateKey = path.Join(nginxPath, fmt.Sprintf("%s%s", sanitizedDomain, KeyExt))
88-
if err := CopyFile(resource.Certificate, certificate); err != nil {
89-
return certificate, privateKey, fmt.Errorf("save nginx certificate: %w", err)
90-
}
91-
if err := CopyFile(resource.PrivateKey, privateKey); err != nil {
92-
return certificate, privateKey, fmt.Errorf("save nginx private key: %w", err)
93-
}
94-
return certificate, privateKey, nil
95-
}
96-
9776
func (s *CertificatesStorage) ReadCertificate(domain string) ([]*x509.Certificate, error) {
9877
sanitizedDomain, err := SanitizedDomain(domain)
9978
if err != nil {
@@ -159,9 +138,6 @@ func (s *CertificatesStorage) SaveResource(certRes *certificate.Resource) error
159138
}
160139
return s.writeFile(sanitizedDomain, ResourceExt, jsonBytes)
161140
}
162-
func (s *CertificatesStorage) readFile(sanitizedDomain, extension string) ([]byte, error) {
163-
return os.ReadFile(filepath.Join(s.rootPath, sanitizedDomain, sanitizedDomain+extension))
164-
}
165141

166142
func (s *CertificatesStorage) writeCertificateFiles(domain string, certRes *certificate.Resource) error {
167143
sanitizedDomain, err := SanitizedDomain(domain)
@@ -225,13 +201,28 @@ func (s *CertificatesStorage) writePFXFile(domain string, certRes *certificate.R
225201
return s.writeFile(domain, PfxExt, pfxBytes)
226202
}
227203

204+
func (s *CertificatesStorage) GetSavePath(domain string) (string, error) {
205+
sanitizedDomain, err := SanitizedDomain(domain)
206+
if err != nil {
207+
return "", err
208+
}
209+
return filepath.Join(s.rootPath, sanitizedDomain), nil
210+
}
211+
228212
func (s *CertificatesStorage) createPath(sanitizedDomain string) error {
229213
return CreateNonExistingFolder(filepath.Join(s.rootPath, sanitizedDomain))
230214
}
231215

216+
func (s *CertificatesStorage) SanitizedDomainSavePath(sanitizedDomain, extension string) string {
217+
return filepath.Join(s.rootPath, sanitizedDomain, sanitizedDomain+extension)
218+
}
219+
220+
func (s *CertificatesStorage) readFile(sanitizedDomain, extension string) ([]byte, error) {
221+
return os.ReadFile(s.SanitizedDomainSavePath(sanitizedDomain, extension))
222+
}
223+
232224
func (s *CertificatesStorage) writeFile(sanitizedDomain, extension string, data []byte) error {
233-
fileName := filepath.Join(s.rootPath, sanitizedDomain, sanitizedDomain+extension)
234-
return os.WriteFile(fileName, data, filePerm)
225+
return os.WriteFile(s.SanitizedDomainSavePath(sanitizedDomain, extension), data, filePerm)
235226
}
236227

237228
func (s *CertificatesStorage) getPFXEncoder(pfxFormat string) (*pkcs12.Encoder, error) {

certificates_storage_test.go

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -119,48 +119,6 @@ func TestCertificatesStorage_ReadResource(t *testing.T) {
119119
}
120120
}
121121

122-
func TestCertificatesStorage_SaveNginx(t *testing.T) {
123-
type fields struct {
124-
rootPath string
125-
pfxFormat string
126-
pfxPassword string
127-
}
128-
type args struct {
129-
nginxPath string
130-
domain string
131-
}
132-
tests := []struct {
133-
name string
134-
fields fields
135-
args args
136-
wantCertificate string
137-
wantPrivateKey string
138-
wantErr bool
139-
}{
140-
// TODO: Add test cases.
141-
}
142-
for _, tt := range tests {
143-
t.Run(tt.name, func(t *testing.T) {
144-
s := &CertificatesStorage{
145-
rootPath: tt.fields.rootPath,
146-
pfxFormat: tt.fields.pfxFormat,
147-
pfxPassword: tt.fields.pfxPassword,
148-
}
149-
gotCertificate, gotPrivateKey, err := s.SaveNginx(tt.args.nginxPath, tt.args.domain)
150-
if (err != nil) != tt.wantErr {
151-
t.Errorf("SaveNginx() error = %v, wantErr %v", err, tt.wantErr)
152-
return
153-
}
154-
if gotCertificate != tt.wantCertificate {
155-
t.Errorf("SaveNginx() gotCertificate = %v, want %v", gotCertificate, tt.wantCertificate)
156-
}
157-
if gotPrivateKey != tt.wantPrivateKey {
158-
t.Errorf("SaveNginx() gotPrivateKey = %v, want %v", gotPrivateKey, tt.wantPrivateKey)
159-
}
160-
})
161-
}
162-
}
163-
164122
func TestCertificatesStorage_SaveResource(t *testing.T) {
165123
type fields struct {
166124
rootPath string

deploy.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package elego
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/go-acme/lego/v4/certificate"
7+
"github.com/pkg6/elego/deploy"
8+
"github.com/pkg6/elego/log"
9+
"os"
10+
"path"
11+
"path/filepath"
12+
)
13+
14+
func Deploy(name string, certificate *certificate.Resource) error {
15+
envDeploy, err := deploy.Get(name)
16+
if err != nil {
17+
log.Fatalf("deployment failed %d", err)
18+
return err
19+
}
20+
return envDeploy.Deploy(context.Background(), certificate)
21+
}
22+
23+
func DeployNginx(s *CertificatesStorage, nginxPath, domain string) (certificate, privateKey string, err error) {
24+
writeFile := func(path string, content []byte) error {
25+
dir := filepath.Dir(path)
26+
err := os.MkdirAll(dir, os.ModePerm)
27+
if err != nil {
28+
return fmt.Errorf("failed to create directory: %w", err)
29+
}
30+
file, err := os.Create(path)
31+
if err != nil {
32+
return fmt.Errorf("failed to create file: %w", err)
33+
}
34+
defer file.Close()
35+
_, err = file.Write(content)
36+
if err != nil {
37+
return fmt.Errorf("fail to write to file: %w", err)
38+
}
39+
return nil
40+
}
41+
resource, err := s.ReadResource(domain)
42+
if err != nil {
43+
return "", "", err
44+
}
45+
sanitizedDomain, err := SanitizedDomain(resource.Domain)
46+
if err != nil {
47+
return "", "", err
48+
}
49+
certificate = path.Join(nginxPath, fmt.Sprintf("%s%s", sanitizedDomain, PemExt))
50+
privateKey = path.Join(nginxPath, fmt.Sprintf("%s%s", sanitizedDomain, KeyExt))
51+
if err := writeFile(certificate, resource.Certificate); err != nil {
52+
return certificate, privateKey, fmt.Errorf("save nginx certificate: %w", err)
53+
}
54+
if err := writeFile(privateKey, resource.PrivateKey); err != nil {
55+
return certificate, privateKey, fmt.Errorf("save nginx private key: %w", err)
56+
}
57+
return certificate, privateKey, nil
58+
}

deploy/aliyuncdn/config.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package aliyuncdn
2+
3+
type Config struct {
4+
// 阿里云 AccessKeyId。
5+
AccessKeyId string `json:"access_key_id,omitempty" yml:"AccessKeyId" xml:"AccessKeyId" env:"ALIYUNCDN_ACCESS_KEY_ID"`
6+
// 阿里云 AccessKeySecret。
7+
AccessKeySecret string `json:"access_key_secret,omitempty" yaml:"AccessKeySecret" xml:"AccessKeySecret" env:"ALIYUNCDN_ACCESS_KEY_SECRET"`
8+
// 加速域名(支持泛域名)。
9+
Domain string `json:"domain,omitempty" yaml:"Domain" xml:"Domain" env:"ALIYUNCDN_DOMAIN"`
10+
}

deploy/aliyuncdn/deploy.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package aliyuncdn
2+
3+
import (
4+
"context"
5+
"fmt"
6+
aliyunCdn "github.com/alibabacloud-go/cdn-20180510/v5/client"
7+
"github.com/alibabacloud-go/tea/tea"
8+
"github.com/caarlos0/env/v11"
9+
"github.com/go-acme/lego/v4/certificate"
10+
"github.com/pkg/errors"
11+
"github.com/pkg6/elego/log"
12+
"strings"
13+
"time"
14+
)
15+
16+
type Deploy struct {
17+
Config *Config
18+
logger log.ILogger
19+
}
20+
21+
func (d *Deploy) WithLogger(logger log.ILogger) {
22+
d.logger = logger
23+
}
24+
25+
func (d *Deploy) WithEnvConfig() error {
26+
var cfg Config
27+
err := env.Parse(&cfg)
28+
if err != nil {
29+
return err
30+
}
31+
d.Config = &cfg
32+
return nil
33+
}
34+
35+
func (d *Deploy) Deploy(ctx context.Context, certificate *certificate.Resource) error {
36+
domain := strings.TrimPrefix(d.Config.Domain, "*")
37+
client, err := newClient(d.Config.AccessKeyId, d.Config.AccessKeySecret)
38+
if err != nil {
39+
return errors.Wrap(err, "failed to create sdk client")
40+
}
41+
setCdnDomainSSLCertificateReq := &aliyunCdn.SetCdnDomainSSLCertificateRequest{
42+
DomainName: tea.String(domain),
43+
CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
44+
CertType: tea.String("upload"),
45+
SSLProtocol: tea.String("on"),
46+
SSLPub: tea.String(string(certificate.Certificate)),
47+
SSLPri: tea.String(string(certificate.PrivateKey)),
48+
}
49+
setCdnDomainSSLCertificateResp, err := client.SetCdnDomainSSLCertificate(setCdnDomainSSLCertificateReq)
50+
if err != nil {
51+
return errors.Wrap(err, "failed to execute sdk request 'cdn.SetCdnDomainSSLCertificate'")
52+
}
53+
d.logger.Printf("已设置 CDN 域名证书 %+v", setCdnDomainSSLCertificateResp)
54+
return nil
55+
}

0 commit comments

Comments
 (0)