Is this implementation of signed URLs reasonably secure?
It looks like a rather straightforward use of HMAC. So I would presume it is safe from that perspective.

A note about terminology. Personally I would talk about an authentication tag or simply HMAC value because people often associate signatures with asymmetric algorithms such as RSA. The same goes for "private key"; I'd use secret key for symmetric keys as in your code.

Some remarks:


the regular expression is used twice, it seems more logical to match the entire GET request and make sure it ends with the group with the signature in it (even if that just means using .*);
to remove one way of attacks, I'd make sure that there aren't two authentication tags in the GET request;
to remove another, I'd include a sequence number or time stamp so that replay attacks are not possible;
hexadecimals are not very efficient, I'd use a base64url encoder, it's made for it;
the groups count check is unnecessary, either the regex matches or it doesn't.


One idea is to have a method split the URI and the signature, you don't need the authentication tag after verification after all - you could for instance use a tuple with the verification status and the URL without signature (as optional value), or use a yucky output parameter. Check your coding standards before doing either of these though.