mirror of
https://github.com/go-acme/lego
synced 2026-03-14 14:35:48 +01:00
otc: adds option to use private zone (#2649)
Co-authored-by: Fernandez Ludovic <ldez@users.noreply.github.com>
This commit is contained in:
parent
0d567188f6
commit
bf0e89cdd9
7 changed files with 85 additions and 21 deletions
3
cmd/zz_gen_cmd_dnshelp.go
generated
3
cmd/zz_gen_cmd_dnshelp.go
generated
|
|
@ -2572,7 +2572,6 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
|
||||
ew.writeln(`Credentials:`)
|
||||
ew.writeln(` - "OTC_DOMAIN_NAME": Domain name`)
|
||||
ew.writeln(` - "OTC_IDENTITY_ENDPOINT": Identity endpoint URL`)
|
||||
ew.writeln(` - "OTC_PASSWORD": Password`)
|
||||
ew.writeln(` - "OTC_PROJECT_NAME": Project name`)
|
||||
ew.writeln(` - "OTC_USER_NAME": User name`)
|
||||
|
|
@ -2580,7 +2579,9 @@ func displayDNSHelp(w io.Writer, name string) error {
|
|||
|
||||
ew.writeln(`Additional Configuration:`)
|
||||
ew.writeln(` - "OTC_HTTP_TIMEOUT": API request timeout in seconds (Default: 10)`)
|
||||
ew.writeln(` - "OTC_IDENTITY_ENDPOINT": Identity endpoint URL`)
|
||||
ew.writeln(` - "OTC_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
|
||||
ew.writeln(` - "OTC_PRIVATE_ZONE": Set to true to use private zones only (default: use public zones only)`)
|
||||
ew.writeln(` - "OTC_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
|
||||
ew.writeln(` - "OTC_SEQUENCE_INTERVAL": Time between sequential requests in seconds (Default: 60)`)
|
||||
ew.writeln(` - "OTC_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 300)`)
|
||||
|
|
|
|||
3
docs/content/dns/zz_gen_otc.md
generated
3
docs/content/dns/zz_gen_otc.md
generated
|
|
@ -35,7 +35,6 @@ _Please contribute by adding a CLI example._
|
|||
| Environment Variable Name | Description |
|
||||
|-----------------------|-------------|
|
||||
| `OTC_DOMAIN_NAME` | Domain name |
|
||||
| `OTC_IDENTITY_ENDPOINT` | Identity endpoint URL |
|
||||
| `OTC_PASSWORD` | Password |
|
||||
| `OTC_PROJECT_NAME` | Project name |
|
||||
| `OTC_USER_NAME` | User name |
|
||||
|
|
@ -49,7 +48,9 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
|
|||
| Environment Variable Name | Description |
|
||||
|--------------------------------|-------------|
|
||||
| `OTC_HTTP_TIMEOUT` | API request timeout in seconds (Default: 10) |
|
||||
| `OTC_IDENTITY_ENDPOINT` | Identity endpoint URL |
|
||||
| `OTC_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
|
||||
| `OTC_PRIVATE_ZONE` | Set to true to use private zones only (default: use public zones only) |
|
||||
| `OTC_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
|
||||
| `OTC_SEQUENCE_INTERVAL` | Time between sequential requests in seconds (Default: 60) |
|
||||
| `OTC_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 300) |
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ func NewClient(username, password, domainName, projectName string) *Client {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *Client) GetZoneID(ctx context.Context, zone string) (string, error) {
|
||||
zonesResp, err := c.getZones(ctx, zone)
|
||||
func (c *Client) GetZoneID(ctx context.Context, zone string, privateZone bool) (string, error) {
|
||||
zonesResp, err := c.getZones(ctx, zone, privateZone)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
@ -62,13 +62,16 @@ func (c *Client) GetZoneID(ctx context.Context, zone string) (string, error) {
|
|||
}
|
||||
|
||||
// https://docs.otc.t-systems.com/domain-name-service/api-ref/apis/public_zone_management/querying_public_zones.html
|
||||
func (c *Client) getZones(ctx context.Context, zone string) (*ZonesResponse, error) {
|
||||
func (c *Client) getZones(ctx context.Context, zone string, privateZone bool) (*ZonesResponse, error) {
|
||||
c.muBaseURL.Lock()
|
||||
endpoint := c.baseURL.JoinPath("zones")
|
||||
c.muBaseURL.Unlock()
|
||||
|
||||
query := endpoint.Query()
|
||||
query.Set("name", zone)
|
||||
if privateZone {
|
||||
query.Set("type", "private")
|
||||
}
|
||||
endpoint.RawQuery = query.Encode()
|
||||
|
||||
req, err := newJSONRequest(ctx, http.MethodGet, endpoint, nil)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,22 @@ func TestClient_GetZoneID(t *testing.T) {
|
|||
With("name", "example.com.")).
|
||||
Build(t)
|
||||
|
||||
zoneID, err := client.GetZoneID(context.Background(), "example.com.")
|
||||
zoneID, err := client.GetZoneID(context.Background(), "example.com.", false)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "123123", zoneID)
|
||||
}
|
||||
|
||||
func TestClient_GetZoneID_private(t *testing.T) {
|
||||
client := mockBuilder().
|
||||
Route("GET /zones",
|
||||
servermock.ResponseFromFixture("zones_GET.json"),
|
||||
servermock.CheckQueryParameter().Strict().
|
||||
With("name", "example.com.").
|
||||
With("type", "private")).
|
||||
Build(t)
|
||||
|
||||
zoneID, err := client.GetZoneID(context.Background(), "example.com.", true)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "123123", zoneID)
|
||||
|
|
@ -47,7 +62,7 @@ func TestClient_GetZoneID_error(t *testing.T) {
|
|||
With("name", "example.com.")).
|
||||
Build(t)
|
||||
|
||||
_, err := client.GetZoneID(context.Background(), "example.com.")
|
||||
_, err := client.GetZoneID(context.Background(), "example.com.", false)
|
||||
require.EqualError(t, err, "zone example.com. not found")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ const (
|
|||
EnvPassword = envNamespace + "PASSWORD"
|
||||
EnvProjectName = envNamespace + "PROJECT_NAME"
|
||||
EnvIdentityEndpoint = envNamespace + "IDENTITY_ENDPOINT"
|
||||
EnvPrivateZone = envNamespace + "PRIVATE_ZONE"
|
||||
|
||||
EnvTTL = envNamespace + "TTL"
|
||||
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
||||
|
|
@ -40,11 +41,13 @@ var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
|
|||
|
||||
// Config is used to configure the creation of the DNSProvider.
|
||||
type Config struct {
|
||||
IdentityEndpoint string
|
||||
DomainName string
|
||||
ProjectName string
|
||||
UserName string
|
||||
Password string
|
||||
DomainName string
|
||||
ProjectName string
|
||||
UserName string
|
||||
Password string
|
||||
IdentityEndpoint string
|
||||
PrivateZone bool
|
||||
|
||||
PropagationTimeout time.Duration
|
||||
PollingInterval time.Duration
|
||||
SequenceInterval time.Duration
|
||||
|
|
@ -65,10 +68,12 @@ func NewDefaultConfig() *Config {
|
|||
tr.DisableKeepAlives = true
|
||||
|
||||
return &Config{
|
||||
PrivateZone: env.GetOrDefaultBool(EnvPrivateZone, false),
|
||||
IdentityEndpoint: env.GetOrDefaultString(EnvIdentityEndpoint, defaultIdentityEndpoint),
|
||||
|
||||
TTL: env.GetOrDefaultInt(EnvTTL, minTTL),
|
||||
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
|
||||
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
|
||||
IdentityEndpoint: env.GetOrDefaultString(EnvIdentityEndpoint, defaultIdentityEndpoint),
|
||||
SequenceInterval: env.GetOrDefaultSecond(EnvSequenceInterval, dns01.DefaultPropagationTimeout),
|
||||
HTTPClient: &http.Client{
|
||||
Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 10*time.Second),
|
||||
|
|
@ -144,7 +149,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
|||
return fmt.Errorf("otc: %w", err)
|
||||
}
|
||||
|
||||
zoneID, err := d.client.GetZoneID(ctx, authZone)
|
||||
zoneID, err := d.client.GetZoneID(ctx, authZone, d.config.PrivateZone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("otc: unable to get zone: %w", err)
|
||||
}
|
||||
|
|
@ -181,7 +186,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
|||
return fmt.Errorf("otc: %w", err)
|
||||
}
|
||||
|
||||
zoneID, err := d.client.GetZoneID(ctx, authZone)
|
||||
zoneID, err := d.client.GetZoneID(ctx, authZone, d.config.PrivateZone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("otc: %w", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@ Example = ''''''
|
|||
OTC_PASSWORD = "Password"
|
||||
OTC_PROJECT_NAME = "Project name"
|
||||
OTC_DOMAIN_NAME = "Domain name"
|
||||
OTC_IDENTITY_ENDPOINT = "Identity endpoint URL"
|
||||
[Configuration.Additional]
|
||||
OTC_IDENTITY_ENDPOINT = "Identity endpoint URL"
|
||||
OTC_PRIVATE_ZONE = "Set to true to use private zones only (default: use public zones only)"
|
||||
OTC_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 2)"
|
||||
OTC_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 60)"
|
||||
OTC_SEQUENCE_INTERVAL = "Time between sequential requests in seconds (Default: 60)"
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ var envTest = tester.NewEnvTest(
|
|||
EnvDomainName,
|
||||
EnvUserName,
|
||||
EnvPassword,
|
||||
EnvPrivateZone,
|
||||
EnvProjectName,
|
||||
EnvIdentityEndpoint).
|
||||
WithDomain(envDomain)
|
||||
|
|
@ -213,7 +214,7 @@ func TestLiveCleanUp(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDNSProvider_Present(t *testing.T) {
|
||||
provider := mockBuilder().
|
||||
provider := mockBuilder(false).
|
||||
Route("GET /v2/zones",
|
||||
servermock.ResponseFromInternal("zones_GET.json"),
|
||||
servermock.CheckQueryParameter().Strict().
|
||||
|
|
@ -227,8 +228,24 @@ func TestDNSProvider_Present(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDNSProvider_Present_private(t *testing.T) {
|
||||
provider := mockBuilder(true).
|
||||
Route("GET /v2/zones",
|
||||
servermock.ResponseFromInternal("zones_GET.json"),
|
||||
servermock.CheckQueryParameter().Strict().
|
||||
With("name", "example.com.").
|
||||
With("type", "private")).
|
||||
Route("POST /v2/zones/123123/recordsets",
|
||||
servermock.Noop(),
|
||||
servermock.CheckRequestJSONBodyFromInternal("zones-recordsets_POST-request.json")).
|
||||
Build(t)
|
||||
|
||||
err := provider.Present("example.com", "", "123d==")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDNSProvider_Present_emptyZone(t *testing.T) {
|
||||
provider := mockBuilder().
|
||||
provider := mockBuilder(false).
|
||||
Route("GET /v2/zones",
|
||||
servermock.ResponseFromInternal("zones_GET_empty.json"),
|
||||
servermock.CheckQueryParameter().Strict().
|
||||
|
|
@ -240,7 +257,7 @@ func TestDNSProvider_Present_emptyZone(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDNSProvider_Cleanup(t *testing.T) {
|
||||
provider := mockBuilder().
|
||||
provider := mockBuilder(false).
|
||||
Route("GET /v2/zones",
|
||||
servermock.ResponseFromInternal("zones_GET.json"),
|
||||
servermock.CheckQueryParameter().Strict().
|
||||
|
|
@ -258,8 +275,28 @@ func TestDNSProvider_Cleanup(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDNSProvider_Cleanup_private(t *testing.T) {
|
||||
provider := mockBuilder(true).
|
||||
Route("GET /v2/zones",
|
||||
servermock.ResponseFromInternal("zones_GET.json"),
|
||||
servermock.CheckQueryParameter().Strict().
|
||||
With("name", "example.com.").
|
||||
With("type", "private")).
|
||||
Route("GET /v2/zones/123123/recordsets",
|
||||
servermock.ResponseFromInternal("zones-recordsets_GET.json"),
|
||||
servermock.CheckQueryParameter().Strict().
|
||||
With("name", "_acme-challenge.example.com.").
|
||||
With("type", "TXT")).
|
||||
Route("DELETE /v2/zones/123123/recordsets/321321",
|
||||
servermock.ResponseFromInternal("zones-recordsets_DELETE.json")).
|
||||
Build(t)
|
||||
|
||||
err := provider.CleanUp("example.com", "", "123d==")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDNSProvider_Cleanup_emptyRecordset(t *testing.T) {
|
||||
provider := mockBuilder().
|
||||
provider := mockBuilder(false).
|
||||
Route("GET /v2/zones",
|
||||
servermock.ResponseFromInternal("zones_GET.json"),
|
||||
servermock.CheckQueryParameter().Strict().
|
||||
|
|
@ -275,7 +312,7 @@ func TestDNSProvider_Cleanup_emptyRecordset(t *testing.T) {
|
|||
require.EqualError(t, err, "otc: unable to get record _acme-challenge.example.com. for zone example.com: record not found")
|
||||
}
|
||||
|
||||
func mockBuilder() *servermock.Builder[*DNSProvider] {
|
||||
func mockBuilder(private bool) *servermock.Builder[*DNSProvider] {
|
||||
return servermock.NewBuilder(
|
||||
func(server *httptest.Server) (*DNSProvider, error) {
|
||||
config := NewDefaultConfig()
|
||||
|
|
@ -285,6 +322,7 @@ func mockBuilder() *servermock.Builder[*DNSProvider] {
|
|||
config.DomainName = "example.com"
|
||||
config.ProjectName = "test"
|
||||
config.IdentityEndpoint = fmt.Sprintf("%s/v3/auth/token", server.URL)
|
||||
config.PrivateZone = private
|
||||
|
||||
return NewDNSProviderConfig(config)
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue