Add DNS provider for YandexCloud (#1694)

Co-authored-by: Fernandez Ludovic <ldez@users.noreply.github.com>
This commit is contained in:
Andrew Kluev 2022-09-02 00:05:43 +03:00 committed by GitHub
parent 11ac3da542
commit be0c6c743d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 698 additions and 8 deletions

View file

@ -74,8 +74,8 @@ Detailed documentation is available [here](https://go-acme.github.io/lego/dns).
| [Simply.com](https://go-acme.github.io/lego/dns/simply/) | [Sonic](https://go-acme.github.io/lego/dns/sonic/) | [Stackpath](https://go-acme.github.io/lego/dns/stackpath/) | [Tencent Cloud DNS](https://go-acme.github.io/lego/dns/tencentcloud/) |
| [TransIP](https://go-acme.github.io/lego/dns/transip/) | [UKFast SafeDNS](https://go-acme.github.io/lego/dns/safedns/) | [Variomedia](https://go-acme.github.io/lego/dns/variomedia/) | [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/) |
| [Vercel](https://go-acme.github.io/lego/dns/vercel/) | [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/) | [VinylDNS](https://go-acme.github.io/lego/dns/vinyldns/) | [Vscale](https://go-acme.github.io/lego/dns/vscale/) |
| [Vultr](https://go-acme.github.io/lego/dns/vultr/) | [WEDOS](https://go-acme.github.io/lego/dns/wedos/) | [Yandex](https://go-acme.github.io/lego/dns/yandex/) | [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/) |
| [Zonomi](https://go-acme.github.io/lego/dns/zonomi/) | | | |
| [Vultr](https://go-acme.github.io/lego/dns/vultr/) | [WEDOS](https://go-acme.github.io/lego/dns/wedos/) | [Yandex Cloud](https://go-acme.github.io/lego/dns/yandexcloud/) | [Yandex](https://go-acme.github.io/lego/dns/yandex/) |
| [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/) | [Zonomi](https://go-acme.github.io/lego/dns/zonomi/) | | |
<!-- END DNS PROVIDERS LIST -->

View file

@ -116,6 +116,7 @@ func allDNSCodes() string {
"vultr",
"wedos",
"yandex",
"yandexcloud",
"zoneee",
"zonomi",
}
@ -2303,6 +2304,26 @@ func displayDNSHelp(name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/yandex`)
case "yandexcloud":
// generated from: providers/dns/yandexcloud/yandexcloud.toml
ew.writeln(`Configuration for Yandex Cloud.`)
ew.writeln(`Code: 'yandexcloud'`)
ew.writeln(`Since: 'v4.9.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "YANDEX_CLOUD_FOLDER_ID": The string id of folder (aka project) in Yandex Cloud`)
ew.writeln(` - "YANDEX_CLOUD_IAM_TOKEN": The base64 encoded json which contains inforamtion about iam token of serivce account with 'dns.admin' permissions`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "YANDEX_CLOUD_POLLING_INTERVAL": Time between DNS propagation check`)
ew.writeln(` - "YANDEX_CLOUD_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
ew.writeln(` - "YANDEX_CLOUD_TTL": The TTL of the TXT record used for the DNS challenge`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/yandexcloud`)
case "zoneee":
// generated from: providers/dns/zoneee/zoneee.toml
ew.writeln(`Configuration for Zone.ee.`)

View file

@ -26,7 +26,7 @@ Configuration for [Infoblox](https://www.infoblox.com/).
Here is an example bash command using the Infoblox provider:
```bash
INFOBLOX_USER=api-user-529 \
INFOBLOX_USERNAME=api-user-529 \
INFOBLOX_PASSWORD=b9841238feb177a84330febba8a83208921177bffe733 \
INFOBLOX_HOST=infoblox.example.org
lego --email you@example.com --dns infoblox --domains my.example.org run

View file

@ -0,0 +1,90 @@
---
title: "Yandex Cloud"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: yandexcloud
dnsprovider:
since: "v4.9.0"
code: "yandexcloud"
url: "https://cloud.yandex.com"
---
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/yandexcloud/yandexcloud.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
Configuration for [Yandex Cloud](https://cloud.yandex.com).
<!--more-->
- Code: `yandexcloud`
- Since: v4.9.0
Here is an example bash command using the Yandex Cloud provider:
```bash
YANDEX_CLOUD_IAM_TOKEN=<base64_IAM_token> \
YANDEX_CLOUD_FOLDER_ID=<folder/project_id> \
lego --email you@example.com --dns yandexcloud --domains "example.org" --domains "*.example.org" run
# ---
YANDEX_CLOUD_IAM_TOKEN=$(echo '{ \
"id": "<string id>", \
"service_account_id": "<string id>", \
"created_at": "<datetime>", \
"key_algorithm": "RSA_2048", \
"public_key": "-----BEGIN PUBLIC KEY-----<rsa public key>-----END PUBLIC KEY-----", \
"private_key": "-----BEGIN PRIVATE KEY-----<rsa private key>-----END PRIVATE KEY-----" \
}' | base64) \
YANDEX_CLOUD_FOLDER_ID=<yandex cloud folder(project) id> \
lego --email you@example.com --dns yandexcloud --domains "example.org" --domains "*.example.org" run
```
## Credentials
| Environment Variable Name | Description |
|-----------------------|-------------|
| `YANDEX_CLOUD_FOLDER_ID` | The string id of folder (aka project) in Yandex Cloud |
| `YANDEX_CLOUD_IAM_TOKEN` | The base64 encoded json which contains inforamtion about iam token of serivce account with `dns.admin` permissions |
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" >}}).
## Additional Configuration
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `YANDEX_CLOUD_POLLING_INTERVAL` | Time between DNS propagation check |
| `YANDEX_CLOUD_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
| `YANDEX_CLOUD_TTL` | The TTL of the TXT record used for the DNS challenge |
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" >}}).
## IAM Token
The simplest way to retrieve IAM access token is usage of yc-cli,
follow [docs](https://cloud.yandex.ru/docs/iam/operations/iam-token/create-for-sa) to get it
```bash
yc iam key create --service-account-name my-robot --output key.json
cat key.json | base64
```
## More information
- [API documentation](https://cloud.yandex.com/en/docs/dns/quickstart)
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/yandexcloud/yandexcloud.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

10
go.mod
View file

@ -56,6 +56,8 @@ require (
github.com/urfave/cli/v2 v2.3.0
github.com/vinyldns/go-vinyldns v0.9.16
github.com/vultr/govultr/v2 v2.16.0
github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f
github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997
golang.org/x/crypto v0.0.0-20220214200702-86341886e292
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
@ -83,13 +85,17 @@ require (
github.com/fatih/structs v1.1.0 // indirect
github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48 // indirect
github.com/golang-jwt/jwt/v4 v4.1.0 // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
@ -122,8 +128,8 @@ require (
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/appengine v1.6.5 // indirect
google.golang.org/genproto v0.0.0-20200305110556-506484158171 // indirect
google.golang.org/grpc v1.27.1 // indirect
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c // indirect
google.golang.org/grpc v1.41.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

47
go.sum
View file

@ -65,6 +65,7 @@ github.com/aliyun/alibaba-cloud-sdk-go v1.61.1183 h1:dkj8/dxOQ4L1XpwCzRLqukvUBbx
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1183/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI=
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
@ -78,16 +79,22 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cloudflare-go v0.20.0 h1:y2a6KwYHTFxhw+8PLhz0q5hpTGj6Un3W1pbpQLhzFaE=
github.com/cloudflare/cloudflare-go v0.20.0/go.mod h1:sPWL/lIC6biLEdyGZwBQ1rGQKF1FhM7N60fuNiFdYTI=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@ -115,7 +122,12 @@ github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/dnsimple/dnsimple-go v0.70.1 h1:cSZndVjttLpgplDuesY4LFIvfKf/zRA1J7mCATBbzSM=
github.com/dnsimple/dnsimple-go v0.70.1/go.mod h1:F9WHww9cC76hrnwGFfAfrqdW99j3MOYasQcIwTS/aUk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/exoscale/egoscale v0.89.0 h1:YEA3pG97j14diC6okttXMOH9mLwlMuv/184uZyUGxhk=
github.com/exoscale/egoscale v0.89.0/go.mod h1:wyXE5zrnFynMXA0jMhwQqSe24CfUhmBk2WI5wFZcq6Y=
@ -130,6 +142,7 @@ github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/getkin/kin-openapi v0.87.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
@ -163,7 +176,8 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0=
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -185,7 +199,9 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
@ -196,6 +212,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
@ -214,6 +231,7 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
@ -232,10 +250,12 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
@ -244,6 +264,8 @@ github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrj
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ=
github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
@ -359,6 +381,7 @@ github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceT
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
@ -449,6 +472,7 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2 h1:dq90+d51/hQRaHEqRAsQ1rE/pC1GUS4sc2rCbbFsAIY=
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
@ -537,6 +561,10 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f h1:cG+ehPRJSlqljSufLf1KXeXpUd1dLNjnzA18mZcB/O0=
github.com/yandex-cloud/go-genproto v0.0.0-20220805142335-27b56ddae16f/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997 h1:2wzke3JH7OtN20WsNDZx2VH/TCmsbqtDEbXzjF+i05E=
github.com/yandex-cloud/go-sdk v0.0.0-20220805164847-cf028e604997/go.mod h1:2CHKs/YGbCcNn/BPaCkEBwKz/FNCELi+MLILjR9RaTA=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@ -546,6 +574,7 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@ -719,6 +748,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@ -807,22 +837,33 @@ google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvx
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171 h1:xes2Q2k+d/+YNXVw0FpZkIDJiaux4OVrRKXRAzH6A0U=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c h1:FqrtZMB5Wr+/RecOM3uPJNPfWR8Upb5hAPnt7PU6i4k=
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=

View file

@ -107,6 +107,7 @@ import (
"github.com/go-acme/lego/v4/providers/dns/vultr"
"github.com/go-acme/lego/v4/providers/dns/wedos"
"github.com/go-acme/lego/v4/providers/dns/yandex"
"github.com/go-acme/lego/v4/providers/dns/yandexcloud"
"github.com/go-acme/lego/v4/providers/dns/zoneee"
"github.com/go-acme/lego/v4/providers/dns/zonomi"
)
@ -320,6 +321,8 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
return wedos.NewDNSProvider()
case "yandex":
return yandex.NewDNSProvider()
case "yandexcloud":
return yandexcloud.NewDNSProvider()
case "zoneee":
return zoneee.NewDNSProvider()
case "zonomi":

View file

@ -0,0 +1,317 @@
// Package yandexcloud implements a DNS provider for solving the DNS-01 challenge using Yandex Cloud.
package yandexcloud
import (
"context"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"strings"
"time"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/platform/config/env"
ycdns "github.com/yandex-cloud/go-genproto/yandex/cloud/dns/v1"
ycsdk "github.com/yandex-cloud/go-sdk"
"github.com/yandex-cloud/go-sdk/iamkey"
)
const defaultTTL = 60
// Environment variables names.
const (
envNamespace = "YANDEX_CLOUD_"
EnvIamToken = envNamespace + "IAM_TOKEN"
EnvFolderID = envNamespace + "FOLDER_ID"
EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
)
// Config is used to configure the creation of the DNSProvider.
type Config struct {
IamToken string
FolderID string
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
}
// NewDefaultConfig returns a default configuration for the DNSProvider.
func NewDefaultConfig() *Config {
return &Config{
TTL: env.GetOrDefaultInt(EnvTTL, defaultTTL),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
}
}
// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
client *ycsdk.SDK
config *Config
}
// NewDNSProvider returns a DNSProvider instance configured for Yandex Cloud.
func NewDNSProvider() (*DNSProvider, error) {
values, err := env.Get(EnvIamToken, EnvFolderID)
if err != nil {
return nil, fmt.Errorf("yandexcloud: %w", err)
}
config := NewDefaultConfig()
config.IamToken = values[EnvIamToken]
config.FolderID = values[EnvFolderID]
return NewDNSProviderConfig(config)
}
// NewDNSProviderConfig return a DNSProvider instance configured for Yandex Cloud.
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config == nil {
return nil, errors.New("yandexcloud: the configuration of the DNS provider is nil")
}
if config.IamToken == "" {
return nil, fmt.Errorf("yandexcloud: some credentials information are missing IAM token")
}
if config.FolderID == "" {
return nil, fmt.Errorf("yandexcloud: some credentials information are missing folder id")
}
creds, err := decodeCredentials(config.IamToken)
if err != nil {
return nil, fmt.Errorf("yandexcloud: iam token is malformed: %w", err)
}
client, err := ycsdk.Build(context.Background(), ycsdk.Config{Credentials: creds})
if err != nil {
return nil, errors.New("yandexcloud: unable to build yandex cloud sdk")
}
return &DNSProvider{
client: client,
config: config,
}, nil
}
// Present creates a TXT record to fulfill the dns-01 challenge.
func (r *DNSProvider) Present(domain, _, keyAuth string) error {
fqdn, value := dns01.GetRecord(domain, keyAuth)
authZone, err := dns01.FindZoneByFqdn(fqdn)
if err != nil {
return fmt.Errorf("yandexcloud: %w", err)
}
ctx := context.Background()
zones, err := r.getZones(ctx)
if err != nil {
return fmt.Errorf("yandexcloud: %w", err)
}
var zoneID string
for _, zone := range zones {
if zone.GetZone() == authZone {
zoneID = zone.GetId()
}
}
if zoneID == "" {
return fmt.Errorf("yandexcloud: cant find dns zone %s in yandex cloud", authZone)
}
name := fqdn[:len(fqdn)-len(authZone)-1]
err = r.upsertRecordSetData(ctx, zoneID, name, value)
if err != nil {
return fmt.Errorf("yandexcloud: %w", err)
}
return nil
}
// CleanUp removes the TXT record matching the specified parameters.
func (r *DNSProvider) CleanUp(domain, _, keyAuth string) error {
fqdn, value := dns01.GetRecord(domain, keyAuth)
authZone, err := dns01.FindZoneByFqdn(fqdn)
if err != nil {
return fmt.Errorf("yandexcloud: %w", err)
}
ctx := context.Background()
zones, err := r.getZones(ctx)
if err != nil {
return fmt.Errorf("yandexcloud: %w", err)
}
var zoneID string
for _, zone := range zones {
if zone.GetZone() == authZone {
zoneID = zone.GetId()
}
}
if zoneID == "" {
return nil
}
name := fqdn[:len(fqdn)-len(authZone)-1]
err = r.removeRecordSetData(ctx, zoneID, name, value)
if err != nil {
return fmt.Errorf("yandexcloud: %w", err)
}
return nil
}
// Timeout returns the timeout and interval to use when checking for DNS propagation.
// Adjusting here to cope with spikes in propagation times.
func (r *DNSProvider) Timeout() (timeout, interval time.Duration) {
return r.config.PropagationTimeout, r.config.PollingInterval
}
// getZones retrieves available zones from yandex cloud.
func (r *DNSProvider) getZones(ctx context.Context) ([]*ycdns.DnsZone, error) {
list := &ycdns.ListDnsZonesRequest{
FolderId: r.config.FolderID,
}
response, err := r.client.DNS().DnsZone().List(ctx, list)
if err != nil {
return nil, errors.New("unable to fetch dns zones")
}
return response.DnsZones, nil
}
func (r *DNSProvider) upsertRecordSetData(ctx context.Context, zoneID, name, value string) error {
get := &ycdns.GetDnsZoneRecordSetRequest{
DnsZoneId: zoneID,
Name: name,
Type: "TXT",
}
exist, err := r.client.DNS().DnsZone().GetRecordSet(ctx, get)
if err != nil {
if !strings.Contains(err.Error(), "RecordSet not found") {
return err
}
}
record := &ycdns.RecordSet{
Name: name,
Type: "TXT",
Ttl: int64(r.config.TTL),
Data: []string{},
}
var deletions []*ycdns.RecordSet
if exist != nil {
record.Data = append(record.Data, exist.Data...)
deletions = append(deletions, exist)
}
appended := appendRecordSetData(record, value)
if !appended {
// The value already present in RecordSet, nothing to do
return nil
}
update := &ycdns.UpdateRecordSetsRequest{
DnsZoneId: zoneID,
Deletions: deletions,
Additions: []*ycdns.RecordSet{record},
}
_, err = r.client.DNS().DnsZone().UpdateRecordSets(ctx, update)
return err
}
func (r *DNSProvider) removeRecordSetData(ctx context.Context, zoneID, name, value string) error {
get := &ycdns.GetDnsZoneRecordSetRequest{
DnsZoneId: zoneID,
Name: name,
Type: "TXT",
}
previousRecord, err := r.client.DNS().DnsZone().GetRecordSet(ctx, get)
if err != nil {
if strings.Contains(err.Error(), "RecordSet not found") {
// RecordSet is not present, nothing to do
return nil
}
return err
}
var additions []*ycdns.RecordSet
if len(previousRecord.Data) > 1 {
// RecordSet is not empty we should update it
record := &ycdns.RecordSet{
Name: name,
Type: "TXT",
Ttl: int64(r.config.TTL),
Data: []string{},
}
for _, data := range previousRecord.Data {
if data != value {
record.Data = append(record.Data, data)
}
}
additions = append(additions, record)
}
update := &ycdns.UpdateRecordSetsRequest{
DnsZoneId: zoneID,
Deletions: []*ycdns.RecordSet{previousRecord},
Additions: additions,
}
_, err = r.client.DNS().DnsZone().UpdateRecordSets(ctx, update)
return err
}
// decodeCredentials converts base64 encoded json of iam token to struct.
func decodeCredentials(accountB64 string) (ycsdk.Credentials, error) {
account, err := base64.StdEncoding.DecodeString(accountB64)
if err != nil {
return nil, err
}
key := &iamkey.Key{}
err = json.Unmarshal(account, key)
if err != nil {
return nil, err
}
return ycsdk.ServiceAccountKey(key)
}
func appendRecordSetData(record *ycdns.RecordSet, value string) bool {
for _, data := range record.Data {
if data == value {
return false
}
}
record.Data = append(record.Data, value)
return true
}

View file

@ -0,0 +1,48 @@
Name = "Yandex Cloud"
Description = ''''''
URL = "https://cloud.yandex.com"
Code = "yandexcloud"
Since = "v4.9.0"
Example = '''
YANDEX_CLOUD_IAM_TOKEN=<base64_IAM_token> \
YANDEX_CLOUD_FOLDER_ID=<folder/project_id> \
lego --email you@example.com --dns yandexcloud --domains "example.org" --domains "*.example.org" run
# ---
YANDEX_CLOUD_IAM_TOKEN=$(echo '{ \
"id": "<string id>", \
"service_account_id": "<string id>", \
"created_at": "<datetime>", \
"key_algorithm": "RSA_2048", \
"public_key": "-----BEGIN PUBLIC KEY-----<rsa public key>-----END PUBLIC KEY-----", \
"private_key": "-----BEGIN PRIVATE KEY-----<rsa private key>-----END PRIVATE KEY-----" \
}' | base64) \
YANDEX_CLOUD_FOLDER_ID=<yandex cloud folder(project) id> \
lego --email you@example.com --dns yandexcloud --domains "example.org" --domains "*.example.org" run
'''
Additional = '''
## IAM Token
The simplest way to retrieve IAM access token is usage of yc-cli,
follow [docs](https://cloud.yandex.ru/docs/iam/operations/iam-token/create-for-sa) to get it
```bash
yc iam key create --service-account-name my-robot --output key.json
cat key.json | base64
```
'''
[Configuration]
[Configuration.Credentials]
YANDEX_CLOUD_IAM_TOKEN = "The base64 encoded json which contains inforamtion about iam token of serivce account with `dns.admin` permissions"
YANDEX_CLOUD_FOLDER_ID = "The string id of folder (aka project) in Yandex Cloud"
[Configuration.Additional]
YANDEX_CLOUD_POLLING_INTERVAL = "Time between DNS propagation check"
YANDEX_CLOUD_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
YANDEX_CLOUD_TTL = "The TTL of the TXT record used for the DNS challenge"
[Links]
API = "https://cloud.yandex.com/en/docs/dns/quickstart"

View file

@ -0,0 +1,164 @@
package yandexcloud
import (
"encoding/base64"
"testing"
"github.com/go-acme/lego/v4/platform/tester"
"github.com/stretchr/testify/require"
)
const envDomain = envNamespace + "DOMAIN"
const fakeIAMToken = `
{
"id": "abcdefghijklmnopqrst",
"service_account_id": "abcdefghijklmnopqrst",
"created_at": "2000-01-01T00:00:00.000000000Z",
"key_algorithm": "RSA_2048",
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkVF2HjTx4v9rGof5OHGO\nGka+5XJc+px2KkzG0kG2H0ftal8n1LaY2rARmGp1T1/px80rR3amJ9mhnmB+jH5+\ntwxWr+qVwVnJrklBozgEtl6wXzB7zNqC3kV5rXZ4Omvn6daKuiczfgLL7N/yYQzk\nSKRYOCygBbPoxVGS50ZLVdCWWtz1iFbNmElnsM4KQjnxWBVRDwR2H5OIU84NonUz\nNcHDkVBX/d8pkSg7iB4NyD1AqvJtF1pS03NQm32n69bsfRsJxrqR6LK/aql379rk\nhgA7SyzMLJcLckKug+KfTCpktrwzi2AppUPD7keKJilOfhSrCGQglMr6Q3ao03SZ\ncQIDAQAB\n-----END PUBLIC KEY-----",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCRUXYeNPHi/2sa\nh/k4cY4aRr7lclz6nHYqTMbSQbYfR+1qXyfUtpjasBGYanVPX+nHzStHdqYn2aGe\nYH6Mfn63DFav6pXBWcmuSUGjOAS2XrBfMHvM2oLeRXmtdng6a+fp1oq6JzN+Asvs\n3/JhDORIpFg4LKAFs+jFUZLnRktV0JZa3PWIVs2YSWewzgpCOfFYFVEPBHYfk4hT\nzg2idTM1wcORUFf93ymRKDuIHg3IPUCq8m0XWlLTc1Cbfafr1ux9GwnGupHosr9q\nqXfv2uSGADtLLMwslwtyQq6D4p9MKmS2vDOLYCmlQ8PuR4omKU5+FKsIZCCUyvpD\ndqjTdJlxAgMBAAECggEAOzG7s8JNZfI1ZrFMy7k18W4wBLb5OPzTBZgQxUUPMt7R\nzyrDxto6mZpvEG8NKjAfwsvIfWvPcxwrwZ/87K36YAYeqbodFo3EocIlgp8nDEK2\nBZByXZgFBxW14vsHLoUWCyLhj8K4LvRkrTDsQqxFsXGAniFPbgNDJl18QclYlrOr\nnn9ZF7W0t2d0jnuzwB9k8L18RqRYWovCAjnFCS0tX5uQKtjSYD0JRG7CiKqd4ruv\ntJ1Go4bo+rRcaEbFgDyf8BEVa6t9VJX1MVjL2xm0toQUjtA+ZTuAAg4hCibEoru8\nYo55+R65HHI9B8nZxfp0kEVyzAhQWov91JbHzhRiAQKBgQDM8yuJ4tDAQ53RDmDF\nX5er2F9TeJo2ARiFB2C+4h9I88jC1LJ3Kgd161MO1mY3SVfNMHXZc0tpRDr+5xdn\nUNKuV8AS+O80Fan5eJX245bJiXr7Q73tV1PjVwJmXkMT+GaITqKsGyOZp1ms61Ed\nP/YaDfS7az1KeIGKWmkO5xDc2QKBgQC1g9G4wTrAaaZ8uXBkm982Oy47iMDy4IgW\na4mLyedhvBhOFNSGwNKfw6zBX+PPT1FKM9xJX1g1kbNNhH+W/y/Qx/uNz7QcsSvQ\nsUVRwPRmUarPsIuDGvqIj7kn7HjQgqJ/hTlmOXR3fTrvGZq8OYyhgF6BqowPFS/2\nxVYOLXsiWQKBgQCpmxdNzZlJcut4ZTiqPfiLas1Ai4664F9FP5zNet2/Bpf+u/xQ\n50QzTqJ2pfEDEbwKf28Xm/UtURytc9qHUnh3dQDr8nwqEz+Nxz/7h85yTEatBxt2\n/Yzbl1bSFnHWZfucE89FNFRaxQZONpLy7MqiNyhvrUiUh3NUZouInKn0yQKBgEAv\nGougGCxNr4dO80VAMM+2YYS/uKqpZrW21O5POLhAkL+bcgMsT84anQ3L4Hw/6di5\nOd3gDwryOFrizVMRbVEARh1BIsk6hOnIpWBhQIqluiayoMJ9WbXMTIangZkJeHhr\nHX7eNibCa4J8pVCFcQryn3huXBRBQ7KY2PMudeoRAoGBAJ1vdBQSuai3RIfyj8Yr\n4ArtCU1T5bicp13+mJODSeRhHMnlKkmI64vwrW5POFXWyJKPYLkuDk9bEYOyNBOA\nBTsUyaJp3jx/942oEwURc4Tb9az7CqEHaCrWHVHCj1CjCEX/FsRfd+wYyuGLwwly\nwdpqBWBl5iH74tRD6c+rguma\n-----END PRIVATE KEY-----"
}
`
var envTest = tester.NewEnvTest(EnvIamToken, EnvFolderID).WithDomain(envDomain)
func TestNewDNSProvider(t *testing.T) {
testCases := []struct {
desc string
envVars map[string]string
expected string
}{
{
desc: "success",
envVars: map[string]string{
EnvIamToken: base64.StdEncoding.EncodeToString([]byte(fakeIAMToken)),
EnvFolderID: "folder_id",
},
},
{
desc: "missing iam token",
envVars: map[string]string{
EnvFolderID: "folder_id",
},
expected: "yandexcloud: some credentials information are missing: YANDEX_CLOUD_IAM_TOKEN",
},
{
desc: "missing folder_id",
envVars: map[string]string{
EnvIamToken: base64.StdEncoding.EncodeToString([]byte(fakeIAMToken)),
},
expected: "yandexcloud: some credentials information are missing: YANDEX_CLOUD_FOLDER_ID",
},
{
desc: "malformed token (not base64)",
envVars: map[string]string{
EnvIamToken: fakeIAMToken,
EnvFolderID: "folder_id",
},
expected: "yandexcloud: iam token is malformed: illegal base64 data at input byte 1",
},
{
desc: "malformed token (invalid json in bas64)",
envVars: map[string]string{
EnvIamToken: "aW52YWxpZCBqc29u",
EnvFolderID: "folder_id",
},
expected: "yandexcloud: iam token is malformed: invalid character 'i' looking for beginning of value",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
defer envTest.RestoreEnv()
envTest.ClearEnv()
envTest.Apply(test.envVars)
p, err := NewDNSProvider()
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
require.NotNil(t, p.config)
} else {
require.EqualError(t, err, test.expected)
}
})
}
}
func TestNewDNSProviderConfig(t *testing.T) {
testCases := []struct {
desc string
config *Config
expected string
}{
{
desc: "success",
config: &Config{
IamToken: base64.StdEncoding.EncodeToString([]byte(fakeIAMToken)),
FolderID: "folder_id",
},
},
{
desc: "nil config",
config: nil,
expected: "yandexcloud: the configuration of the DNS provider is nil",
},
{
desc: "missing token",
config: &Config{
FolderID: "folder_id",
},
expected: "yandexcloud: some credentials information are missing IAM token",
},
{
desc: "missing folder id",
config: &Config{
IamToken: base64.StdEncoding.EncodeToString([]byte(fakeIAMToken)),
},
expected: "yandexcloud: some credentials information are missing folder id",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
p, err := NewDNSProviderConfig(test.config)
if test.expected == "" {
require.NoError(t, err)
require.NotNil(t, p)
require.NotNil(t, p.config)
} else {
require.EqualError(t, err, test.expected)
}
})
}
}
func TestLivePresent(t *testing.T) {
if !envTest.IsLiveTest() {
t.Skip("skipping live test")
}
envTest.RestoreEnv()
provider, err := NewDNSProvider()
require.NoError(t, err)
err = provider.Present(envTest.GetDomain(), "", "123d==")
require.NoError(t, err)
}
func TestLiveCleanUp(t *testing.T) {
if !envTest.IsLiveTest() {
t.Skip("skipping live test")
}
envTest.RestoreEnv()
provider, err := NewDNSProvider()
require.NoError(t, err)
err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
require.NoError(t, err)
}