Product(123) -> You should return the single entity in your response payload
Product(123)?$filter=sku eq 123 -> That doesn't really make sense - filter is supposed to apply to collections of entities, and Product(123) identifies a single entity (always). Many OData services today ignore this due to the behavior or early server stacks, but a 400 is acceptable since the query option does not apply.
Product?$filter=sku eq 123 -> Product identifies an entity set, so a collection of entities (AKA feed) should be returned. Even though your particular query happens to identify a single entity, a feed with a single entity in it is REQUIRED response.
Product?$filter=title eq 'Some handy product' -> This is the same as sku eq 123 in terms of the expected response. Even though it might identify a single resource, this does not change the fact that an entity set must still contain a feed as a response.
You said that you wanted to hold the rule that one entity has one URL. In OData, one URL identifies an entity, though multiple URLs could give you the same information about it. So, I'd argue that you are OK. The one URL that identifies a resource is called the canonical URL. Product(123) is a canonical URL. In, say, a JSON payload, the odata.id would give the canonical URL of an entity.
So what about these other queries that SEEM to reference the same entity? In your valid filter examples (the 3rd and 4th ones), your path identifies a COLLECTION as I indicated above. The fact that the collection happens to contain just one entity is irrelevant. The path that IDENTIFIES the resource is still Product(123). Other URLs can give give information about that entity without 'identifying' it. So I don't think that you've broken you're statement in any way.
To answer the 3xx part of your question: You are always free to respond to a request with some sort of redirect - that is part of HTTP, and OData does not change that. However, to redirect to something that is not the same shape as the original request would be a bad server behavior. For instance, Product(123)?$filter=whatever identifies a Collection of Product entities. To redirect to Product(123) would be a bad idea in my opinion, since it identifies a single entity. The response that you would write out would look different! I'd be surprised if any existing OData clients could handle that, and I wouldn't expect new ones to handle it either.
What does this mean for HTTP Caching? Well, quite frankly, at least in the scenario's given, I don't think you should do anything special.