title | layout |
---|---|
Tutorial |
page |
In this tutorial, you will:
- get to know how Faasten manages security privileges,
- get to know Faasten's system-enforced data security,
- get to know how one can easily add a functionality without breaking the security.
Download the tutorial code.
git clone [email protected]:faasten/example-apps
cd example-apps/tutorial
Install Faasten's command line client fstn
on your local machine
cargo install --git https://github.com/faasten/fstn.git --branch tutorial fstn
Faasten log-in
# faasten server address
export FSTN_SERVER=https://sns60.cs.princeton.edu
# follow instructions, only Princeton CAS is supported as of now
fstn login
The tutorial code include a function image thumbnail.img
.
Now, install the image to your home directory on Faasten.
export FSTN_SERVER=https://sns60.cs.princeton.edu
export NETID=yuetan # replace with your NETID
# in example-apps/tutorial
fstn register ./thumbnail.img $NETID/tutorial/thumb,$NETID/tutorial/thumb '~:thumbnail' 128 python
Check your home directory. The installment should create the entry thumbnail
.
fstn list-dir '~'
Test out the installment.
# set up the photo blob
fstn put-blob ./people12.jpg '~:people12.jpg' $NETID,$NETID
# invoke
echo '{"download_key":":home:<'$NETID,$NETID'>:people12.jpg", "output_dir":":home", "sizes":[[75,75],[100,100]]}' | fstn invoke '~:thumbnail'
# check the outputs, they should be in :home:<$NETID,$NETID/tutorial/thumb>
fstn list-dir ':home:<'$NETID,$NETID'/tutorial/thumb>'
# your home directory is untouched
fstn list-dir '~'
Discussion
(Faasten tightly couples a file-system with the computation substrate. As a result, data are named by colon-separated
paths. In the example above, :
names the root directory. home
names a faceted directory in the root directory,
<yuetan,yuetan>
names a facet of home
.
A facet is a directory named by its security policy. In this case, the facet can be read by anyone but can only
be written by yuetan
.
Notably, ~
is the shorthand of one's home directory :home:<USER,USER>
, readable and writable
only by USER.
Gates are our mechanism to transfer a privilege in a protected way.
Functions are linked into the file-system as gates as invoking a function indirectly grants the invoker
some privilege.
Above, when we register thumbnail
, the second positional argument is the policy specifying what privilege
we are granting---yuetan/tutorial/thumb (before the comma)---and the integrity that an invoker's integrity
must be as strong as---yuetan/tutorial/thumb (after the comma).
This policy would allow one thumbnail instance invokes another.)
Now let's try different output_dir values.
First, we can supply a value that leaks the presence of the thumbnails (metadata).
echo '{"download_key":":home:<'$NETID,$NETID'>:people12.jpg", "output_dir":":home:<T,'$NETID'/tutorial/thumb>", "sizes":[[75,75],[100,100]]}' | fstn invoke '~:thumbnail'
# check the leaky output dir, we will see that the invocation silently fails
fstn list-dir ':home:<T,'$NETID'/tutorial/thumb>'
Next, we can supply a value that the instance cannot write.
echo '{"download_key":":home:<'$NETID,$NETID'>:people12.jpg", "output_dir":":home:<'$NETID,$NETID'>", "sizes":[[75,75],[100,100]]}' | fstn invoke '~:thumbnail'
# check the non-writable output dir, we will see that the invocation silently fails
fstn list-dir ':home:<'$NETID,$NETID'>'
Discussion
(In Faasten, data security is enforced by the system end-to-end. Here, the photo blob itself and its presence are both private to the end user (i.e. the owner). The system enforce that any function that reads the photo blob cannot output to a less secret location unless the function acts on behalf of the end user (i.e. runs with the privilege $NETID) and can, therefore, declassify its computation.
The photo blob and its presence are also only writable by the end user (or the owner). This makes sure that no function can delete the photo or point the name to something else unless it acts on behalf of the end user.)
By design, in Faasten, one can easily extend an application without breaking the security.
As a prompt, the tutorial code includes detect-face/workload.py
an incomplete source of the function
that add the face detection functionality.
First, let's dive into the source of thumbnail
to see how a faasten looks like.
Faasten loads a function as a module through explicitly loading workload.py
. That is, a function's
source should always include the workload.py
file.
Additionally, each function must define the entry-point function handle
inside workload.py
.
The function takes two positional arguments. The first is a Python object that contains all inputs.
The second is the CloudCall object whose methods are CloudCall wrappers. The function must return a JSON-serializable
object.
# import dependencies
from PIL import Image
def handle(event, cloudcall):
return {}
Download the input photo blob from the persistent storage.
download_path = event['input']['download_key']
with cloudcall.fs_openblob(download_path) as blob:
# compute over the blob and output to local storage ...
Upload the thumbnail to the persistent storage.
upload_path = ... # construct the upload path
with cloudcall.create_blob() as newblob:
bn = img.save(newblob, format='JPEG')
newblob.finalize(b'')
cloudcall.fs_linkblob(upload_path, bn)
Detailed CloudCall documentations are here (wip).
from PIL import Image
def handle(event, cloudcall):
download_path = event['input']['download_key']
output_dir = event['input']['output_dir']
sizes = event['input']['sizes']
blobs = {}
with cloudcall.fs_openblob(download_path) as blob:
img = Image.open(blob)
for size in sizes:
img.thumbnail(tuple(size))
thumbnail_name = '-'.join(map(str, size)) + '.jpeg'
upload_path = ':'.join([output_dir, thumbnail_name])
with cloudcall.create_blob() as newblob:
img.save(newblob, format='JPEG')
bn = newblob.finalize(b'')
blobs[thumbnail_name] = bn
cloudcall.fs_linkblob(upload_path, bn)
return {'thumb-blobs': blobs}
detect-face
would have the same structure asthumbnail
---download the input, compute, and upload the result. Just likethumbnail
, the system will automatically confines andetect-face
instance.- Packaging
detect-face
requires make, Docker and squashfs-tools.
# in example-apps/tutorial
make -C detect-face
gensquashfs --pack-dir detect-face/out detect-face.img
Alternatively, we include a compressed detec-face.base.img.tgz of format ext2 on Git LFS. One can download, uncompress, and mount it and then overwrite workload.py with the finished workload.py.