Here's a somewhat simpler version than MarkF's one, also using discrete MOSFETs and one I/O pin. It does need two diodes, but if you use
BAT54C, you get two in one package.
The button turns on the P-MOSFET when pushed, and also pulls the Arduino GPIO low so button pushes can be detected. The diodes keep the GPIO level and PMOS gate level separate.
To keep the power on after the user releases the button, enable the GPIO's weak pullup, which keeps the N-MOSFET gate high, which keeps the P-MOSFET on. N.B. The N-MOSFET gate pulldown *MUST* be large compared to the Arduino internal weak pullup, which is max. 50K.
To turn the power off, the Arduino sets the GPIO to Output Low. Power off will be delayed if the user is holding the button down. Unlike Mark's, holding the button down wont force poweroff if the Arduino is crashed.
A 330R resistor is included to protect against mistakes like setting the GPIO to Output High while the button is pushed.
LTspice sim attached (including model of Arduino code controlled behaviour).