Skip to content

Commit

Permalink
many changes to concepts and getting_started plus other minor fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
bashir2 committed Nov 29, 2024
1 parent cbd6cd3 commit 16322df
Show file tree
Hide file tree
Showing 11 changed files with 232 additions and 133 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ The requests to the access proxy should have the access token as a Bearer
Authorization header. Based on that, the proxy decides whether to grant access
for a FHIR query.

<img src="doc/summary.png" width=50% alt="Modules involved in FHIR authorization/access-control">
<img src="doc/docs/summary.png" width=50% alt="Modules involved in FHIR authorization/access-control">

For more information on the technical design,
[see the design doc](doc/docs/design.md).
Expand Down Expand Up @@ -177,7 +177,7 @@ accessing the proxy from an Android emulator, which runs on a separate network.
GCP note: if this is not on a VM with proper service account (e.g., on a local
host), you need to pass GCP credentials to it, for example by mapping the
`.config/gcloud` volume (i.e., add `-v ~/.config/gcloud:/root/.config/gcloud` to
the above command).
the docker command).

# How to use this proxy

Expand Down
196 changes: 127 additions & 69 deletions doc/docs/concepts.md

Large diffs are not rendered by default.

10 changes: 4 additions & 6 deletions doc/docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ For more context, please see the [Introduction](#introduction) section.
Here is a summary of proposals and decisions in this design document, for the
first version (V1) of the FHIR gateway:

<img src="summary.png" width=50% height=50%>
![High-level Architecture](images/summary.png)

- There are three main components responsible for access decisions: an Identity
Provider (IDP) which authenticates the user, an Authorization server (AuthZ)
Expand Down Expand Up @@ -198,8 +198,6 @@ sometimes referred to as the Identity and Access Management (IAM) or simply
We also have an "access gateway" which is responsible for processing any access
request for the FHIR server and is the main focus of this design doc.

<img src="summary.png" width=50% height=50%>

### Authentication and authorization flow

Before the user can access data, their identity should be established and based
Expand All @@ -226,7 +224,7 @@ to use
[PKCE](https://auth0.com/docs/authorization/flows/authorization-code-flow-with-proof-key-for-code-exchange-pkce)
which is not shown in this diagram)[^1]:

<img src="flow.png">
![flow](images/flow.png)

Here is a brief description of each step:

Expand Down Expand Up @@ -265,7 +263,7 @@ to AuthZ which in turn maps the user identity to some access rules to FHIR
resources. Popular IAM servers like [Keycloak](https://www.keycloak.org/),
support separate/3rd party IDPs.

<img src="separate.png" width=50% height=50%>
![separate](images/separate.png)

**Integrated AuthZ+Gateway**

Expand All @@ -277,7 +275,7 @@ simplifies the deployment architecture significantly, however we note that the
elimination of the access token might be incompatible with some use-cases like
SoF apps.

<img src="integrated.png" width=50% height=50%>
![integrated](images/integrated.png)

## Access gateway

Expand Down
95 changes: 55 additions & 40 deletions doc/docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,91 +2,103 @@

!!! tip "Quick Start Guide"

The easiest way to get started is to follow the ["Run the Info Gateway in Docker" guide](getting_started_docker.md).
The easiest way to get started is to follow the ["Run the Info Gateway in Docker" guide](tutorial_docker.md).

## Building from source
The proxy consists of a core, which is in the [server](https://github.com/google/fhir-gateway/tree/main/server) module, and a set of _access-checker_ plugins, which can be implemented by third parties and added to the proxy server. Two sample plugins are implemented in the [plugins](https://github.com/google/fhir-gateway/tree/main/plugins) module.

There is also a sample `exec` module which shows how all pieces can be woven together into a single Spring Boot app.

To build all modules, from the root run:
To build all modules, from the root run (if you are a developer, do _not_ use
`spotless.apply.skip=true`):

```shell
mvn package -Dspotless.apply.skip=true
```

The server and the plugins can be run together through this executable jar (
`--server.port` is just one of the many default Spring Boot flags):
The `server` and `plugins` modules can be run together through this executable
jar (`--server.port` is just one of the many default Spring Boot flags):

```shell
java -jar exec/target/exec-0.1.0.jar --server.port=8081
```

Note that extra access-checker plugins can be added through the `loader.path` property (although it is probably easier to build them into your server):
Note that extra access-checker plugins can be added through the `loader.path`
property (although it is probably easier to build them into your server):

```shell
java -Dloader.path="PATH-TO-ADDITIONAL-PLUGINGS/custom-plugins.jar" \
-jar exec/target/exec-0.1.0.jar --server.port=8081
```

The plugin library can be swapped with any third party access-checker as described in the [plugins](https://github.com/google/fhir-gateway/tree/main/plugins) directory. Learn more about [AccessCheckers](concepts.md#access-checkers)

The plugin library can be swapped with any third party access-checker as
described in
the [plugins](https://github.com/google/fhir-gateway/tree/main/plugins)
directory. Learn more about [AccessCheckers](concepts.md#access-checkers).

## Gateway to server access
The proxy must be able to send FHIR queries to the FHIR server. The FHIR server must be configured to accept connections from the proxy while rejecting most other requests.

If you use a [GCP FHIR store](https://cloud.google.com/healthcare-api/docs/concepts/fhir) you have the following options:
The proxy must be able to send FHIR queries to the FHIR server. The FHIR server
must be configured to accept connections from the proxy while rejecting most
other requests.

- If you have access to the FHIR store, you can use your own credentials by
doing [application-default login](https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login). This is useful when testing the proxy on your local machine, and you have access to the FHIR server through your credentials.
If you use
a [GCP FHIR store](https://cloud.google.com/healthcare-api/docs/concepts/fhir)
you have the following options:

- Use a service account with required access (e.g., "Healthcare FHIR Resource Reader", "Healthcare Dataset Viewer", "Healthcare FHIR Store Viewer"). You can then run the proxy in the same GCP project on a VM with this service account.
- If you have access to the FHIR store, you can use your own credentials by
doing [application-default login](https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login).
This is useful when testing the proxy on your local machine, and you have
access to the FHIR server through your credentials.

- [not-recommended] You can create and download a key file for the above service account, then use it with:
- Use a service account with required access (e.g., "Healthcare FHIR Resource
Reader", "Healthcare Dataset Viewer", "Healthcare FHIR Store Viewer"). You can
then run the proxy in the same GCP project on a VM with this service account.

- [not-recommended] You can create and download a key file for the above service
account, then use it with:
```shell
export GOOGLE_APPLICATION_CREDENTIALS="PATH_TO_THE_JSON_KEY_FILE"
```

## Running the proxy server
Once you have set all the above, you can run the proxy server. The sample `exec` module uses [Apache Tomcat](https://tomcat.apache.org/) through [Spring Boot](https://spring.io/projects/spring-boot) and the usual configuration parameters apply, e.g., to run on port 8081:
## Running the gateway

```shell
java -jar exec/target/exec-0.1.0.jar --server.port=8081
```
!!! tip "Configuration Parameters"

Note if the `TOKEN_ISSUER` is on the `localhost` you may need to bypass proxy's token issuer check by setting `RUN_MODE=DEV` environment variable if you are accessing the proxy from an Android emulator, which runs on a separate network.
Take a moment to review the [configuration parameters](concepts.md#configuration-parameters).

[Try the proxy with test servers in Docker](https://github.com/google/fhir-gateway/wiki/Try-out-FHIR-Information-Gateway).

GCP note: if this is not on a VM with proper service account (e.g., on a localhost), you need to pass GCP credentials to it, for example by mapping the `.config/gcloud` volume (i.e., add `-v ~/.config/gcloud:/root/.config/gcloud` to the above command).

## As a docker image
The proxy is also available as a docker image:
Once you have set all the above, you can run the proxy server. The sample `exec`
module uses [Apache Tomcat](https://tomcat.apache.org/)
through [Spring Boot](https://spring.io/projects/spring-boot) and the usual
configuration parameters apply, e.g., to run on port 8081:

```shell
$ docker run -p 8081:8080 -e TOKEN_ISSUER=[token_issuer_url] \
-e PROXY_TO=[fhir_server_url] -e ACCESS_CHECKER=list \
us-docker.pkg.dev/fhir-proxy-build/stable/fhir-gateway:latest
java -jar exec/target/exec-0.1.0.jar --server.port=8081
```

Note if the TOKEN_ISSUER is on the localhost you may need to bypass proxy's token issuer check by setting RUN_MODE=DEV environment variable if you are accessing the proxy from an Android emulator, which runs on a separate network.
!!! tip "Android Emulator"

Try the proxy with test servers in Docker, see the [Getting Started with Docker tutorial](getting_started_docker.md)

GCP note: if this is not on a VM with proper service account (e.g., on a local host), you need to pass GCP credentials to it, for example by mapping the .config/gcloud volume (i.e., add -v ~/.config/gcloud:/root/.config/gcloud to the above command).
If the `TOKEN_ISSUER` is on the `localhost` and you are accessing the gateway from an Android emulator (which runs on a separate network), you may need to bypass proxy's token issuer check by setting `RUN_MODE=DEV` environment variable.

## Using the Info Gateway
Once the proxy is running, we first need to fetch an access token from the `TOKEN_ISSUER`; you need the test `username` and `password` plus the
`client_id`:

In this section we assume that a Keycloak instance is set up using the sample
docker setup provided
[here](https://github.com/google/fhir-gateway/blob/main/docker/keycloak/config-compose.yaml).
If you have a different IDP+AuthZ setup, you need to adjust the parameters
below accordingly.

Once the gateway is running, we first need to fetch an access token from
the `TOKEN_ISSUER`; you need the test server's `username` and `password` plus
the `client_id`:

```shell
$ curl -X POST -d 'client_id=CLIENT_ID' -d 'username=testuser' \
-d 'password=testpass' -d 'grant_type=password' \
"http://localhost:9080/auth/realms/test/protocol/openid-connect/token"
```

We need the `access_token` of the returned JSON to be able to convince the proxy to authorize our FHIR requests (there is also a `refresh_token` in the above response). Assuming this is stored in the `ACCESS_TOKEN` environment variable, we can access the FHIR store:
We need the `access_token` of the returned JSON to be able to convince the
gateway to authorize our FHIR requests (there is also a `refresh_token` in the
above response). Assuming this is stored in the `ACCESS_TOKEN` environment
variable, we can access the FHIR store:

```shell
$ curl -X GET -H "Authorization: Bearer ${ACCESS_TOKEN}" \
Expand All @@ -101,9 +113,12 @@ $ curl -X PUT -H "Authorization: Bearer ${ACCESS_TOKEN}" \
-d @Patient_f16b5191-af47-4c5a-b9ca-71e0a4365824_modified.json
```

Of course, whether a query is accepted or denied, depends on the access-checker used and the `ACCESS_TOKEN` claims.
Of course, whether a query is accepted or denied, depends on the access-checker
used and the `ACCESS_TOKEN` claims.

For example:

* For `ACCESS_CHECKER=list` there should be a `patient_list` claim which is the ID of a `List` FHIR resource with all the patients that this user has access to.
* For `ACCESS_CHECKER=list` there should be a `patient_list` claim which is the
ID of a `List` FHIR resource with all the patients that this user has access
to.
* For `ACCESS_CHECKER=patient`, there should be a `patient_id` claim with a valid Patient resource ID.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
55 changes: 39 additions & 16 deletions doc/docs/index.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,55 @@
# FHIR Info Gateway
The Info Gateway is a reverse proxy which controls client access to FHIR resources on a server by checking requests for authorization to a FHIR URL or search query.

It makes it easier for developers to enforce organizational role based access control (RBAC) policies when working with FHIR data.

* The Info Gateway enables authorization (AT) and access-control (ACL) between a client application and a FHIR server when used along with any OpenID Connect compliant Identity Provider (IdP) and Authorization server (AuthZ).
* It currently supports Keycloak as the IDP+AuthZ provider and has been tested with HAPI FHIR and Google Cloud Healthcare API FHIR store as the FHIR server.
The Info Gateway is a reverse proxy which controls client access to FHIR
resources on a server. It works by inspecting FHIR requests and verifying that
the client is authorized to access the requested resources.

It makes it easier for developers to enforce various forms of authorization
policies including organizational role based access control (RBAC) policies
when working with FHIR data.

* To enable authorization and access-control (ACL) policy enforcement between a
client application and a FHIR server, the Info Gateway is used along with an
Identity Provider (IDP) and Authorization server (AuthZ).
* The IDP can be a generic OpenID Connect (OIDC) compliant service or a special
purpose one.
* The IDP+AuthZ should provide a JSON Web Token (JWT) to the client. The client
uses this as a Bearer access-token (AT) when sending FHIR requests.
* A sample end-to-end implementation with Keycloak as the IDP+AuthZ service is
provided and has been tested with HAPI FHIR and Google Cloud Healthcare
FHIR-store as the FHIR server.

![FHIR Info Gateway](images/Info_Gateway_Overview.png)

## Key Features
Key features of the Info Gateway features include:
Key features of the Info Gateway include:

* A stand-alone service that can work with any FHIR compliant servers (e.g., a HAPI FHIR server, GCP FHIR store, etc.)
* A pluggable architecture for defining an access-checkers to allow for implementation configurability
* Query filtering to block/allow specific queries such as for disabling joins
* A stand-alone service that can work with any FHIR compliant servers.
* A pluggable architecture for defining an access-checker to allow for
implementation configurability.
* Query filtering to block/allow specific queries.
* Post-processing of the results returned by the FHIR-server, for example to
remove sensitive information.
* A generic interface for implementing custom endpoints, e.g., a sync endpoint
to return updates for all patients assigned to a health-worker.

## Common use cases
The Info Gateway is designed to solve for a generic problem, that is, access control for **any client**.

Common use cases include:

1. Web based dashboard used by program admins
The Info Gateway is designed to solve for a generic problem, that is, access
control for **any client** and **any FHIR server**.

2. For a mobile app used by commnunity based frontline health workers possibly with offline support
Common access-check use-cases include:

3. For a personal health record app used by patients or care-givers
1. For a mobile app used by community based front-line health workers possibly
with offline support
2. Web based dashboard used by program admins
3. For a personal health record app used by patients or caregivers
4. To enable SMART-on-FHIR apps for patient or system level scopes

4. To enable SMART-on-FHIR for patient or system level scopes
FHIR Info Gateway is implemented as a "FHIR facade", i.e., it is a FHIR server
itself which is implemented using the
[HAPI FHIR Plain Server](https://hapifhir.io/hapi-fhir/docs/server_plain/introduction.html)
library:

![FHIR Info Gateway](images/Info_Gateway_Use_Cases.png)

4 changes: 4 additions & 0 deletions doc/docs/tutorial_docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ running on your local machine.
and [`patient`](https://github.com/google/fhir-gateway/blob/main/plugins/src/main/java/com/google/fhir/gateway/plugin/PatientAccessChecker.java)
example access-checkers.

!!! tip "GCP Note"

If the FHIR server is GCP FHIR-store and the gateway is not run on a VM with proper service account (e.g., running on a localhost), you need to pass GCP credentials to it, for example by mapping the `.config/gcloud` volume (i.e., add `-v ~/.config/gcloud:/root/.config/gcloud` to the above command).

## Examine the sample Keycloak configuration

In this section you will review the Keycloak settings relevant to use FHIR
Expand Down
1 change: 1 addition & 0 deletions doc/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ nav:
- Tutorials:
- 'Run the Info Gateway in Docker' : 'tutorial_docker.md'
- 'Create an access checker' : 'tutorial_first_access_checker.md'
- Design: 'design.md'
- Community:
- 'Support' : 'support.md'
- 'Contributing': 'contribute.md'
Expand Down

0 comments on commit 16322df

Please sign in to comment.