From 49e0c8b0e7cd7bf07f2c7967129e97b3874fe4bb Mon Sep 17 00:00:00 2001 From: Mike Eves Date: Thu, 12 Sep 2019 22:00:29 +0100 Subject: [PATCH 1/3] Support Cloudflare API Token Auth --- docs/tutorials/cloudflare.md | 5 ++++- go.mod | 5 +++-- go.sum | 8 ++++++++ provider/cloudflare.go | 8 +++++++- provider/cloudflare_test.go | 13 ++++++++++++- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/docs/tutorials/cloudflare.md b/docs/tutorials/cloudflare.md index d1bce19e2..bd4057317 100644 --- a/docs/tutorials/cloudflare.md +++ b/docs/tutorials/cloudflare.md @@ -18,7 +18,10 @@ Snippet from [Cloudflare - Getting Started](https://api.cloudflare.com/#getting- >The Cloudflare API is a RESTful API based on HTTPS requests and JSON responses. If you are registered with Cloudflare, you can obtain your API key from the bottom of the "My Account" page, found here: [Go to My account](https://dash.cloudflare.com/profile). -The environment vars `CF_API_KEY` and `CF_API_EMAIL` will be needed to run ExternalDNS with Cloudflare. +API Token will be preferred for authentication if `CF_API_TOKEN` environment variable is set. +Otherwise `CF_API_KEY` and `CF_API_EMAIL` should be set to run ExternalDNS with Cloudflare. + +When using API Token authentication the token should be granted Zone `Read` and DNS `Edit` privileges. ## Deploy ExternalDNS diff --git a/go.mod b/go.mod index db42b9b90..7a7854594 100644 --- a/go.mod +++ b/go.mod @@ -13,8 +13,9 @@ require ( github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20180828111155-cad214d7d71f github.com/aws/aws-sdk-go v1.23.18 github.com/cenkalti/backoff v2.1.1+incompatible // indirect - github.com/cloudflare/cloudflare-go v0.0.0-20190102215809-0c85496d8730 + github.com/cloudflare/cloudflare-go v0.10.1 github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 + github.com/codegangsta/cli v1.20.0 // indirect github.com/coreos/bbolt v1.3.2 // indirect github.com/coreos/etcd v3.3.10+incompatible github.com/coreos/go-semver v0.2.0 // indirect @@ -64,7 +65,7 @@ require ( github.com/smartystreets/gunit v1.0.2 // indirect github.com/soheilhy/cmux v0.1.3 // indirect github.com/spf13/cobra v0.0.3 // indirect - github.com/stretchr/testify v1.3.0 + github.com/stretchr/testify v1.4.0 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 // indirect github.com/transip/gotransip v5.8.2+incompatible github.com/ugorji/go/codec v0.0.0-20190320090025-2dc34c0b8780 // indirect diff --git a/go.sum b/go.sum index 320d6255f..b7abecb97 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,8 @@ github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.0.0-20190102215809-0c85496d8730 h1:+TK6ytATp7coqI4UlTBboFYD0kSkWZt6L6/T+1yBK6k= github.com/cloudflare/cloudflare-go v0.0.0-20190102215809-0c85496d8730/go.mod h1:qKQ9S///VKEax9N8kFel9/AvmnkYgvb8uiKTnoVFvpg= +github.com/cloudflare/cloudflare-go v0.10.1 h1:d2CL6F9k2O0Ux0w27LgogJ5UOzZRj6a/hDPFqPP68d8= +github.com/cloudflare/cloudflare-go v0.10.1/go.mod h1:C0Y6eWnTJPMK2ceuOxx2pjh78UUHihcXeTTHb8r7QjU= github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 h1:rdRS5BT13Iae9ssvcslol66gfOOXjaLYwqerEn/cl9s= github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381/go.mod h1:e5+USP2j8Le2M0Jo3qKPFnNhuo1wueU4nWHCXBOfQ14= github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA= @@ -192,6 +194,7 @@ github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:A github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mdempsky/unconvert v0.0.0-20190325185700-2f5dc3378ed3/go.mod h1:9+3Wp2ccIz73BJqVfc7n2+1A+mzvnEwtDTqEjeRngBQ= @@ -286,6 +289,8 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/transip/gotransip v5.8.2+incompatible h1:aNJhw/w/3QBqFcHAIPz1ytoK5FexeMzbUCGrrhWr3H0= @@ -294,6 +299,7 @@ github.com/ugorji/go v1.1.2 h1:JON3E2/GPW2iDNGoSAusl1KDf5TRQ8k8q7Tp097pZGs= github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ugorji/go/codec v0.0.0-20190320090025-2dc34c0b8780 h1:vG/gY/PxA3v3l04qxe3tDjXyu3bozii8ulSlIPOYKhI= github.com/ugorji/go/codec v0.0.0-20190320090025-2dc34c0b8780/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA= +github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ= github.com/vinyldns/go-vinyldns v0.0.0-20190611170422-7119fe55ed92 h1:Q76MzqJu++vAfhj0mVf7t0F4xHUbg+V/d/Uk5PBQjRU= github.com/vinyldns/go-vinyldns v0.0.0-20190611170422-7119fe55ed92/go.mod h1:AZuEfReFWdvtU0LatbLpo70t3lqdLvph2D5mqFP0bkA= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= @@ -369,6 +375,8 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 h1:+DCIGbF/swA92ohVg0//6X2I golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/provider/cloudflare.go b/provider/cloudflare.go index cecb810c3..20b2ce8fe 100644 --- a/provider/cloudflare.go +++ b/provider/cloudflare.go @@ -118,7 +118,13 @@ type cloudFlareChange struct { // NewCloudFlareProvider initializes a new CloudFlare DNS based Provider. func NewCloudFlareProvider(domainFilter DomainFilter, zoneIDFilter ZoneIDFilter, zonesPerPage int, proxiedByDefault bool, dryRun bool) (*CloudFlareProvider, error) { // initialize via API email and API key and returns new API object - config, err := cloudflare.New(os.Getenv("CF_API_KEY"), os.Getenv("CF_API_EMAIL")) + var config *cloudflare.API + var err error + if os.Getenv("CF_API_TOKEN") != "" { + config, err = cloudflare.NewWithAPIToken(os.Getenv("CF_API_TOKEN")) + } else { + config, err = cloudflare.New(os.Getenv("CF_API_KEY"), os.Getenv("CF_API_EMAIL")) + } if err != nil { return nil, fmt.Errorf("failed to initialize cloudflare provider: %v", err) } diff --git a/provider/cloudflare_test.go b/provider/cloudflare_test.go index 024d69f71..7e2423978 100644 --- a/provider/cloudflare_test.go +++ b/provider/cloudflare_test.go @@ -509,9 +509,20 @@ func TestRecords(t *testing.T) { } func TestNewCloudFlareProvider(t *testing.T) { + _ = os.Setenv("CF_API_TOKEN", "abc123def") + _, err := NewCloudFlareProvider( + NewDomainFilter([]string{"ext-dns-test.zalando.to."}), + NewZoneIDFilter([]string{""}), + 25, + false, + true) + if err != nil { + t.Errorf("should not fail, %s", err) + } + _ = os.Unsetenv("CF_API_TOKEN") _ = os.Setenv("CF_API_KEY", "xxxxxxxxxxxxxxxxx") _ = os.Setenv("CF_API_EMAIL", "test@test.com") - _, err := NewCloudFlareProvider( + _, err = NewCloudFlareProvider( NewDomainFilter([]string{"ext-dns-test.zalando.to."}), NewZoneIDFilter([]string{""}), 1, From 0f234eade41e304f80c330630c7370b993d8e647 Mon Sep 17 00:00:00 2001 From: Mike Eves Date: Tue, 17 Sep 2019 11:27:14 +0100 Subject: [PATCH 2/3] Small syntax change --- provider/cloudflare.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/provider/cloudflare.go b/provider/cloudflare.go index 20b2ce8fe..0b4e9d264 100644 --- a/provider/cloudflare.go +++ b/provider/cloudflare.go @@ -117,9 +117,11 @@ type cloudFlareChange struct { // NewCloudFlareProvider initializes a new CloudFlare DNS based Provider. func NewCloudFlareProvider(domainFilter DomainFilter, zoneIDFilter ZoneIDFilter, zonesPerPage int, proxiedByDefault bool, dryRun bool) (*CloudFlareProvider, error) { - // initialize via API email and API key and returns new API object - var config *cloudflare.API - var err error + // initialize via chosen auth method and returns new API object + var ( + config *cloudflare.API + err error + ) if os.Getenv("CF_API_TOKEN") != "" { config, err = cloudflare.NewWithAPIToken(os.Getenv("CF_API_TOKEN")) } else { From 3580908ce48bf91d250220b79c318cc824b618d0 Mon Sep 17 00:00:00 2001 From: Mike Eves Date: Tue, 17 Sep 2019 11:30:24 +0100 Subject: [PATCH 3/3] Formatting --- provider/cloudflare.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/provider/cloudflare.go b/provider/cloudflare.go index 0b4e9d264..f7f5f6360 100644 --- a/provider/cloudflare.go +++ b/provider/cloudflare.go @@ -119,9 +119,9 @@ type cloudFlareChange struct { func NewCloudFlareProvider(domainFilter DomainFilter, zoneIDFilter ZoneIDFilter, zonesPerPage int, proxiedByDefault bool, dryRun bool) (*CloudFlareProvider, error) { // initialize via chosen auth method and returns new API object var ( - config *cloudflare.API - err error - ) + config *cloudflare.API + err error + ) if os.Getenv("CF_API_TOKEN") != "" { config, err = cloudflare.NewWithAPIToken(os.Getenv("CF_API_TOKEN")) } else {