How does a CDN actually prevent DDoS attacks, when an origin server accepts direct connections?

IP whitelist is an imperfect solution because it's fiddly. CloudFlare's global network of reverse proxies themselves aren't necessarily a static list of IP addresses. If CloudFlare added new IP Range, some of CloudFlare's servers may not be able to reach your Origin server until you update your Firewall, and your application could be experiencing a brownout for many of your users that you may never notice and is really hard to debug even when you do because everything is working perfectly fine from your vantage point. The maintenance busywork to keep the whitelist of IP addresses on your firewall up to date will be just as problematic as handling a DDoS.

The main idea of CloudFlare's CDN protection is by hiding your Origin Server's real IP address from publicly accessible database like the DNS system. This makes it much more difficult for an attacker to discover where to direct their attack to your Origin server.

Additionally, if your firewall appliance can actually handle the direct DDoS load, then your attacker is probably not big enough yet for you to actually be needing a DDoS protection. So the suggestion to just skip town and change your public IP is sensible as it's likely the fastest way to alleviate the impact of an active attack.

CloudFlare's solution to protect your Origin Server from direct traffic is to use Authenticated Origin Pull (free), which would have CloudFlare use a TLS Client certificate when making a connection to your Origin server, or Argo Tunnel (additional cost), which will require you to run a cloudflare agent daemon inside your network to maintain an outgoing connection to one of CloudFlare's point of presence.