Skip to content

Commit b38ddb7

Browse files
Support for more DNS providers for the SSL certificate challenges (lucasdillmann#20)
1 parent eb8f7eb commit b38ddb7

172 files changed

Lines changed: 10510 additions & 364 deletions

File tree

Some content is hidden

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

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
*.dylib
77
*.test
88
*.out
9-
build/*
109

1110
# Dependency directories and files
1211
vendor/
@@ -19,3 +18,4 @@ vendor/
1918
*.iml
2019
.idea/
2120
.qodo
21+
build/

api/go.mod

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.25.1
44

55
require (
66
github.com/aws/smithy-go v1.23.0
7-
github.com/gin-gonic/gin v1.10.1
7+
github.com/gin-gonic/gin v1.11.0
88
github.com/go-playground/validator/v10 v10.27.0
99
github.com/golang-jwt/jwt/v5 v5.3.0
1010
github.com/google/uuid v1.6.0
@@ -22,25 +22,27 @@ require (
2222
github.com/go-playground/locales v0.14.1 // indirect
2323
github.com/go-playground/universal-translator v0.18.1 // indirect
2424
github.com/goccy/go-json v0.10.5 // indirect
25+
github.com/goccy/go-yaml v1.18.0 // indirect
2526
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect
2627
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
27-
github.com/kr/pretty v0.3.1 // indirect
2828
github.com/leodido/go-urn v1.4.0 // indirect
2929
github.com/mattn/go-isatty v0.0.20 // indirect
3030
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
3131
github.com/modern-go/reflect2 v1.0.2 // indirect
3232
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
3333
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
34-
github.com/rogpeppe/go-internal v1.14.1 // indirect
35-
github.com/stretchr/testify v1.11.1 // indirect
34+
github.com/quic-go/qpack v0.5.1 // indirect
35+
github.com/quic-go/quic-go v0.55.0 // indirect
3636
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
3737
github.com/ugorji/go/codec v1.3.0 // indirect
38+
go.uber.org/mock v0.6.0 // indirect
3839
golang.org/x/arch v0.21.0 // indirect
3940
golang.org/x/crypto v0.42.0 // indirect
41+
golang.org/x/mod v0.28.0 // indirect
4042
golang.org/x/net v0.44.0 // indirect
43+
golang.org/x/sync v0.17.0 // indirect
4144
golang.org/x/sys v0.36.0 // indirect
4245
golang.org/x/text v0.29.0 // indirect
43-
google.golang.org/protobuf v1.36.9 // indirect
44-
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
45-
gopkg.in/yaml.v3 v3.0.1 // indirect
46+
golang.org/x/tools v0.37.0 // indirect
47+
google.golang.org/protobuf v1.36.10 // indirect
4648
)

certificate/letsencrypt/acme_facade.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ func issueCertificate(
4141
return nil, err
4242
}
4343

44-
dnsChallengeProvider, err := resolveDnsProvider(ctx, domainNames, parameters)
44+
dnsChallenge, err := resolveProviderChallenge(ctx, domainNames, parameters)
4545
if err != nil {
4646
return nil, err
4747
}
4848

4949
client.Challenge.Remove(challenge.TLSALPN01)
5050
client.Challenge.Remove(challenge.HTTP01)
51-
err = client.Challenge.SetDNS01Provider(dnsChallengeProvider)
51+
err = client.Challenge.SetDNS01Provider(dnsChallenge)
5252
if err != nil {
5353
return nil, err
5454
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package acmedns
2+
3+
import (
4+
"context"
5+
"strings"
6+
7+
"github.com/aws/smithy-go/ptr"
8+
"github.com/go-acme/lego/v4/challenge"
9+
legoacmedns "github.com/go-acme/lego/v4/providers/dns/acmedns"
10+
11+
"dillmann.com.br/nginx-ignition/certificate/letsencrypt/dns"
12+
"dillmann.com.br/nginx-ignition/core/common/dynamic_fields"
13+
)
14+
15+
const (
16+
apiBaseFieldID = "acmednsApiBase"
17+
allowListFieldID = "acmednsAllowList"
18+
storagePathFieldID = "acmednsStoragePath"
19+
storageBaseURLFieldID = "acmednsStorageBaseURL"
20+
)
21+
22+
type Provider struct{}
23+
24+
func (p *Provider) ID() string { return "ACME_DNS" }
25+
26+
func (p *Provider) Name() string { return "ACME-DNS" }
27+
28+
func (p *Provider) DynamicFields() []*dynamic_fields.DynamicField {
29+
return dns.LinkedToProvider(p.ID(), []dynamic_fields.DynamicField{
30+
{
31+
ID: apiBaseFieldID,
32+
Description: "ACME-DNS API base (e.g., https://acmedns.example.com)",
33+
Required: true,
34+
Type: dynamic_fields.SingleLineTextType,
35+
},
36+
{
37+
ID: allowListFieldID,
38+
Description: "Comma-separated list of CIDR sources allowed to update (optional)",
39+
Type: dynamic_fields.SingleLineTextType,
40+
},
41+
{
42+
ID: storagePathFieldID,
43+
Description: "Local storage file path for ACME-DNS accounts",
44+
HelpText: ptr.String("Mutually exclusive with storage base URL"),
45+
Type: dynamic_fields.SingleLineTextType,
46+
},
47+
{
48+
ID: storageBaseURLFieldID,
49+
Description: "Remote storage base URL for ACME-DNS accounts",
50+
HelpText: ptr.String("Mutually exclusive with storage path"),
51+
Type: dynamic_fields.SingleLineTextType,
52+
},
53+
})
54+
}
55+
56+
func (p *Provider) ChallengeProvider(
57+
_ context.Context,
58+
_ []string,
59+
parameters map[string]any,
60+
) (challenge.Provider, error) {
61+
apiBase, _ := parameters[apiBaseFieldID].(string)
62+
allowListStr, _ := parameters[allowListFieldID].(string)
63+
storagePath, _ := parameters[storagePathFieldID].(string)
64+
storageBaseURL, _ := parameters[storageBaseURLFieldID].(string)
65+
66+
cfg := &legoacmedns.Config{
67+
APIBase: apiBase,
68+
StoragePath: storagePath,
69+
StorageBaseURL: storageBaseURL,
70+
}
71+
72+
if allowListStr != "" {
73+
var list []string
74+
for _, raw := range strings.Split(allowListStr, ",") {
75+
trimmedValue := strings.TrimSpace(raw)
76+
if trimmedValue != "" {
77+
list = append(list, trimmedValue)
78+
}
79+
}
80+
81+
cfg.AllowList = list
82+
}
83+
84+
return legoacmedns.NewDNSProviderConfig(cfg)
85+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package active24
2+
3+
import (
4+
"context"
5+
6+
"github.com/go-acme/lego/v4/challenge"
7+
"github.com/go-acme/lego/v4/providers/dns/active24"
8+
9+
"dillmann.com.br/nginx-ignition/certificate/letsencrypt/dns"
10+
"dillmann.com.br/nginx-ignition/core/common/dynamic_fields"
11+
)
12+
13+
const (
14+
apiKeyFieldID = "active24ApiKey"
15+
secretFieldID = "active24Secret"
16+
)
17+
18+
type Provider struct{}
19+
20+
func (p *Provider) ID() string { return "ACTIVE24" }
21+
22+
func (p *Provider) Name() string { return "Active24" }
23+
24+
func (p *Provider) DynamicFields() []*dynamic_fields.DynamicField {
25+
return dns.LinkedToProvider(p.ID(), []dynamic_fields.DynamicField{
26+
{
27+
ID: apiKeyFieldID,
28+
Description: "Active24 API key",
29+
Required: true,
30+
Sensitive: true,
31+
Type: dynamic_fields.SingleLineTextType,
32+
},
33+
{
34+
ID: secretFieldID,
35+
Description: "Active24 secret",
36+
Required: true,
37+
Sensitive: true,
38+
Type: dynamic_fields.SingleLineTextType,
39+
},
40+
})
41+
}
42+
43+
func (p *Provider) ChallengeProvider(
44+
_ context.Context,
45+
_ []string,
46+
parameters map[string]any,
47+
) (challenge.Provider, error) {
48+
apiKey, _ := parameters[apiKeyFieldID].(string)
49+
secret, _ := parameters[secretFieldID].(string)
50+
51+
cfg := &active24.Config{
52+
APIKey: apiKey,
53+
Secret: secret,
54+
TTL: dns.TTL,
55+
PropagationTimeout: dns.PropagationTimeout,
56+
PollingInterval: dns.PollingInterval,
57+
}
58+
59+
return active24.NewDNSProviderConfig(cfg)
60+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package alibaba
2+
3+
import (
4+
"context"
5+
6+
"github.com/go-acme/lego/v4/challenge"
7+
"github.com/go-acme/lego/v4/providers/dns/alidns"
8+
9+
"dillmann.com.br/nginx-ignition/certificate/letsencrypt/dns"
10+
"dillmann.com.br/nginx-ignition/core/common/dynamic_fields"
11+
)
12+
13+
const (
14+
accessKeyFieldID = "alibabaAccessKeyId"
15+
accessKeySecretFieldID = "alibabaAccessKeySecret"
16+
securityTokenFieldID = "alibabaSecurityToken"
17+
regionFieldID = "alibabaRegion"
18+
ramRoleFieldID = "alibabaRamRole"
19+
)
20+
21+
type Provider struct{}
22+
23+
func (p *Provider) ID() string { return "ALIBABA" }
24+
25+
func (p *Provider) Name() string { return "Alibaba" }
26+
27+
func (p *Provider) DynamicFields() []*dynamic_fields.DynamicField {
28+
return dns.LinkedToProvider(p.ID(), []dynamic_fields.DynamicField{
29+
{
30+
ID: accessKeyFieldID,
31+
Description: "Alibaba Cloud access key ID",
32+
Required: true,
33+
Type: dynamic_fields.SingleLineTextType,
34+
},
35+
{
36+
ID: accessKeySecretFieldID,
37+
Description: "Alibaba Cloud access key secret",
38+
Required: true,
39+
Sensitive: true,
40+
Type: dynamic_fields.SingleLineTextType,
41+
},
42+
{
43+
ID: securityTokenFieldID,
44+
Description: "Alibaba Cloud security token",
45+
Sensitive: true,
46+
Type: dynamic_fields.SingleLineTextType,
47+
},
48+
{
49+
ID: regionFieldID,
50+
Description: "Alibaba Cloud region",
51+
Type: dynamic_fields.SingleLineTextType,
52+
},
53+
{
54+
ID: ramRoleFieldID,
55+
Description: "Alibaba Cloud RAM role",
56+
Type: dynamic_fields.SingleLineTextType,
57+
},
58+
})
59+
}
60+
61+
func (p *Provider) ChallengeProvider(
62+
_ context.Context,
63+
_ []string,
64+
parameters map[string]any,
65+
) (challenge.Provider, error) {
66+
accessKey, _ := parameters[accessKeyFieldID].(string)
67+
accessSecret, _ := parameters[accessKeySecretFieldID].(string)
68+
securityToken, _ := parameters[securityTokenFieldID].(string)
69+
region, _ := parameters[regionFieldID].(string)
70+
role, _ := parameters[ramRoleFieldID].(string)
71+
72+
cfg := &alidns.Config{
73+
RAMRole: role,
74+
APIKey: accessKey,
75+
SecretKey: accessSecret,
76+
SecurityToken: securityToken,
77+
RegionID: region,
78+
PropagationTimeout: dns.PropagationTimeout,
79+
PollingInterval: dns.PollingInterval,
80+
TTL: dns.TTL,
81+
}
82+
83+
return alidns.NewDNSProviderConfig(cfg)
84+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package allinkl
2+
3+
import (
4+
"context"
5+
6+
"github.com/go-acme/lego/v4/challenge"
7+
"github.com/go-acme/lego/v4/providers/dns/allinkl"
8+
9+
"dillmann.com.br/nginx-ignition/certificate/letsencrypt/dns"
10+
"dillmann.com.br/nginx-ignition/core/common/dynamic_fields"
11+
)
12+
13+
const (
14+
loginFieldID = "allInklLogin"
15+
passwordFieldID = "allInklPassword"
16+
)
17+
18+
type Provider struct{}
19+
20+
func (p *Provider) ID() string { return "ALL_INKL" }
21+
22+
func (p *Provider) Name() string { return "ALL-INKL" }
23+
24+
func (p *Provider) DynamicFields() []*dynamic_fields.DynamicField {
25+
return dns.LinkedToProvider(p.ID(), []dynamic_fields.DynamicField{
26+
{
27+
ID: loginFieldID,
28+
Description: "ALL-INKL login",
29+
Required: true,
30+
Type: dynamic_fields.SingleLineTextType,
31+
},
32+
{
33+
ID: passwordFieldID,
34+
Description: "ALL-INKL password",
35+
Required: true,
36+
Sensitive: true,
37+
Type: dynamic_fields.SingleLineTextType,
38+
},
39+
})
40+
}
41+
42+
func (p *Provider) ChallengeProvider(
43+
_ context.Context,
44+
_ []string,
45+
parameters map[string]any,
46+
) (challenge.Provider, error) {
47+
login, _ := parameters[loginFieldID].(string)
48+
password, _ := parameters[passwordFieldID].(string)
49+
50+
cfg := &allinkl.Config{
51+
Login: login,
52+
Password: password,
53+
TTL: dns.TTL,
54+
PropagationTimeout: dns.PropagationTimeout,
55+
PollingInterval: dns.PollingInterval,
56+
}
57+
58+
return allinkl.NewDNSProviderConfig(cfg)
59+
}

0 commit comments

Comments
 (0)