From f87f80ae966e85f961b7e8fb598e00350651d3ec Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 9 Oct 2026 13:52:20 +0200 Subject: [PATCH] feat(dns): add opt-in Cloudflare proxy mode for new DNS records --- .../Security/IntegrationTokenEditor.php | 9 ++++++ .../Security/IntegrationTokenForm.php | 7 ++++ app/Models/IntegrationToken.php | 6 ++++ app/Services/Dns/CloudflareDnsProvider.php | 3 +- .../integration-token-editor.blade.php | 7 ++++ .../security/integration-token-form.blade.php | 7 ++++ tests/Feature/DnsProviderManagementTest.php | 17 ++++++++++ .../Security/IntegrationTokenFormTest.php | 32 +++++++++++++++++++ 8 files changed, 87 insertions(+), 1 deletion(-) diff --git a/app/Livewire/Security/IntegrationTokenEditor.php b/app/Livewire/Security/IntegrationTokenEditor.php index 66310c104e..16a7f0ad9b 100644 --- a/app/Livewire/Security/IntegrationTokenEditor.php +++ b/app/Livewire/Security/IntegrationTokenEditor.php @@ -30,6 +30,8 @@ class IntegrationTokenEditor extends Component public bool $automaticDns = true; + public bool $proxiedDns = false; + public function mount(string $integration_token_uuid): void { $this->integrationToken = IntegrationToken::ownedByCurrentTeam() @@ -43,6 +45,7 @@ class IntegrationTokenEditor extends Component $this->metadata = $this->integrationToken->metadata ?? []; $this->loadZones(); $this->automaticDns = $this->integrationToken->automaticDnsEnabled(); + $this->proxiedDns = $this->integrationToken->proxiedDnsEnabled(); } protected function rules(): array @@ -55,6 +58,7 @@ class IntegrationTokenEditor extends Component 'capabilities' => ['required', 'array', 'min:1'], 'capabilities.*' => ['required', 'in:'.$allowedCapability], 'automaticDns' => ['boolean'], + 'proxiedDns' => ['boolean'], ]; if ($this->integrationToken->provider === 'infisical') { @@ -91,6 +95,11 @@ class IntegrationTokenEditor extends Component } else { $metadata['automatic_dns'] = false; } + if ($validated['proxiedDns']) { + $metadata['proxied_dns'] = true; + } else { + unset($metadata['proxied_dns']); + } } $storedMetadata = $this->integrationToken->metadata ?? []; $changedConnectionFields = $this->changedConnectionFields($provider, $storedMetadata, $metadata); diff --git a/app/Livewire/Security/IntegrationTokenForm.php b/app/Livewire/Security/IntegrationTokenForm.php index e07e22db0b..3cfbc75aa7 100644 --- a/app/Livewire/Security/IntegrationTokenForm.php +++ b/app/Livewire/Security/IntegrationTokenForm.php @@ -27,6 +27,8 @@ class IntegrationTokenForm extends Component public bool $automaticDns = true; + public bool $proxiedDns = false; + public function mount(): void { $this->authorize('create', IntegrationToken::class); @@ -38,6 +40,7 @@ class IntegrationTokenForm extends Component $this->capabilities = ['dns']; $this->metadata = []; $this->automaticDns = true; + $this->proxiedDns = false; } else { $this->capabilities = ['secrets']; $this->metadata = $this->provider === 'infisical' @@ -57,6 +60,7 @@ class IntegrationTokenForm extends Component 'capabilities' => ['required', 'array', 'min:1'], 'capabilities.*' => ['required', 'in:'.$allowedCapability], 'automaticDns' => ['boolean'], + 'proxiedDns' => ['boolean'], ]; if ($this->provider === 'infisical') { @@ -94,6 +98,9 @@ class IntegrationTokenForm extends Component if ($validated['provider'] === 'cloudflare' && ! $validated['automaticDns']) { $metadata['automatic_dns'] = false; } + if ($validated['provider'] === 'cloudflare' && $validated['proxiedDns']) { + $metadata['proxied_dns'] = true; + } try { if (! $validator->validate($validated['provider'], $validated['token'], $validated['capabilities'], $metadata)) { diff --git a/app/Models/IntegrationToken.php b/app/Models/IntegrationToken.php index 25c2f55939..119c8d95df 100644 --- a/app/Models/IntegrationToken.php +++ b/app/Models/IntegrationToken.php @@ -76,6 +76,12 @@ class IntegrationToken extends BaseModel return $this->provider === 'cloudflare' && data_get($this->metadata, 'automatic_dns', true) !== false; } + /** New Cloudflare records are created proxied (orange cloud) when enabled, so the server IP is not exposed. */ + public function proxiedDnsEnabled(): bool + { + return $this->provider === 'cloudflare' && data_get($this->metadata, 'proxied_dns') === true; + } + public function dopplerTokenType(): ?string { if ($this->provider !== 'doppler') { diff --git a/app/Services/Dns/CloudflareDnsProvider.php b/app/Services/Dns/CloudflareDnsProvider.php index 9cc64beb4b..995a632f8a 100644 --- a/app/Services/Dns/CloudflareDnsProvider.php +++ b/app/Services/Dns/CloudflareDnsProvider.php @@ -153,7 +153,8 @@ class CloudflareDnsProvider $uuid = new_public_id(); $response = $this->client($zone->integrationToken)->post("https://api.cloudflare.com/client/v4/zones/{$zone->provider_zone_id}/dns_records", [ - 'type' => $type, 'name' => $hostname, 'content' => $content, 'ttl' => 1, 'proxied' => false, + 'type' => $type, 'name' => $hostname, 'content' => $content, 'ttl' => 1, + 'proxied' => $zone->integrationToken->proxiedDnsEnabled(), 'comment' => ManagedDnsRecord::ownershipCommentFor($uuid), ]); if (! $response->successful() || ! is_string($response->json('result.id'))) { diff --git a/resources/views/livewire/security/integration-token-editor.blade.php b/resources/views/livewire/security/integration-token-editor.blade.php index 9a558939ba..ed7d108aed 100644 --- a/resources/views/livewire/security/integration-token-editor.blade.php +++ b/resources/views/livewire/security/integration-token-editor.blade.php @@ -50,6 +50,13 @@ Create DNS records automatically when a new domain has one unambiguous matching credential.
++ Create new DNS records with the Cloudflare proxy on (orange cloud), so the server IP is not public. Existing records keep their proxy status. +
++ Create new DNS records with the Cloudflare proxy on (orange cloud), so the server IP is not public. Existing records keep their proxy status. +
+