I've seen how nodes gather network time data, but how is it enforced in the blockchain?
Are all of the timestamps digitally signed and included in the block as proof?
First, where do these time samples come from: when your client connects to peers in the network it exchanges a
version message with them. Among other things this message contains the current UTC timestamp at the peer. Your client then calculates an offset between the time at its peer and its own clock. The network time is simply the local timestamp + the median of all offsets of its peers. So you can see that we have a relatively simple attempt at synchronizing the clocks in the network, but depending on the sample of peers you connect to they can still vary wildly.
About enforcing the timestamps: there are very few places the timestamp appears in the communication between peers, likely the only place where it is actually enforced is in the block header. Should a peer receive a new block while being synched with the network, and the timestamp differs more than 2 hours from its local timestamp, it'll discard the block as invalid (source). The idea behind this check is that a client could attempt to skew the perceived difficulty seen by a node that is synchronizing with the rest of the network.