diff --git a/docs/tutorials/cloudflare.md b/docs/tutorials/cloudflare.md index 04ea012c4..ea2c762c8 100644 --- a/docs/tutorials/cloudflare.md +++ b/docs/tutorials/cloudflare.md @@ -44,6 +44,7 @@ spec: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. - --provider=cloudflare + - --cloudflare-proxied # (optional) enable the proxy feature of Cloudflare (DDOS protection, CDN...) env: - name: CF_API_KEY value: "YOUR_CLOUDFLARE_API_KEY" diff --git a/main.go b/main.go index 45a6176ef..e9879c709 100644 --- a/main.go +++ b/main.go @@ -92,7 +92,7 @@ func main() { case "azure": p, err = provider.NewAzureProvider(cfg.AzureConfigFile, domainFilter, cfg.AzureResourceGroup, cfg.DryRun) case "cloudflare": - p, err = provider.NewCloudFlareProvider(domainFilter, cfg.DryRun) + p, err = provider.NewCloudFlareProvider(domainFilter, cfg.CloudflareProxied, cfg.DryRun) case "google": p, err = provider.NewGoogleProvider(cfg.GoogleProject, domainFilter, cfg.DryRun) case "digitalocean": diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 9e2d2bf73..a880f1920 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -40,6 +40,7 @@ type Config struct { DomainFilter []string AzureConfigFile string AzureResourceGroup string + CloudflareProxied bool Policy string Registry string TXTOwnerID string @@ -65,6 +66,7 @@ var defaultConfig = &Config{ DomainFilter: []string{}, AzureConfigFile: "/etc/kubernetes/azure.json", AzureResourceGroup: "", + CloudflareProxied: false, Policy: "sync", Registry: "txt", TXTOwnerID: "default", @@ -105,6 +107,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter) app.Flag("azure-config-file", "When using the Azure provider, specify the Azure configuration file (required when --provider=azure").Default(defaultConfig.AzureConfigFile).StringVar(&cfg.AzureConfigFile) app.Flag("azure-resource-group", "When using the Azure provider, override the Azure resource group to use (optional)").Default(defaultConfig.AzureResourceGroup).StringVar(&cfg.AzureResourceGroup) + app.Flag("cloudflare-proxied", "When using the Cloudflare provider, specify if the proxy mode must be enabled (default: disabled)").BoolVar(&cfg.CloudflareProxied) // Flags related to policies app.Flag("policy", "Modify how DNS records are sychronized between sources and providers (default: sync, options: sync, upsert-only)").Default(defaultConfig.Policy).EnumVar(&cfg.Policy, "sync", "upsert-only") diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go index 061027e16..83f235f40 100644 --- a/pkg/apis/externaldns/types_test.go +++ b/pkg/apis/externaldns/types_test.go @@ -38,6 +38,7 @@ var ( DomainFilter: []string{""}, AzureConfigFile: "/etc/kubernetes/azure.json", AzureResourceGroup: "", + CloudflareProxied: false, Policy: "sync", Registry: "txt", TXTOwnerID: "default", @@ -62,6 +63,7 @@ var ( DomainFilter: []string{"example.org", "company.com"}, AzureConfigFile: "azure.json", AzureResourceGroup: "arg", + CloudflareProxied: true, Policy: "upsert-only", Registry: "noop", TXTOwnerID: "owner-1", @@ -105,6 +107,7 @@ func TestParseFlags(t *testing.T) { "--google-project=project", "--azure-config-file=azure.json", "--azure-resource-group=arg", + "--cloudflare-proxied", "--domain-filter=example.org", "--domain-filter=company.com", "--policy=upsert-only", @@ -135,6 +138,7 @@ func TestParseFlags(t *testing.T) { "EXTERNAL_DNS_GOOGLE_PROJECT": "project", "EXTERNAL_DNS_AZURE_CONFIG_FILE": "azure.json", "EXTERNAL_DNS_AZURE_RESOURCE_GROUP": "arg", + "EXTERNAL_DNS_CLOUDFLARE_PROXIED": "1", "EXTERNAL_DNS_DOMAIN_FILTER": "example.org\ncompany.com", "EXTERNAL_DNS_POLICY": "upsert-only", "EXTERNAL_DNS_REGISTRY": "noop", diff --git a/provider/cloudflare.go b/provider/cloudflare.go index bbe4fdeb9..2f01d2b27 100644 --- a/provider/cloudflare.go +++ b/provider/cloudflare.go @@ -84,6 +84,7 @@ type CloudFlareProvider struct { Client cloudFlareDNS // only consider hosted zones managing domains ending in this suffix domainFilter DomainFilter + proxied bool DryRun bool } @@ -94,7 +95,7 @@ type cloudFlareChange struct { } // NewCloudFlareProvider initializes a new CloudFlare DNS based Provider. -func NewCloudFlareProvider(domainFilter DomainFilter, dryRun bool) (*CloudFlareProvider, error) { +func NewCloudFlareProvider(domainFilter DomainFilter, proxied 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")) if err != nil { @@ -104,6 +105,7 @@ func NewCloudFlareProvider(domainFilter DomainFilter, dryRun bool) (*CloudFlareP //Client: config, Client: zoneService{config}, domainFilter: domainFilter, + proxied: proxied, DryRun: dryRun, } return provider, nil @@ -159,9 +161,9 @@ func (p *CloudFlareProvider) Records() ([]*endpoint.Endpoint, error) { func (p *CloudFlareProvider) ApplyChanges(changes *plan.Changes) error { combinedChanges := make([]*cloudFlareChange, 0, len(changes.Create)+len(changes.UpdateNew)+len(changes.Delete)) - combinedChanges = append(combinedChanges, newCloudFlareChanges(cloudFlareCreate, changes.Create)...) - combinedChanges = append(combinedChanges, newCloudFlareChanges(cloudFlareUpdate, changes.UpdateNew)...) - combinedChanges = append(combinedChanges, newCloudFlareChanges(cloudFlareDelete, changes.Delete)...) + combinedChanges = append(combinedChanges, newCloudFlareChanges(cloudFlareCreate, changes.Create, p.proxied)...) + combinedChanges = append(combinedChanges, newCloudFlareChanges(cloudFlareUpdate, changes.UpdateNew, p.proxied)...) + combinedChanges = append(combinedChanges, newCloudFlareChanges(cloudFlareDelete, changes.Delete, p.proxied)...) return p.submitChanges(combinedChanges) } @@ -266,24 +268,24 @@ func (p *CloudFlareProvider) getRecordID(records []cloudflare.DNSRecord, record } // newCloudFlareChanges returns a collection of Changes based on the given records and action. -func newCloudFlareChanges(action string, endpoints []*endpoint.Endpoint) []*cloudFlareChange { +func newCloudFlareChanges(action string, endpoints []*endpoint.Endpoint, proxied bool) []*cloudFlareChange { changes := make([]*cloudFlareChange, 0, len(endpoints)) for _, endpoint := range endpoints { - changes = append(changes, newCloudFlareChange(action, endpoint)) + changes = append(changes, newCloudFlareChange(action, endpoint, proxied)) } return changes } -func newCloudFlareChange(action string, endpoint *endpoint.Endpoint) *cloudFlareChange { +func newCloudFlareChange(action string, endpoint *endpoint.Endpoint, proxied bool) *cloudFlareChange { return &cloudFlareChange{ Action: action, ResourceRecordSet: cloudflare.DNSRecord{ Name: endpoint.DNSName, // TTL Value of 1 is 'automatic' TTL: 1, - Proxied: false, + Proxied: proxied, Type: endpoint.RecordType, Content: endpoint.Target, }, diff --git a/provider/cloudflare_test.go b/provider/cloudflare_test.go index a260fbc48..0f2ad14f9 100644 --- a/provider/cloudflare_test.go +++ b/provider/cloudflare_test.go @@ -338,7 +338,7 @@ func (m *mockCloudFlareUpdateRecordsFail) ListZones(zoneID ...string) ([]cloudfl func TestNewCloudFlareChanges(t *testing.T) { action := cloudFlareCreate endpoints := []*endpoint.Endpoint{{DNSName: "new", Target: "target"}} - _ = newCloudFlareChanges(action, endpoints) + _ = newCloudFlareChanges(action, endpoints, true) } func TestCloudFlareZones(t *testing.T) { @@ -382,13 +382,13 @@ func TestRecords(t *testing.T) { func TestNewCloudFlareProvider(t *testing.T) { _ = os.Setenv("CF_API_KEY", "xxxxxxxxxxxxxxxxx") _ = os.Setenv("CF_API_EMAIL", "test@test.com") - _, err := NewCloudFlareProvider(NewDomainFilter([]string{"ext-dns-test.zalando.to."}), true) + _, err := NewCloudFlareProvider(NewDomainFilter([]string{"ext-dns-test.zalando.to."}), false, true) if err != nil { t.Errorf("should not fail, %s", err) } _ = os.Unsetenv("CF_API_KEY") _ = os.Unsetenv("CF_API_EMAIL") - _, err = NewCloudFlareProvider(NewDomainFilter([]string{"ext-dns-test.zalando.to."}), true) + _, err = NewCloudFlareProvider(NewDomainFilter([]string{"ext-dns-test.zalando.to."}), false, true) if err == nil { t.Errorf("expected to fail") }