France saw far less of the ball than Germany throughout the 90 minutes but they were devastatingly effective with the chances they had.
Antoine Griezmann gave them the lead of the stroke of half time from the penalty spot when Bastian Schweinsteiger was adjudged to have handled the ball in the box.
Despite their continued dominance, they found themselves two down in the 72nd minute as Griezmann poked the ball through Manuel Neuer's legs.
The Euros hosts began the game well and Griezmann showed his skill in the seventh minute to dance past three German defenders before hitting a low drive towards the bottom corner, but Manuel Neuer did well to get down and make the save.
Germany soon began to play themselves into the game and Emre Can tested Hugo Lloris with a deflected effort from the edge of the area, but the French goalkeeper was equal to it.
The Germans began to dominate proceedings, starving France of the ball. Mesut Ozil had a shot blocked and the rebound fell for Bastian Schweinsteiger, who took a chance from long range and forced Lloris to tip the ball over the bar.
France came back into the game towards the end of the first half and Samuel Umtiti played Dimitri Payet through on the left wing with a killer throughball. The West Ham playmaker beat his man before squaring for Griezmann, who's shot from a tight angle hit the side netting.
Jerome Boateng then mistimed a header on the halfway line to allow Olivier Giroud clean through on goal, but Benedikt Howedes got across brilliantly to execute a last-ditch diving tackle to deny the Arsenal striker.
On the stroke of half time, Schweinsteiger was blown up for handball in the box giving France a magnificent opportunity to take the lead from the penalty spot. Griezmann stepped up and buried the spot kick to give them a slightly undeserved 1-0 lead at half time.
Again, France were the better of the two sides at the start of the second half and Germany's defence had to be on their toes to block two chances early on.
The same pattern as the first half resumed as Germany clung on to possession and looked for openings.
However, another piece of poor defending cost them as Joshua Kimmich was caught on the ball by Paul Pogba, who poached it and lofted a looping cross into the German box. Manuel Neuer came out to punch it, but made a hash of it letting the ball fall for Griezmann, who poked the ball through the German keeper's legs to double the hosts advantage in the 72nd minute.
Germany then began to pile on the pressure but it was just one of those nights when nothing would go their way.
Kimmich hit a long range blast that looked destined for the top corner, but hit the outside of the post and bounced out for a goal kick.
Julian Draxler and Leroy Sane were both denied by fantastic saves from Lloris before Shkodran Mustafi and Howedes sent headers inches over the bar, but the hosts clung on for dear life and booked their place in the European Championship final against Portugal.