The following steps outline how to create an S3 bucket for ObjectFS, configure moodle to use this, and then how to implement the CloudFront CDN (Content Delivery Network) to securely sit infront of the S3 Bucket, so that content delivery maybe off-loaded from the moodle servers to the CDN. This will typically result in faster access for users to content due do caching by the CDN, and less load on the moodle servers.
The following steps implement the following high level objectives:
- Grant the Cloudfront Distribution access to the S3 bucket for ObjectFS
-
existing steps in document are for "Legacy access identies" Console text: "Use a CloudFront origin access identity (OAI) to access the S3 Bucket"
-
use "Origin access control settings (recommended)" Console text: "Bucket can restrict acess to only CloudFront." This configuration has been tested, and also works. This blog post outlines the advantages of the newer option: https://aws.amazon.com/blogs/networking-and-content-delivery/amazon-cloudfront-introduces-origin-access-control-oac/
-
Update S3 Bucket Policy (this step is required for either legacy OAI or Origin access control. "Policy must allow access to CloudFront IAM service principle role". (policy auto generated)
-
Restrict viewer access (CloudFront Distribution) to signed requests (Trusted Key Groups)
This is access control is independant of the access granted in step 1. The HTTP headers associated with this are not required, and should not be forwarded from Cloudfront to S3.
-
Setup CORS security (response header policy) for the Cloudfront distribution
- Login to AWS console https://aws.amazon.com/console/
- Navigate to Services -> S3.
- Click Create bucket.
- Fill out the bucket name and region
- Ensure Block all public access is ticked
- Enable Server-side encryption with Amazon S3 key (SSE-S3)
- Click Create bucket.
- Set the following as Cross-origin resource sharing (CORS):
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET",
"HEAD"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [],
"MaxAgeSeconds": 3000
}
]
9. Navigate to _My Security Credentials_.
10. In the _Access keys_ section click on the _Create New Access Key_ button.
- Run the following commands via CLI:
php admin/cli/cfg.php --component=tool_objectfs --name=enabletasks --set=1
php admin/cli/cfg.php --component=tool_objectfs --name=deletelocal --set=1
php admin/cli/cfg.php --component=tool_objectfs --name=consistencydelay --set=0
php admin/cli/cfg.php --component=tool_objectfs --name=sizethreshold --set=0
php admin/cli/cfg.php --component=tool_objectfs --name=minimumage --set=0
php admin/cli/cfg.php --component=tool_objectfs --name=filesystem --set='\tool_objectfs\s3_file_system'
php admin/cli/cfg.php --component=tool_objectfs --name=s3_key --set='your key'
php admin/cli/cfg.php --component=tool_objectfs --name=s3_secret --set='your secret'
php admin/cli/cfg.php --component=tool_objectfs --name=s3_bucket --set='your bucket'
php admin/cli/cfg.php --component=tool_objectfs --name=s3_region --set='your region'
- Put the following line into your config.php:
$CFG->alternative_file_system_class = '\tool_objectfs\s3_file_system';
- Access the /admin/settings.php?section=tool_objectfs_settings page.
- Confirm, that there is a green notification message Could establish connection to the external object storage. under the Amazon S3 Settings section.
- Run the following scheduled tasks:
php admin/cli/scheduled_task.php --execute='\tool_objectfs\task\check_objects_location'
php admin/cli/scheduled_task.php --execute='\tool_objectfs\task\push_objects_to_storage'
php admin/cli/scheduled_task.php --execute='\tool_objectfs\task\delete_local_objects'
php admin/cli/scheduled_task.php --execute='\tool_objectfs\task\generate_status_report'
- Access the /admin/tool/objectfs/object_status.php page.
- Confirm, that all files have been moved to the external storage: Marked as only in filedir and Duplicated in filedir and external storage should be 0.
ObjectFS can use a CloudFront key from either the local filesystem or an admin setting. If using an admin setting, the key may be generated outside of the Moodle environment.
- Make a directory $CFG->dataroot . '/objectfs/'.
- Make it readable and writable:
chmod 777 objectfs
- Generate an RSA key pair with a length of 2048 bits:
cd objectfs/
openssl genrsa -out cloudfront.pem 2048
chmod 777 cloudfront.pem
- Extract the public key:
openssl rsa -pubout -in cloudfront.pem -out public_key.pem
- Navigate to https://console.aws.amazon.com/cloudfront/v3/home#/publickey.
- Click Create public key.
- Enter key name.
- Enter key value. Use the following command to get the public key:
cat public_key.pem
- Click Create public key.
- Write down key ID from the https://console.aws.amazon.com/cloudfront/v3/home#/publickey page.
- Navigate to https://console.aws.amazon.com/cloudfront/v3/home#/keygrouplist
- Create a key group and select the public key created previously
- Store the public and private key files somewhere secure
- Navigate to https://console.aws.amazon.com/cloudfront/v3/home#/policies/responseHeaders
- Click on Create response headers policy
- Name: CORS-with-preflight-and-SecurityHeadersPolicy-ReadOnly
- Configure CORS: disabled
- Strict-Transport-Security: Enabled, origin override enabled
- X-Content-Type-Options: Enabled, origin override enabled
- X-Frame-Options: Disabled
- X-XSS-Protection: Enabled, block, origin override enabled
- Referrer-Policy: Enabled, strict-origin-when-cross-origin, origin override enabled
- Content-Security-Policy: disabled
- Navigate to https://console.aws.amazon.com/cloudfront/v3/home#/policies/origin
- Click on Create origin request policy
- Name: IncludeResponseContentDisposition
- Headers: Include the following headers
- Access-Control-Request-Method
- Access-Control-Request-Headers
- Query strings: Include Specified query strings
- response-content-disposition
- response-content-type
- Cookies: None
- Navigate to https://console.aws.amazon.com/cloudfront/.
- Click on Create a CloudFront distribution.
- Choose your Amazon S3 bucket from Origin domain dropdown menu.
- S3 bucket access: Choose Yes use OAI (bucket can restrict access to only CloudFront) and click Create new OAI. Alternative: choose Origin access control settings (recommended)
- S3 bucket access -> Bucket policy: Choose Yes, update the bucket policy. If Origin access control was selected in step 4, you may need to manually add the supplied policy to the S3 Bucket.
- Viewer protocol policy: Choose Redirect HTTP to HTTPS.
- Allowed HTTP methods: Choose GET, HEAD, OPTIONS and tick OPTIONS under Cache HTTP methods.
- Restrict viewer access: Choose Yes -> Trusted key groups (recommended).
- Add key group created earlier
- Cache key and origin requests: Choose Cache policy and origin request policy (recommended).
- Cache policy: Choose CachingOptimized
- Origin request policy: Choose IncludeResponseContentDisposition
- Response headers policy: Choose CORS-with-preflight-and-SecurityHeadersPolicy-ReadOnly
- Click Create distribution.
- Navigate to https://console.aws.amazon.com/cloudfront/v3/home#/distributions.
- Confirm, that Status is Enabled and Last modified is changed from Deploying to the date the distribution was created.
- Open your distribution.
- Write down Distribution domain name (with https://).
Note: If you have already setup Moodle behind a CloudFront distribution, it is also possible to use that same CloudFront distribution to serve files from objectfs. In this scenario, a specific prefix in the URL path directs traffic to the S3 Bucket (moodle.domain/objectfs/ for example). To achieve that, use the key_prefix option to add a prefix on your Bucket, and configure a second Origin on your existing CloudFront distribution that points to your Bucket. Setup a Behavior that uses that new Origin with the same prefix as the one you used as key_prefix in your Bucket. Follow all other instructions.
- Run the following commands from the CLI to configure Objectfs:
php admin/cli/cfg.php --component=tool_objectfs --name=enablepresignedurls --set=1
php admin/cli/cfg.php --component=tool_objectfs --name=expirationtime --set=172800
php admin/cli/cfg.php --component=tool_objectfs --name=presignedminfilesize --set=0
php admin/cli/cfg.php --component=tool_objectfs --name=signingwhitelist --set='*'
php admin/cli/cfg.php --component=tool_objectfs --name=signingmethod --set='cf'
php admin/cli/cfg.php --component=tool_objectfs --name=cloudfrontresourcedomain --set='your cloudfrom domain'
php admin/cli/cfg.php --component=tool_objectfs --name=cloudfrontkeypairid --set='your key pair id'
php admin/cli/cfg.php --component=tool_objectfs --name=cloudfrontprivatekey --set='cloudfront.pem'
- Please note that cloudfrontprivatekey setting can can be one of the following:
- a file name with the pem extension (described in this wiki), or
- a PEM formatted string, eg:
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAynfONnizsVKXwuoXXWZC948QFsZme3zXUJ7PDrd4fKBpDCPr
...
TPdsThtG51qIzZxYw4jlle2jCArTEta9meJRwpU9X32omvHLdENBnw==
-----END RSA PRIVATE KEY-----
- Open Dev Tool Network tab and navigate to the /admin/tool/objectfs/presignedurl_tests.php page.
- Confirm, that file requests like /pluginfile.php/1/tool_objectfs/settings/0/testvideo.mp4 get redirected to pre-signed CloudFront URL (HTTP status 303).
- Confirm, that requests to pre-signed CloudFront URL return requested data (HTTP status 200).
- Put the following lines into your config.php to make sure H5P activities are displayed correctly:
$CFG->h5pcrossorigin = 'anonymous';
$CFG->mod_hvp_crossorigin = 'anonymous';