samvera / serverless-iiif

IIIF Image API 2.1 & 3.0 server in an AWS Serverless Application
https://samvera.github.io/serverless-iiif/
Apache License 2.0
69 stars 21 forks source link

Question: is there a recommended approach for securing access to the IIIF resources #81

Closed ryantomaselli closed 1 year ago

ryantomaselli commented 1 year ago

Hey @mbklein :)

The IIIF server is working great...we're deploying the cloudfront option using sam deploy.

Is there a recommended approach to providing security around access to the images. Like say we wanted to do a database look up, verify credentials or check some other business rules before honoring the request.

Do you have insights into that side of things?

All insights appreciated.

mbklein commented 1 year ago

Yes, absolutely! Take a look at the Advanced Usage section of the README. What you'd need to do is write and deploy a Lambda@Edge Function. The function can either alter the incoming request (i.e., add/delete/change headers, query parameters, whatever) or return an HTTP result outright, telling CloudFront to skip calling the Origin and just return what you sent back. A simple auth function would look like this:

module.exports = async (event) => {
  const authed = await decideWhetherToAllowAccess(event);

  if (!authed) {
    return {
       statusCode: 403,
       statusDescription: 'Unauthorized'
     };    
  }

  return event;
}

The entire HTTP request (along with some other metadata) is available to you in the event object.

Once you've deployed that function, you'd configure serverless-iiif to use it by adding

ViewerRequestARN: [Qualified ARN of the Lambda@Edge Function you just created]
ViewerRequestType: Lambda@Edge

You'll also see references to CloudFront Functions, but those can't have dependencies or network access, so their functionality is far more limited. If you want to auth via a DB lookup or an API call, you'll need to use Lambda@Edge.

ryantomaselli commented 1 year ago

Super appreciate the detailed response, this is great.

Thanks @mbklein

ryantomaselli commented 1 year ago

One thing I noticed is that the deploy fails if I don't provide the version for the Viewer Request Lambda (as in qualify the arn with version number.

To get past this I had publish a new version and then reference the version qualified arn.

Resource handler returned message: "Invalid request provided: The function ARN must reference a specific function version. (The ARN must end with the version number.) ARN: arn:aws:lambda:us-east-1:xxxxxxxxxxxxx:function:CheckAuthIIIFImageRequest-xxxxxxxxxxx (Service: CloudFront, Status Code: 400, Request ID: xxxxxxxxxxx)
fitnycdigitalinitiatives commented 1 year ago

It doesn't have good documentation but you can take a look at our authentication function that we based off what Michael did at Northwestern: https://github.com/fitnycdigitalinitiatives/iiif-authenticate

Basically, we have a DynamoDB listing every image key and whether it's public or private, and when a request comes in it checks whether it's a public image to let it through, if not, it checks for the presence of a valid JWT that would only be sent if someone is logged into our repository system. It's very simple.

mbklein commented 1 year ago

That's almost identical to what we do, @fitnycdigitalinitiatives, except our "source of truth" is part of an OpenSearch document instead of a DyanmoDB table.

ryantomaselli commented 1 year ago

I really appreciate both you guys sharing all this...it's really made my Friday