AWS S3 Secure Image Upload
For Feature Requests
Desired Feature: Secure image uploads (require auth) with S3 storage backend (the S3 version of #551 / #665)
Expected Behavior
Same user experience as local secure uploads, but via AWS S3 signed URLs. Also -- and I'm not sure how this would work now since the local secure feature has already been released -- but ideally it wouldn't use a 'new' storage method, but just add an 'authed images' flag. However, I'm sure that there's a good reason why it was implemented with a new storage method previously... Ideally, there would also be a streamlined way to migrate to secure images as well.
I'm not sure if I should create another feature request, but I too would like to see something like this build into Bookstack. Perhaps a more broader idea in the sense that it applies to maybe mounting a S3 bucket that can can operate outside of Bookstack to include media assets in bookstack. My use case is videos mainly. If uploading to S3 storage, it puts the video into a page as an attachment. But if I want to embed it from a bucket that is 'publicly' available a signed url would be much better than a direct url to prevent unauthorized access or a sharing of a URL bypassing Bookstack. S3 complaint storage supports this. Cloudflare supports this in their streaming service as well.
https://developers.cloudflare.com/stream/viewing-videos/securing-your-stream https://docs.min.io/docs/upload-files-from-browser-using-pre-signed-urls.html
Both uploads and downloads for S3 type storage would be great. This likely would require handling these type of attachments differently than local storage. This would allow using a true cdn to serve content authenticated without needing to load it through bookstack attachment process. Context would be loaded for example via cdn.domain.com rather than bookstackdomain.com/attachment/3
Does anyone have a workaround for this?
We implemented a logical theme for signed s3 image urls:
functions.php:
use BookStack\Facades\Theme;
use BookStack\Http\Controller;
use BookStack\Theming\ThemeEvents;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Filesystem\FilesystemManager;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Route;
class S3Controller extends Controller{
public function __construct(
protected FilesystemManager $fileSystem,
) {
}
public function signedRedirect($path){
$disk = $this->fileSystem->disk('s3');
$url = $disk->temporaryUrl($path, Carbon::now()->addMinutes(5));
return redirect()->away($url);
}
}
Theme::listen(ThemeEvents::ROUTES_REGISTER_WEB, function(){
Route::middleware('auth')->group(function(){
Route::get('/s3/{path}', [S3Controller::class, 'signedRedirect'])->where('path', '.*');
});
});
.env:
STORAGE_TYPE=s3
STORAGE_S3_KEY=your-key
STORAGE_S3_SECRET=your-secret
STORAGE_S3_BUCKET=your-bucket
STORAGE_S3_REGION=your-region
STORAGE_S3_ENDPOINT=https://s3.your-region.your-provider.tld
STORAGE_URL=https://your.bookstack.domain.tld/s3/
The STORAGE_URL points to the S3Controller which is redirecting to the signed s3 url. The signed URLs are only valid for 5 minutes and the S3Controller itself requires a valid BookStack session.
What I have tested looks like that Presigned URLs is also required with Garage .
I tested with following config:
STORAGE_TYPE=s3 STORAGE_S3_KEY=keyxxx STORAGE_S3_SECRET=secretxxx STORAGE_S3_BUCKET=bookstack-bucket STORAGE_S3_ENDPOINT=https://s3.domain.com STORAGE_S3_REGION=garage STORAGE_URL=https://s3.domain.com/bookstack-bucket
Image upload worked but Bookstack showed only links instead of image and when clicked link I got
Forbidden: Garage does not support anonymous access yet
Would love to see this feature added please.