How do we properly perform CGNAT on a MikroTik Router for customers?

For connections between a peer inside your 10.64.0.0/10 and a peer out there in the internet - yes. For connections between two of your peers, it will be more interesting.

In order that it worked, you need to src-nat also the connections your clients initiate towards the addresses in your public /25 range, but that’s not enough. If two clients initiate such connection, RouterOS creates an independent tracked connection for each of them, and it cannot match them together and merge them. So you need the following arrangement (roughly, adapt it to your actual configuration):

/interface bridge add name=br-lo protocol-mode=none
/ip address add address=127.0.0.11/32 interface=br-lo
/ip address add address=127.0.0.12/32 interface=br-lo
/interface ipip add name=hairpin-1 local-address=127.0.0.11 remote-address=127.0.0.12
/interface ipip add name=hairpin-2 local-address=127.0.0.12 remote-address=127.0.0.11
/ip route rule add interface=hairpin-1 dst-address=your.public.sub.net/25 action=drop
/ip route rule add interface=hairpin-2 dst-address=your.public.sub.net/25 action=drop
/ip route add dst-address=your.public.sub.net/25 gateway=hairpin-1,hairpin-2

The addresses from the /25 subnet you use for src-nat must not be assigned to any interface of the router itself, otherwise it won’t work because packets for any address on the router itself are not routed, unless they get dst-nated at arrival.

The route must have both ends of the IPIP tunnel as gateways because if you set rp-filter to strict (which you may want to do as you are an ISP so dropping forged packets saves you some problems). The action=drop routing rules are there to prevent the packets from looping through the hairpin tunnel until the second tracked connection gets created.