This repository has been archived by the owner on Apr 13, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 161
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement multi-tenancy and group export (#416)
* feat: add tenantId attribute to Cognito user pool (#348) * feat: remove unneeded scope checks in authorizer (#347) * feat: update lambda state machine to accommodate tenantId (#367) * feat: add "enableMultiTenancy" CFN parameter (#381) * test: add multi-tenancy integ tests (#387) * fix: remove _id, _tenantId from bulk export results (#384) * feat: Group export scripts (#389) * fix: add multi-tenant metadata route (#392) * fix: allow more concurrent export jobs for multi-tenant deployments (#397) * test: integ tests for Group export (#393) * feat: add ES hard delete config value (#398) * docs: update postman collection and docs to use Id token (#399) * docs: add multi-tenancy docs (#400) Co-authored-by: Yanyu Zheng <[email protected]> BREAKING CHANGE: The Cognito IdToken is now used instead of the accessToken to authorize requests.
- Loading branch information
Showing
31 changed files
with
55,200 additions
and
91,457 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# Multi-Tenancy | ||
|
||
Multi-tenancy allows a single `fhir-works-on-aws` stack to serve as multiple FHIR servers for different tenants. | ||
|
||
`fhir-works-on-aws` uses a pooled infrastructure model for multi-tenancy. This means that all tenants share the | ||
same infrastructure (DynamoDB tables, S3 Buckets, Elasticsearch cluster, etc.), but the data | ||
is logically partitioned to ensure that tenants are prevented from accessing another tenant’s resources. | ||
|
||
## Enabling multi-tenancy | ||
|
||
Use the `enableMultiTenancy` option when deploying the stack: | ||
|
||
```bash | ||
serverless deploy --enableMultiTenancy true | ||
``` | ||
|
||
**Note:** Updating an existing (single-tenant) stack to enable multi-tenancy is a breaking change. Multi-tenant | ||
deployments use a different data partitioning strategy that renders the old, single-tenant, data inaccessible. | ||
If you wish to switch from single-tenant to a multi-tenant model, it is recommended to create a new multi-tenant stack | ||
and then migrate the data from the old stack. Switching from multi-tenant to a single-tenant model is also a breaking change. | ||
|
||
## Tenant identifiers | ||
|
||
Tenants are identified by a tenant Id in the auth token. A tenant Id is a string that can contain alphanumeric characters, | ||
dashes, and underscores and have a maximum length of 64 characters. | ||
|
||
There are 2 ways to include a tenant Id in the auth token: | ||
|
||
1. Add the tenant Id in a custom claim. This is the recommended approach. | ||
The default configuration adds the tenant Id on the `custom:tenantId` claim | ||
|
||
1. Encode the tenant Id in the `aud` claim by providing an URL that matches `<baseUrl>/tenant/<tenantId>`. | ||
This can be useful when using an IDP that does not support custom claims. | ||
|
||
If a token has a tenant Id in a custom claim and in the aud claim, then both claims must have the same tenant Id value, | ||
otherwise an Unauthorized error is thrown. | ||
|
||
The default deployment adds a custom claim `custom:tenantId` to the Cognito User Pool. You can manage the tenant Id value | ||
for the different users on the AWS Cognito Console. The [provision-user.py](https://github.com/awslabs/fhir-works-on-aws-deployment/blob/mainline/scripts/provision-user.py) | ||
script will also create users with a set tenant Id. | ||
|
||
## Additional Configuration | ||
|
||
Additional configuration values can be set on [config.ts](https://github.com/awslabs/fhir-works-on-aws-deployment/blob/mainline/src/config.ts) | ||
|
||
- `enableMultiTenancy`: Whether or not to enable multi-tenancy. | ||
- `useTenantSpecificUrl`: When enabled, `/tenant/<tenantId>/` is appended to the FHIR server url. | ||
|
||
e.g. A client with `tennatId=tenantA` would use the following url to search for Patients: | ||
``` | ||
GET <serverUrl>/tenant/<tenantId>/Patient | ||
GET https://1234567890.execute-api.us-west-2.amazonaws.com/dev/tenant/tenantA/Patient | ||
``` | ||
Enabling this setting is useful to give each tenant a unique FHIR server base URL. | ||
|
||
- `tenantIdClaimPath`: Path to the tenant Id claim in the auth token JSON. Defaults to `custom:tenantId` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
This scripts generates the two patientCompartmentSearchParams JSON files from compartment definition files and save them at bulkExport/schema. | ||
Run the script: | ||
> node extractPatientCompartmentSearchParams.js | ||
The compartment definition files are downloaded from the following URL and saved in folder bulkExport/schema: | ||
compartmentdefinition-patient.4.0.1.json: https://www.hl7.org/fhir/compartmentdefinition-patient.json.html | ||
compartmentdefinition-patient.3.0.2.json: http://hl7.org/fhir/stu3/compartmentdefinition-patient.json.html (Note the AuditEvent and Provenance fields in this file are updated to remove dotted path) | ||
*/ | ||
|
||
const fs = require('fs'); | ||
const compartmentPatientV3 = require('./schema/compartmentdefinition-patient.3.0.2.json'); | ||
const compartmentPatientV4 = require('./schema/compartmentdefinition-patient.4.0.1.json'); | ||
const baseSearchParamsV3 = require('../../fhir-works-on-aws-search-es/src/schema/compiledSearchParameters.3.0.1.json'); | ||
const baseSearchParamsV4 = require('../../fhir-works-on-aws-search-es/src/schema/compiledSearchParameters.4.0.1.json'); | ||
|
||
// Create a dictionary of search params | ||
function extractPatientCompartmentSearchParams(baseSearchParams, compartmentPatient) { | ||
const baseSearchParamsDict = {}; | ||
// example of an item in baseSearchParamsDict: Account-identifier: {resourceType: "Account", path: "identifier"} | ||
baseSearchParams.forEach(param => { | ||
baseSearchParamsDict[`${param.base}-${param.name}`] = param.compiled; | ||
}); | ||
|
||
// Find the search params needed for patient compartment | ||
const patientCompartmentSearchParams = {}; | ||
compartmentPatient.resource.forEach(resource => { | ||
if (resource.param) { | ||
let compiledPaths = []; | ||
resource.param.forEach(param => { | ||
const pathsForThisParam = baseSearchParamsDict[`${resource.code}-${param}`].map(item => item.path); | ||
compiledPaths = compiledPaths.concat(pathsForThisParam); | ||
}); | ||
patientCompartmentSearchParams[resource.code] = compiledPaths; | ||
} | ||
}); | ||
return patientCompartmentSearchParams; | ||
} | ||
|
||
const patientCompartmentSearchParamsV4 = extractPatientCompartmentSearchParams( | ||
baseSearchParamsV4, | ||
compartmentPatientV4, | ||
); | ||
const patientCompartmentSearchParamsV3 = extractPatientCompartmentSearchParams( | ||
baseSearchParamsV3, | ||
compartmentPatientV3, | ||
); | ||
|
||
fs.writeFileSync( | ||
'./schema/patientCompartmentSearchParams.3.0.2.json', | ||
JSON.stringify(patientCompartmentSearchParamsV3), | ||
); | ||
fs.writeFileSync( | ||
'./schema/patientCompartmentSearchParams.4.0.1.json', | ||
JSON.stringify(patientCompartmentSearchParamsV4), | ||
); | ||
|
||
console.log(patientCompartmentSearchParamsV4); | ||
console.log(patientCompartmentSearchParamsV3); |
Oops, something went wrong.