Here's a script I use to clip rasters by shapefiles--note that it returns a raster object that contains the array, masking, and georeferencing. It would be another step to write the array as a geotiff, but not a difficult one. Note that you need to install the fiona and rasterstats packages.
import fiona
from rasterstats.io import Raster
def clip_raster_by_shp(rasterpath, shppath, band=1):
"""
Given an input raster (path) and shapefile (path), returns the raster object
corresponding to the raster defined by the bounds of the shapefile
"""
with fiona.open(shppath) as f:
geom_bounds = f.bounds
with Raster(rasterpath, band=band) as raster_obj:
rast = raster_obj.read(bounds=geom_bounds)
return rast
To see what the rast object contains, after running this type rast. then press tab (this assumes you're using an IDE like Spyder). But if you're not manipulating the clipped raster and you need to save it as a geotiff, I would definitely go with the other answer.