diff --git a/cmd/zz_gen_cmd_dnshelp.go b/cmd/zz_gen_cmd_dnshelp.go index d49670f1b..7c43bb2a7 100644 --- a/cmd/zz_gen_cmd_dnshelp.go +++ b/cmd/zz_gen_cmd_dnshelp.go @@ -2935,11 +2935,14 @@ func displayDNSHelp(w io.Writer, name string) error { ew.writeln() ew.writeln(`Additional Configuration:`) + ew.writeln(` - "SELECTELV2_AUTH_REGION": Location for auth endpoint like ResellAPI or Keystone (default: 'ru-1')`) + ew.writeln(` - "SELECTELV2_AUTH_URL": Identity endpoint (defaul: 'https://cloud.api.selcloud.ru/identity/v3/')`) ew.writeln(` - "SELECTELV2_BASE_URL": API endpoint URL`) ew.writeln(` - "SELECTELV2_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`) ew.writeln(` - "SELECTELV2_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 5)`) ew.writeln(` - "SELECTELV2_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`) ew.writeln(` - "SELECTELV2_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`) + ew.writeln(` - "SELECTELV2_USER_DOMAIN_NAME": To specify the domain name (account ID) where the user is located. (default: SELECTELV2_ACCOUNT_ID)`) ew.writeln() ew.writeln(`More information: https://go-acme.github.io/lego/dns/selectelv2`) diff --git a/docs/content/dns/zz_gen_selectelv2.md b/docs/content/dns/zz_gen_selectelv2.md index 24dd67d1e..933ca201f 100644 --- a/docs/content/dns/zz_gen_selectelv2.md +++ b/docs/content/dns/zz_gen_selectelv2.md @@ -53,11 +53,14 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}). | Environment Variable Name | Description | |--------------------------------|-------------| +| `SELECTELV2_AUTH_REGION` | Location for auth endpoint like ResellAPI or Keystone (default: 'ru-1') | +| `SELECTELV2_AUTH_URL` | Identity endpoint (defaul: 'https://cloud.api.selcloud.ru/identity/v3/') | | `SELECTELV2_BASE_URL` | API endpoint URL | | `SELECTELV2_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) | | `SELECTELV2_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 5) | | `SELECTELV2_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 120) | | `SELECTELV2_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 60) | +| `SELECTELV2_USER_DOMAIN_NAME` | To specify the domain name (account ID) where the user is located. (default: SELECTELV2_ACCOUNT_ID) | The environment variable names can be suffixed by `_FILE` to reference a file instead of a value. More information [here]({{% ref "dns#configuration-and-credentials" %}}). diff --git a/providers/dns/selectelv2/selectelv2.go b/providers/dns/selectelv2/selectelv2.go index 1b5d55394..2654cd742 100644 --- a/providers/dns/selectelv2/selectelv2.go +++ b/providers/dns/selectelv2/selectelv2.go @@ -21,11 +21,14 @@ import ( const ( envNamespace = "SELECTELV2_" - EnvBaseURL = envNamespace + "BASE_URL" - EnvUsernameOS = envNamespace + "USERNAME" - EnvPasswordOS = envNamespace + "PASSWORD" - EnvAccount = envNamespace + "ACCOUNT_ID" - EnvProjectID = envNamespace + "PROJECT_ID" + EnvBaseURL = envNamespace + "BASE_URL" + EnvUsernameOS = envNamespace + "USERNAME" + EnvPasswordOS = envNamespace + "PASSWORD" + EnvDomainName = envNamespace + "ACCOUNT_ID" + EnvProjectID = envNamespace + "PROJECT_ID" + EnvAuthRegion = envNamespace + "AUTH_REGION" + EnvAuthURL = envNamespace + "AUTH_URL" + EnvUserDomainName = envNamespace + "USER_DOMAIN_NAME" EnvTTL = envNamespace + "TTL" EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT" @@ -34,7 +37,12 @@ const ( ) const ( - defaultBaseURL = "https://api.selectel.ru/domains/v2" + defaultBaseURL = "https://api.selectel.ru/domains/v2" + defaultAuthRegion = "ru-1" + defaultAuthURL = "https://cloud.api.selcloud.ru/identity/v3/" +) + +const ( defaultTTL = 60 defaultPropagationTimeout = 120 * time.Second defaultPollingInterval = 5 * time.Second @@ -47,11 +55,15 @@ var errNotFound = errors.New("rrset not found") // Config is used to configure the creation of the DNSProvider. type Config struct { - BaseURL string - Username string - Password string - Account string - ProjectID string + BaseURL string + Username string + Password string + DomainName string + ProjectID string + AuthURL string + AuthRegion string + UserDomainName string + TTL int PropagationTimeout time.Duration PollingInterval time.Duration @@ -61,7 +73,10 @@ type Config struct { // NewDefaultConfig returns a default configuration for the DNSProvider. func NewDefaultConfig() *Config { return &Config{ - BaseURL: env.GetOrDefaultString(EnvBaseURL, defaultBaseURL), + BaseURL: env.GetOrDefaultString(EnvBaseURL, defaultBaseURL), + AuthRegion: env.GetOrDefaultString(EnvAuthRegion, defaultAuthRegion), + AuthURL: env.GetOrDefaultString(EnvAuthURL, defaultAuthURL), + TTL: env.GetOrDefaultInt(EnvTTL, defaultTTL), PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, defaultPropagationTimeout), PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, defaultPollingInterval), @@ -78,7 +93,7 @@ type DNSProvider struct { // NewDNSProvider returns a DNSProvider instance configured for Selectel Domains APIv2. func NewDNSProvider() (*DNSProvider, error) { - values, err := env.Get(EnvUsernameOS, EnvPasswordOS, EnvAccount, EnvProjectID) + values, err := env.Get(EnvUsernameOS, EnvPasswordOS, EnvDomainName, EnvProjectID) if err != nil { return nil, fmt.Errorf("selectelv2: %w", err) } @@ -86,8 +101,9 @@ func NewDNSProvider() (*DNSProvider, error) { config := NewDefaultConfig() config.Username = values[EnvUsernameOS] config.Password = values[EnvPasswordOS] - config.Account = values[EnvAccount] + config.DomainName = values[EnvDomainName] config.ProjectID = values[EnvProjectID] + config.UserDomainName = env.GetOrDefaultString(EnvUserDomainName, "") return NewDNSProviderConfig(config) } @@ -106,8 +122,8 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { return nil, errors.New("selectelv2: missing password") } - if config.Account == "" { - return nil, errors.New("selectelv2: missing account") + if config.DomainName == "" { + return nil, errors.New("selectelv2: missing account ID") } if config.ProjectID == "" { @@ -133,7 +149,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { func (d *DNSProvider) Present(domain, _, keyAuth string) error { ctx := context.Background() - client, err := d.authorize() + client, err := d.authorize(ctx) if err != nil { return fmt.Errorf("selectelv2: authorize: %w", err) } @@ -180,7 +196,7 @@ func (d *DNSProvider) Present(domain, _, keyAuth string) error { func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error { ctx := context.Background() - client, err := d.authorize() + client, err := d.authorize(ctx) if err != nil { return fmt.Errorf("selectelv2: authorize: %w", err) } @@ -221,8 +237,8 @@ func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error { return nil } -func (d *DNSProvider) authorize() (*clientWrapper, error) { - token, err := obtainOpenstackToken(d.config) +func (d *DNSProvider) authorize(ctx context.Context) (*clientWrapper, error) { + token, err := obtainOpenstackToken(ctx, d.config) if err != nil { return nil, err } @@ -235,12 +251,16 @@ func (d *DNSProvider) authorize() (*clientWrapper, error) { }, nil } -func obtainOpenstackToken(config *Config) (string, error) { +func obtainOpenstackToken(ctx context.Context, config *Config) (string, error) { vpcClient, err := selvpcclient.NewClient(&selvpcclient.ClientOptions{ + Context: ctx, + DomainName: config.DomainName, + AuthURL: config.AuthURL, + AuthRegion: config.AuthRegion, Username: config.Username, Password: config.Password, - UserDomainName: config.Account, ProjectID: config.ProjectID, + UserDomainName: config.UserDomainName, }) if err != nil { return "", fmt.Errorf("new VPC client: %w", err) diff --git a/providers/dns/selectelv2/selectelv2.toml b/providers/dns/selectelv2/selectelv2.toml index 4993cb0f8..fd8dbda9f 100644 --- a/providers/dns/selectelv2/selectelv2.toml +++ b/providers/dns/selectelv2/selectelv2.toml @@ -20,6 +20,9 @@ lego --email you@example.com --dns selectelv2 -d '*.example.com' -d example.com SELECTELV2_PROJECT_ID = "Cloud project ID (UUID)" [Configuration.Additional] SELECTELV2_BASE_URL = "API endpoint URL" + SELECTELV2_AUTH_REGION = "Location for auth endpoint like ResellAPI or Keystone (default: 'ru-1')" + SELECTELV2_AUTH_URL = "Identity endpoint (defaul: 'https://cloud.api.selcloud.ru/identity/v3/')" + SELECTELV2_USER_DOMAIN_NAME = "To specify the domain name (account ID) where the user is located. (default: SELECTELV2_ACCOUNT_ID)" SELECTELV2_POLLING_INTERVAL = "Time between DNS propagation check in seconds (Default: 5)" SELECTELV2_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation in seconds (Default: 120)" SELECTELV2_TTL = "The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)" diff --git a/providers/dns/selectelv2/selectelv2_test.go b/providers/dns/selectelv2/selectelv2_test.go index 4859b9932..265c17e90 100644 --- a/providers/dns/selectelv2/selectelv2_test.go +++ b/providers/dns/selectelv2/selectelv2_test.go @@ -11,7 +11,15 @@ import ( const envDomain = envNamespace + "DOMAIN" -var envTest = tester.NewEnvTest(EnvUsernameOS, EnvPasswordOS, EnvAccount, EnvProjectID). +var envTest = tester.NewEnvTest( + EnvUsernameOS, + EnvPasswordOS, + EnvDomainName, + EnvUserDomainName, + EnvProjectID, + EnvAuthRegion, + EnvAuthURL, +). WithDomain(envDomain) func TestNewDNSProvider(t *testing.T) { @@ -25,7 +33,7 @@ func TestNewDNSProvider(t *testing.T) { envVars: map[string]string{ EnvUsernameOS: "someName", EnvPasswordOS: "qwerty", - EnvAccount: "1", + EnvDomainName: "1", EnvProjectID: "111a11111aaa11aa1a11aaa11111aa1a", }, }, @@ -33,7 +41,7 @@ func TestNewDNSProvider(t *testing.T) { desc: "missing username", envVars: map[string]string{ EnvPasswordOS: "qwerty", - EnvAccount: "1", + EnvDomainName: "1", EnvProjectID: "111a11111aaa11aa1a11aaa11111aa1a", }, expected: "selectelv2: some credentials information are missing: SELECTELV2_USERNAME", @@ -42,7 +50,7 @@ func TestNewDNSProvider(t *testing.T) { desc: "missing password", envVars: map[string]string{ EnvUsernameOS: "someName", - EnvAccount: "1", + EnvDomainName: "1", EnvProjectID: "111a11111aaa11aa1a11aaa11111aa1a", }, expected: "selectelv2: some credentials information are missing: SELECTELV2_PASSWORD", @@ -61,7 +69,7 @@ func TestNewDNSProvider(t *testing.T) { envVars: map[string]string{ EnvUsernameOS: "someName", EnvPasswordOS: "qwerty", - EnvAccount: "1", + EnvDomainName: "1", }, expected: "selectelv2: some credentials information are missing: SELECTELV2_PROJECT_ID", }, @@ -123,7 +131,7 @@ func TestNewDNSProviderConfig(t *testing.T) { username: "user", password: "secret", projectID: "111a11111aaa11aa1a11aaa11111aa1a", - expected: "selectelv2: missing account", + expected: "selectelv2: missing account ID", }, { desc: "missing projectID", @@ -139,7 +147,7 @@ func TestNewDNSProviderConfig(t *testing.T) { config := NewDefaultConfig() config.Username = test.username config.Password = test.password - config.Account = test.account + config.DomainName = test.account config.ProjectID = test.projectID p, err := NewDNSProviderConfig(config)