Kennedy (13-3) gave up two runs, six hits and struck out seven to help Arizona move one game behind first-place San Francisco in the National League West. The Giants have lost four straight.
Willie Bloomquist had a two-run single to cap a five-run sixth inning as Arizona won its third straight contest and seventh in nine games.
Arizona's J.J. Putz allowed back-to-back singles in the ninth before retiring Aaron Rowand on a liner to right for his 25th save.
The Giants had the tying run at the plate in the eighth when Kennedy induced Carlos Beltran to hit into an inning-ending double play.
Cain, who had beaten Arizona three times this season, gave up five runs and eight hits in 5 2/3 innings.