Yoshimar Yotun had given Peru the lead in the first half only for Juan Cuadrado to equalise with a free-kick shortly after the break.
Diaz then put Colombia in front before a Gianluca Lapadula’s 82nd-minute header levelled the match again.
A penalty shootout looked on the cards but Diaz scored in the 94th minute.
“We’re happy – it was important to finish by winning,” said Cuadrado. “I’m happy with how we reacted [to going behind] and how we went after the result.”
Argentina, who beat Colombia on penalties in their semi-final, will play host Brazil, who beat Peru 1-0, in the final on Sunday in a game that the whole world is looking up to.