alidns: support ECS instance RAM role (#1462)

This commit is contained in:
Yuanhai He 2021-08-25 18:49:56 +08:00 committed by GitHub
parent dc2b19e1b1
commit 99ba43f743
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 19 deletions

View file

@ -142,6 +142,7 @@ func displayDNSHelp(name string) error {
ew.writeln(`Credentials:`) ew.writeln(`Credentials:`)
ew.writeln(` - "ALICLOUD_ACCESS_KEY": Access key ID`) ew.writeln(` - "ALICLOUD_ACCESS_KEY": Access key ID`)
ew.writeln(` - "ALICLOUD_RAM_ROLE": Your instance RAM role (https://www.alibabacloud.com/help/doc-detail/54579.htm)`)
ew.writeln(` - "ALICLOUD_SECRET_KEY": Access Key secret`) ew.writeln(` - "ALICLOUD_SECRET_KEY": Access Key secret`)
ew.writeln(` - "ALICLOUD_SECURITY_TOKEN": STS Security Token (optional)`) ew.writeln(` - "ALICLOUD_SECURITY_TOKEN": STS Security Token (optional)`)
ew.writeln() ew.writeln()

View file

@ -21,8 +21,14 @@ Configuration for [Alibaba Cloud DNS](https://www.alibabacloud.com/product/dns).
Here is an example bash command using the Alibaba Cloud DNS provider: Here is an example bash command using the Alibaba Cloud DNS provider:
```bash ```bash
# Setup using instance RAM role
ALICLOUD_RAM_ROLE=lego \
lego --email myemail@example.com --dns alidns --domains my.example.org run
# Or, using credentials
ALICLOUD_ACCESS_KEY=abcdefghijklmnopqrstuvwx \ ALICLOUD_ACCESS_KEY=abcdefghijklmnopqrstuvwx \
ALICLOUD_SECRET_KEY=xxxxxxx \ ALICLOUD_SECRET_KEY=your-secret-key \
ALICLOUD_SECURITY_TOKEN=your-sts-token \
lego --email myemail@example.com --dns alidns --domains my.example.org run lego --email myemail@example.com --dns alidns --domains my.example.org run
``` ```
@ -34,6 +40,7 @@ lego --email myemail@example.com --dns alidns --domains my.example.org run
| Environment Variable Name | Description | | Environment Variable Name | Description |
|-----------------------|-------------| |-----------------------|-------------|
| `ALICLOUD_ACCESS_KEY` | Access key ID | | `ALICLOUD_ACCESS_KEY` | Access key ID |
| `ALICLOUD_RAM_ROLE` | Your instance RAM role (https://www.alibabacloud.com/help/doc-detail/54579.htm) |
| `ALICLOUD_SECRET_KEY` | Access Key secret | | `ALICLOUD_SECRET_KEY` | Access Key secret |
| `ALICLOUD_SECURITY_TOKEN` | STS Security Token (optional) | | `ALICLOUD_SECURITY_TOKEN` | STS Security Token (optional) |

View file

@ -23,6 +23,7 @@ const defaultRegionID = "cn-hangzhou"
const ( const (
envNamespace = "ALICLOUD_" envNamespace = "ALICLOUD_"
EnvRAMRole = envNamespace + "RAM_ROLE"
EnvAccessKey = envNamespace + "ACCESS_KEY" EnvAccessKey = envNamespace + "ACCESS_KEY"
EnvSecretKey = envNamespace + "SECRET_KEY" EnvSecretKey = envNamespace + "SECRET_KEY"
EnvSecurityToken = envNamespace + "SECURITY_TOKEN" EnvSecurityToken = envNamespace + "SECURITY_TOKEN"
@ -36,6 +37,7 @@ const (
// Config is used to configure the creation of the DNSProvider. // Config is used to configure the creation of the DNSProvider.
type Config struct { type Config struct {
RAMRole string
APIKey string APIKey string
SecretKey string SecretKey string
SecurityToken string SecurityToken string
@ -63,18 +65,26 @@ type DNSProvider struct {
} }
// NewDNSProvider returns a DNSProvider instance configured for Alibaba Cloud DNS. // NewDNSProvider returns a DNSProvider instance configured for Alibaba Cloud DNS.
// Credentials must be passed in the environment variables: // - If you're using the instance RAM role, the RAM role environment variable must be passed in: ALICLOUD_RAM_ROLE.
// - Other than that, credentials must be passed in the environment variables:
// ALICLOUD_ACCESS_KEY, ALICLOUD_SECRET_KEY, and optionally ALICLOUD_SECURITY_TOKEN. // ALICLOUD_ACCESS_KEY, ALICLOUD_SECRET_KEY, and optionally ALICLOUD_SECURITY_TOKEN.
func NewDNSProvider() (*DNSProvider, error) { func NewDNSProvider() (*DNSProvider, error) {
values, err := env.Get(EnvAccessKey, EnvSecretKey) config := NewDefaultConfig()
config.RegionID = env.GetOrFile(EnvRegionID)
values, err := env.Get(EnvRAMRole)
if err == nil {
config.RAMRole = values[EnvRAMRole]
return NewDNSProviderConfig(config)
}
values, err = env.Get(EnvAccessKey, EnvSecretKey)
if err != nil { if err != nil {
return nil, fmt.Errorf("alicloud: %w", err) return nil, fmt.Errorf("alicloud: %w", err)
} }
config := NewDefaultConfig()
config.APIKey = values[EnvAccessKey] config.APIKey = values[EnvAccessKey]
config.SecretKey = values[EnvSecretKey] config.SecretKey = values[EnvSecretKey]
config.RegionID = env.GetOrFile(EnvRegionID)
config.SecurityToken = env.GetOrFile(EnvSecurityToken) config.SecurityToken = env.GetOrFile(EnvSecurityToken)
return NewDNSProviderConfig(config) return NewDNSProviderConfig(config)
@ -86,23 +96,24 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("alicloud: the configuration of the DNS provider is nil") return nil, errors.New("alicloud: the configuration of the DNS provider is nil")
} }
if config.APIKey == "" || config.SecretKey == "" {
return nil, fmt.Errorf("alicloud: credentials missing")
}
if config.RegionID == "" { if config.RegionID == "" {
config.RegionID = defaultRegionID config.RegionID = defaultRegionID
} }
conf := sdk.NewConfig().WithTimeout(config.HTTPTimeout)
var credential auth.Credential var credential auth.Credential
if config.SecurityToken == "" { switch {
credential = credentials.NewAccessKeyCredential(config.APIKey, config.SecretKey) case config.RAMRole != "":
} else { credential = credentials.NewEcsRamRoleCredential(config.RAMRole)
case config.APIKey != "" && config.SecretKey != "" && config.SecurityToken != "":
credential = credentials.NewStsTokenCredential(config.APIKey, config.SecretKey, config.SecurityToken) credential = credentials.NewStsTokenCredential(config.APIKey, config.SecretKey, config.SecurityToken)
case config.APIKey != "" && config.SecretKey != "":
credential = credentials.NewAccessKeyCredential(config.APIKey, config.SecretKey)
default:
return nil, fmt.Errorf("alicloud: ram role or credentials missing")
} }
conf := sdk.NewConfig().WithTimeout(config.HTTPTimeout)
client, err := alidns.NewClientWithOptions(config.RegionID, conf, credential) client, err := alidns.NewClientWithOptions(config.RegionID, conf, credential)
if err != nil { if err != nil {
return nil, fmt.Errorf("alicloud: credentials failed: %w", err) return nil, fmt.Errorf("alicloud: credentials failed: %w", err)

View file

@ -5,13 +5,20 @@ Code = "alidns"
Since = "v1.1.0" Since = "v1.1.0"
Example = ''' Example = '''
# Setup using instance RAM role
ALICLOUD_RAM_ROLE=lego \
lego --email myemail@example.com --dns alidns --domains my.example.org run
# Or, using credentials
ALICLOUD_ACCESS_KEY=abcdefghijklmnopqrstuvwx \ ALICLOUD_ACCESS_KEY=abcdefghijklmnopqrstuvwx \
ALICLOUD_SECRET_KEY=xxxxxxx \ ALICLOUD_SECRET_KEY=your-secret-key \
ALICLOUD_SECURITY_TOKEN=your-sts-token \
lego --email myemail@example.com --dns alidns --domains my.example.org run lego --email myemail@example.com --dns alidns --domains my.example.org run
''' '''
[Configuration] [Configuration]
[Configuration.Credentials] [Configuration.Credentials]
ALICLOUD_RAM_ROLE = "Your instance RAM role (https://www.alibabacloud.com/help/doc-detail/54579.htm)"
ALICLOUD_ACCESS_KEY = "Access key ID" ALICLOUD_ACCESS_KEY = "Access key ID"
ALICLOUD_SECRET_KEY = "Access Key secret" ALICLOUD_SECRET_KEY = "Access Key secret"
ALICLOUD_SECURITY_TOKEN = "STS Security Token (optional)" ALICLOUD_SECURITY_TOKEN = "STS Security Token (optional)"

View file

@ -12,7 +12,8 @@ const envDomain = envNamespace + "DOMAIN"
var envTest = tester.NewEnvTest( var envTest = tester.NewEnvTest(
EnvAccessKey, EnvAccessKey,
EnvSecretKey). EnvSecretKey,
EnvRAMRole).
WithDomain(envDomain) WithDomain(envDomain)
func TestNewDNSProvider(t *testing.T) { func TestNewDNSProvider(t *testing.T) {
@ -28,6 +29,12 @@ func TestNewDNSProvider(t *testing.T) {
EnvSecretKey: "456", EnvSecretKey: "456",
}, },
}, },
{
desc: "success (RAM role)",
envVars: map[string]string{
EnvRAMRole: "LegoInstanceRole",
},
},
{ {
desc: "missing credentials", desc: "missing credentials",
envVars: map[string]string{ envVars: map[string]string{
@ -78,6 +85,7 @@ func TestNewDNSProvider(t *testing.T) {
func TestNewDNSProviderConfig(t *testing.T) { func TestNewDNSProviderConfig(t *testing.T) {
testCases := []struct { testCases := []struct {
desc string desc string
ramRole string
apiKey string apiKey string
secretKey string secretKey string
expected string expected string
@ -87,19 +95,23 @@ func TestNewDNSProviderConfig(t *testing.T) {
apiKey: "123", apiKey: "123",
secretKey: "456", secretKey: "456",
}, },
{
desc: "success",
ramRole: "LegoInstanceRole",
},
{ {
desc: "missing credentials", desc: "missing credentials",
expected: "alicloud: credentials missing", expected: "alicloud: ram role or credentials missing",
}, },
{ {
desc: "missing api key", desc: "missing api key",
secretKey: "456", secretKey: "456",
expected: "alicloud: credentials missing", expected: "alicloud: ram role or credentials missing",
}, },
{ {
desc: "missing secret key", desc: "missing secret key",
apiKey: "123", apiKey: "123",
expected: "alicloud: credentials missing", expected: "alicloud: ram role or credentials missing",
}, },
} }
@ -108,6 +120,7 @@ func TestNewDNSProviderConfig(t *testing.T) {
config := NewDefaultConfig() config := NewDefaultConfig()
config.APIKey = test.apiKey config.APIKey = test.apiKey
config.SecretKey = test.secretKey config.SecretKey = test.secretKey
config.RAMRole = test.ramRole
p, err := NewDNSProviderConfig(config) p, err := NewDNSProviderConfig(config)