Airlock - Suggested API (Design)
See original GitHub issueThe API suggested below corresponds to both the import and the export flows for the Airlock feature.
The suggested logical flow is:
- A user creates a blank draft import/export request -> a container is created either in the import or export storage account -> SAS token + URL is generated and returned to the user (with time expiration)
- User uploads files directly to the container (directly, not via any TRE API, e.g. using storage explorer)
- User submits the request -> SAS token is revoked (i.e. container is blocked for read/write)
- TRE admin ask to download the files and get SAS token + URL with READ permission
- TRE admin download the files within the TRE vnet (enforced by storage account network configuration)
- TRE admin submits a review
- (researcher is notified) Researcher ask for the request storage accounts and get SAS token + URL for the containers
technical notes - for the API feasibility only (not for the complete feature)
- multiple storage accounts per TRE: a) external b) internal c) rejected d) blocked
- the number of containers per request vary, as containers are created and deleted on the fly
- There is no (Azure) limit on the number of containers per storage account - allows us to support this flow
- SAS token + URL is in a container level - allows us to supply fine grained permissions and revoke
Researcher
Create a new draft request
Creates the storage container for the user to drop files. Creates a TRE request object
POST /api/workspaces/<workspace_id>/requests
{
"type": "import",
"business_justification": "will be provided to the request reviewer"
}
Response 201 Created
{
"request_Id": "abcd1234-5678-9101-1121-31415161718x",
"type": "import",
"files": [],
"business_justification": "will be provided to the request reviewer",
"user": "<user_id>,
"status": "draft",
"container": {
"id": <containerid>,
"type": "external",
"connectionstring":"https://externalstoragexyz.blob.core.windows.net/<ws_id>?sp=...XYZ"
}
}
Submit a request
Block access to the container, preventing changes to the files and starts the relevant airlock flow The status of the request will change, the files will be enumerated and added to the request object.
POST /api/workspaces/<workspace_id>/requests/<request_id>/submit
{
}
Response 200 OK
{
"requestId": "abcd1234-5678-9101-1121-31415161718x",
"type": "import",
"files": ["text1.txt", "text2.txt"],
"business_justification": "text",
"user": "<user_id>,
"status": "submitted"
}
Get workspace storage accounts
Returns the Airlock related storage containers for the given request. External == the container to start an import request or end an export reqeust. Internal == the container to start an export request or end an import request. Blocked == the container with files blocked for any reason. Rejected == the container to hold files which were not allowed to continue by the reviewer.
External containers are configured at the storage account level to allow public access. The other containers are configured at the storage account level to allow connectivity using private endpoints and block public access.
Since there are multiple storage accounts and not all of those are in use all the times, not all containers urls will be returned…
GET /api/workspaces/<workspace_id>/requests/<request_id>/storageContainers
Response 200 OK
{
[
{
"id": <containerid>,
"type": "internal",
"connectionstring":"https://internalstoragexyz.blob.core.windows.net/<ws_id>?sp=...XYZ"
},
{
"id": <containerid>,
"type": "external",
"connectionstring":"https://externalstoragexyz.blob.core.windows.net/<ws_id>?sp=...XYZ"
},
{
"id": <containerid>,
"type": "rejected",
"connectionstring":"https://rejectedstoragexyz.blob.core.windows.net/<ws_id>?sp=...XYZ"
},
{
"id": <containerid>,
"type": "blocked",
"connectionstring":"https://blockedstoragexyz.blob.core.windows.net/<ws_id>?sp=...XYZ"
}
]
}
Get an existing request
GET /api/workspaces/<workspace_id>/requests/<request_id>
Response 200 OK
{
"requestId": "abcd1234-5678-9101-1121-31415161718x",
"type": "import",
"files": ["file1.txt", "file2.txt"],
"business_justification": "Meaningful text...",
"user": "<user_id>,
"status": "submitted/in-review/approved/rejected/cancelled/blocked"
}
blocked == when the scanning process detected malicious content or any other scanner did not approve the content.
Cancel request
Cancelling a request, does not delete the request itself, it moves it to a ‘cancelled’ state and moves the data to rejected storage and a dedicated container
POST /api/workspaces/<workspace_id>/requests/<request_id>/cancel
{
"reason": "Some text"
}
Response 200 OK
Update request - not supported. one can close and create a new request
Get reviews related to the request
GET /api/workspaces/<workspace_id>/requests/<request_id>/reviews
Response 200 OK
{
"reviews": [
{
"review_decision": "approved/rejected",
"decision_explanation": "Describe why the request was approved/rejected",
"user": "<user_id>",
"override": false,
"override_justification": "explanation",
"allow_blocked_content": false,
"allow_blocked_justification": "explanation"
}
]
}
Get review
GET /api/workspaces/<workspace_id>/requests/<request_id>/reviews/<review_id>
Response 200 OK
{
"review_decision": "approved/rejected",
"decision_explanation": "Describe why the request was approved/rejected",
"user": "<user_id>",
"override": false,
"override_justification": "explanation",
"allow_blocked_content": false,
"allow_blocked_justification": "explanation"
}
TRE admin
Approve / Reject
POST /api/workspaces/<workspace_id>/requests/<request_id>/reviews
{
"review_decision": "approved/rejected",
"decision_explanation": "Describe why the request was approved/rejected",
"override": false,
"override_justification": "explanation",
"allow_blocked_content": false,
"allow_blocked_justification": "explanation"
}
(Optional) override - if provided, can override a previously rejection (Optional) allow_blocked_content - if provided, allows content which was blocked (found malicious (FP), encrypted, etc)
Response
{
"review_id": "xyzw1234-5678-9101-1121-31415161718x",
"review_decision": "approved/rejected",
"decision_explanation": "Describe why the request was approved/rejected",
"override": false,
"override_justification": "explanation",
"allow_blocked_content": false,
"allow_blocked_justification": "explanation",
"user": "<user_id>"
}
Allowed for the: data steward (TRE admin)
Get request’s download links
Get a list of files with their urls in the container. this is useful for UI clients which need a way to enumerate all files of the request
GET /api/workspaces/<workspace_id>/importrequests/<request_id>/download
Response 200 OK
{
"links": ["https://xyz.blob.core.windows.net/mycontainer?sp=abcdefg&sig=xyz...1Abc1", "https://xyz.blob.core.windows.net/mycontainer?sp=abcdefg&sig=xyz...1Abc2", "https://xyz.blob.core.windows.net/mycontainer?sp=abcdefg&sig=xyz...1Abc3", "https://xyz.blob.core.windows.net/mycontainer?sp=abcdefg&sig=xyz...1Abc4]
}
Issue Analytics
- State:
- Created a year ago
- Comments:18 (6 by maintainers)
Top GitHub Comments
I am not sure that we want to limit the reviews to just 1 per request. I agree we can merge the review into the request itself. but then it gets a bit complicated, e.g. what happens if the user try to create a new request and also adds a review property? (trying to pre-approve the request)
@marrobi I liked the idea. updated the design All, please re-review as I changed it quite a bit.