Skip to content

🐛 Local network permissions when running as non-root on macOS #1460

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
IngmarStein opened this issue May 1, 2025 · 4 comments
Open
Labels
Priority: Normal Minor issue impacting one or more users Type: Bug Something isn't working

Comments

@IngmarStein
Copy link

IngmarStein commented May 1, 2025

Describe the bug

When I run cloudflared as a non-root user, installed with cloudflared service install, it can't access any backend service in the local network. Each access results in a log entry like this:

Unable to reach the origin service. The service may be down or it may not be responding to traffic from cloudflared: dial tcp 192.168.1.1:443: connect: no route to host

Any backend on the localhost is accessible, so the tunnel is working overall.

There are no network issues and I can reach this IP just from the host. After launchctl unload ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist and sudo cloudflared service install, the same cloudflared binary with the same command line arguments is able to serve the backends on the local network.

To Reproduce
Steps to reproduce the behavior:

  1. Configure cloudflared to run as a local user
  2. Run launchctl bootstrap gui/501 ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist to start it
  3. Configure a backend on a different machine on the local network
  4. Attempt to access the backend

Expected behavior

I expect cloudflared to behave identically when run as root or a different user.

Environment and versions

  • OS: macOS 15.4.1
  • Architecture: Apple Silicon
  • Version: 2025.04.2

Logs and errors
See above

Additional context
When debugging the issue over Apple Remote Desktop, I got a popup asking whether cloudflared should be allowed local network access. I clicked "yes" and verified that /opt/homebrew/Cellar/cloudflared/2025.4.2/bin/cloudflared is enabled in System Preferences / Privacy & Security / Local Network.

I assume this is related to macOS's security mechanisms.

@IngmarStein IngmarStein added Priority: Normal Minor issue impacting one or more users Type: Bug Something isn't working labels May 1, 2025
@IngmarStein
Copy link
Author

I think I know what is happening:

Per https://developer.apple.com/forums/thread/759955, local network permissions are not applied to processes running as root (this explains why it's working as a launch daemon).
Per https://developer.apple.com/forums/thread/761001, the LC_UUID load command is required to grant the local network permission to a binary. So, even though the dialog pops up and the binary is listed as having the permission, it is not effective if the UUID is missing.
The binary built by the Homebrew formula doesn't have this load command:

otool -l /opt/homebrew/bin/cloudflared | grep -F LC_UUID

It might require -ldflags="-linkmode=external".

@IngmarStein
Copy link
Author

This issue was fixed in Go 1.24: golang/go#68678
The fix was backported to 1.22 and 1.23, but it requires passing -B gobuildid which is the default on 1.24.

The homebrew bottle was built with 1.22.5 and without -B:

❯ go version -m /opt/homebrew/bin/cloudflared
/opt/homebrew/bin/cloudflared: go1.22.5-devel-cf
[…]
	build	-buildmode=exe
	build	-compiler=gc
	build	-ldflags="-X \"main.Version=2025.4.2\" -X \"main.BuildTime=2025-04-30T13:15:20Z\" -X \"github.com/cloudflare/cloudflared/cmd/cloudflared/updater.BuiltForPackageManager=Homebrew\" "
	build	CGO_ENABLED=1
	build	CGO_CFLAGS=
	build	CGO_CPPFLAGS=
	build	CGO_CXXFLAGS=
	build	CGO_LDFLAGS=
	build	GOARCH=arm64
	build	GOOS=darwin

@IngmarStein
Copy link
Author

IngmarStein commented May 2, 2025

I think this is an issue on the cloudflared side and not Homebrew because the project uses Cloudflare's own Go fork which is based on 1.22. Consider bumping this to 1.24 (or at least 1.22.9 with -B gobuildid) which should fix this issue.

IngmarStein added a commit to IngmarStein/cloudflared that referenced this issue May 2, 2025
Fixes cloudflare#1460.

This required fixing new `go vet` findings:

```
tunnelrpc/pogs/configuration_manager.go:99:22: non-constant format string in call to fmt.Errorf
tunnelrpc/pogs/session_manager.go:130:22: non-constant format string in call to fmt.Errorf
ingress/ingress.go:116:20: non-constant format string in call to (*github.com/rs/zerolog.Event).Msgf
ingress/origin_proxy.go:77:21: non-constant format string in call to (*github.com/rs/zerolog.Event).Msgf
cmd/cloudflared/tunnel/subcommands.go:764:31: non-constant format string in call to github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil.UsageError
```
IngmarStein added a commit to IngmarStein/cloudflared that referenced this issue May 2, 2025
Fixes cloudflare#1460.

This required fixing new `go vet` findings:

```
tunnelrpc/pogs/configuration_manager.go:99:22: non-constant format string in call to fmt.Errorf
tunnelrpc/pogs/session_manager.go:130:22: non-constant format string in call to fmt.Errorf
ingress/ingress.go:116:20: non-constant format string in call to (*github.com/rs/zerolog.Event).Msgf
ingress/origin_proxy.go:77:21: non-constant format string in call to (*github.com/rs/zerolog.Event).Msgf
cmd/cloudflared/tunnel/subcommands.go:764:31: non-constant format string in call to github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil.UsageError
```
@IngmarStein
Copy link
Author

@DevinCarr, I believe this bug affects a whole class of users (those who run cloudflared on macOS) and the workaround of running the service as root has negative security implications.

IngmarStein added a commit to IngmarStein/homebrew-core that referenced this issue May 18, 2025
Recent macOS versions require user permissions to use local network
access. This can only be granted for binaries which have a LC_UUID load
command. Go 1.24 adds the UUID by default, but the fix was backported to
Go 1.22.9 and 1.23 where it requires passing `-B gobuildid` to the linker.

Cloudflared uses Cloudflare's Go fork which is based on Go 1.22.5 which
doesn't have the backport. Because of this, cloudflare can't talk to any
machine on the local network (`no route to host`) when it's runnning as
a non-root user.

Upstream bug: cloudflare/cloudflared#1460

This workaround updates the Go fork to `go1.22.12-devel-cf` and adds `-B
gobuildid` so that the binary now has a UUID:

```
❯ dwarfdump --uuid /opt/homebrew/bin/cloudflared
UUID: F2088E17-03A1-34B1-F12C-0DF01F00BA32 (arm64) /opt/homebrew/bin/cloudflared
```
IngmarStein added a commit to IngmarStein/homebrew-core that referenced this issue May 18, 2025
Recent macOS versions require user permissions to use local network
access. This can only be granted for binaries which have a LC_UUID load
command. Go 1.24 adds the UUID by default, but the fix was backported to
Go 1.22.9 and 1.23 where it requires passing `-B gobuildid` to the linker.

Cloudflared uses Cloudflare's Go fork which is based on Go 1.22.5 which
doesn't have the backport. Because of this, cloudflare can't talk to any
machine on the local network (`no route to host`) when it's runnning as
a non-root user.

Upstream bug: cloudflare/cloudflared#1460

This workaround updates the Go fork to `go1.22.12-devel-cf` and adds `-B
gobuildid` so that the binary now has a UUID:

```
❯ dwarfdump --uuid /opt/homebrew/bin/cloudflared
UUID: F2088E17-03A1-34B1-F12C-0DF01F00BA32 (arm64) /opt/homebrew/bin/cloudflared
```
IngmarStein added a commit to IngmarStein/homebrew-core that referenced this issue May 19, 2025
Recent macOS versions require user permissions to use local network
access. This can only be granted for binaries which have a LC_UUID load
command. Go 1.24 adds the UUID by default, but the fix was backported to
Go 1.22.9 and 1.23 where it requires passing `-B gobuildid` to the linker.

Cloudflared uses Cloudflare's Go fork which is based on Go 1.22.5 which
doesn't have the backport. Because of this, cloudflare can't talk to any
machine on the local network (`no route to host`) when it's runnning as
a non-root user.

Upstream bug: cloudflare/cloudflared#1460

This workaround updates the Go fork to `go1.22.12-devel-cf` and adds `-B
gobuildid` so that the binary now has a UUID:

```
❯ dwarfdump --uuid /opt/homebrew/bin/cloudflared
UUID: F2088E17-03A1-34B1-F12C-0DF01F00BA32 (arm64) /opt/homebrew/bin/cloudflared
```
IngmarStein added a commit to IngmarStein/cloudflared that referenced this issue May 19, 2025
Recent macOS versions require user permissions to access the local network. This can only be granted for binaries which have a LC_UUID load command. Go 1.24 adds the UUID by default, but the fix was backported to Go 1.22.9 and 1.23 where it requires passing `-B gobuildid` to the linker.

cloudflared uses Cloudflare's Go fork which is based on Go 1.22.5 and doesn't have the backport. Because of this, cloudflared can't talk to any machine on the local network (no route to host) when it's runnning as a non-root user.

This workaround updates the Go fork to go1.22.12-devel-cf and adds `-B gobuildid` so that the binary now has a UUID:

```
❯ dwarfdump --uuid /opt/homebrew/bin/cloudflared
UUID: F2088E17-03A1-34B1-F12C-0DF01F00BA32 (arm64) /opt/homebrew/bin/cloudflared
```

Fixes cloudflare#1460
IngmarStein added a commit to IngmarStein/cloudflared that referenced this issue May 19, 2025
Recent macOS versions require user permissions to access the local network. This can only be granted for binaries which have a LC_UUID load command. Go 1.24 adds the UUID by default, but the fix was backported to Go 1.22.9 and 1.23 where it requires passing `-B gobuildid` to the linker.

cloudflared uses Cloudflare's Go fork which is based on Go 1.22.5 and doesn't have the backport. Because of this, cloudflared can't talk to any machine on the local network (no route to host) when it's runnning as a non-root user.

This workaround updates the Go fork to go1.22.12-devel-cf and adds `-B gobuildid` so that the binary now has a UUID:

```
❯ dwarfdump --uuid /opt/homebrew/bin/cloudflared
UUID: F2088E17-03A1-34B1-F12C-0DF01F00BA32 (arm64) /opt/homebrew/bin/cloudflared
```

Fixes cloudflare#1460
IngmarStein added a commit to IngmarStein/cloudflared that referenced this issue May 19, 2025
Recent macOS versions require user permissions to access the local network. This can only be granted for binaries which have a LC_UUID load command. Go 1.24 adds the UUID by default, but the fix was backported to Go 1.22.9 and 1.23 where it requires passing `-B gobuildid` to the linker.

cloudflared uses Cloudflare's Go fork which is based on Go 1.22.5 and doesn't have the backport. Because of this, cloudflared can't talk to any machine on the local network (no route to host) when it's runnning as a non-root user.

This workaround updates the Go fork to go1.22.12-devel-cf and adds `-B gobuildid` so that the binary now has a UUID:

```
❯ dwarfdump --uuid /opt/homebrew/bin/cloudflared
UUID: F2088E17-03A1-34B1-F12C-0DF01F00BA32 (arm64) /opt/homebrew/bin/cloudflared
```

Fixes cloudflare#1460
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Priority: Normal Minor issue impacting one or more users Type: Bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant