diff --git a/README.md b/README.md index 1ab8f270..d5cc92bc 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ networks: - load `docker-compose/lb/tls/ca.pem` into keychain/local certs - add `left.local`, `node.left.local`, `admin.left.local`, `right.local`, `admin.right.local` and `node.right.local` to `/etc/hosts` (127.0.0.1) - execute `make docker` -- execute `./setup.sh` (this will also start all containers in the docker-compose setup) +- execute `./setup.sh ` (setup is independent of PEP, so usually fine to run without argument (defaults to nginx)) ### setup.sh the setup script executes the following steps: @@ -135,5 +135,10 @@ docker exec nuts-demo-ehr-node-right-1 curl -X POST "http://localhost:8081/inter ``` ### Run -- docker compose up +The repo contains different docker compose setups that each have a different PEP configured +- NGINX `docker-compose-nginx.yml` +- APISIX `docker-compose-apisix.yml` + +Select the PEP you want (use NGINX if unsure) and run +- `docker compose -f docker-compose-.yml up` - goto: https://left.local and https://right.local \ No newline at end of file diff --git a/docker-compose-apisix.yml b/docker-compose-apisix.yml new file mode 100644 index 00000000..16cb6be1 --- /dev/null +++ b/docker-compose-apisix.yml @@ -0,0 +1,166 @@ +services: + lb: + image: nginx:1.25.1 + depends_on: + - pep-left + - pep-right + - admin-left + - admin-right + networks: + demo: + ipv4_address: 172.90.10.2 + ports: + - 80:80 + - 443:443 + volumes: + - "./docker-compose/lb/config/nginx-apisix.conf:/etc/nginx/nginx.conf" + - "./docker-compose/lb/tls:/etc/nginx/ssl:ro" + pep-left: + image: &apisix-img apache/apisix:3.9.1-debian + environment: + APISIX_STAND_ALONE: true + depends_on: + - demo-left + - node-left + - pip-left + networks: + demo: + ipv4_address: 172.90.10.11 + volumes: + - './docker-compose/left/config/pep/apisix.yaml:/usr/local/apisix/conf/apisix.yaml:ro' + pep-right: + image: *apisix-img + environment: + APISIX_STAND_ALONE: true + depends_on: + - demo-right + - node-right + - pip-right + networks: + demo: + ipv4_address: 172.90.10.12 + volumes: + - './docker-compose/right/config/pep/apisix.yaml:/usr/local/apisix/conf/apisix.yaml:ro' + pip-left: &pip + image: nutsfoundation/nuts-pxp:main + environment: + NUTS_CONFIGFILE: /nuts/config.yaml + ports: + - 8080:8080 + networks: + demo: + ipv4_address: 172.90.10.13 + volumes: + - "./docker-compose/left/data/nutspxp:/nuts/data" + - "./docker-compose/left/config/nutspxp/policies:/nuts/policies" + - "./docker-compose/left/config/nutspxp/config.yaml:/nuts/config.yaml" + pip-right: + <<: *pip + ports: + - 8081:8080 + networks: + demo: + ipv4_address: 172.90.10.14 + volumes: + - "./docker-compose/right/data/nutspxp:/nuts/data" + - "./docker-compose/right/config/nutspxp/policies:/nuts/policies" + - "./docker-compose/left/config/nutspxp/config.yaml:/nuts/config.yaml" + node-left: &node + image: nutsfoundation/nuts-node:master + environment: + NUTS_CONFIGFILE: /nuts/nuts.yaml + extra_hosts: + - "left.local:172.90.10.2" + - "node.left.local:172.90.10.2" + - "right.local:172.90.10.2" + - "node.right.local:172.90.10.2" + networks: + demo: + ipv4_address: 172.90.10.3 + volumes: + - "./docker-compose/left/config/node/nuts.yaml:/nuts/nuts.yaml" + - "./docker-compose/left/data/node:/nuts/data" + - "./docker-compose/left/config/node/policies:/nuts/policies" + - "./docker-compose/left/config/node/discovery:/nuts/discovery" + - "./docker-compose/lb/tls/ca.pem:/etc/ssl/certs/demo_ca.pem" + node-right: + <<: *node + networks: + demo: + ipv4_address: 172.90.10.4 + volumes: + - "./docker-compose/right/config/node/nuts.yaml:/nuts/nuts.yaml" + - "./docker-compose/right/data/node:/nuts/data" + - "./docker-compose/right/config/node/policies:/nuts/policies" + - "./docker-compose/right/config/node/discovery:/nuts/discovery" + - "./docker-compose/lb/tls/ca.pem:/etc/ssl/certs/demo_ca.pem" + admin-left: &admin + image: nutsfoundation/nuts-admin:main + environment: + NUTS_NODE_ADDRESS: http://node-left:8081 + networks: + demo: + ipv4_address: 172.90.10.5 + admin-right: + <<: *admin + environment: + NUTS_NODE_ADDRESS: http://node-right:8081 + networks: + demo: + ipv4_address: 172.90.10.6 + demo-left: &demo + image: nutsfoundation/nuts-demo-ehr:main + volumes: + - "./docker-compose/left/config/demo/server.config.yaml:/app/server.config.yaml" + - "./docker-compose/left/config/demo/customers.json:/app/customers.json" + - "./docker-compose/left/data/demo:/app/data" + - "./docker-compose/lb/tls/ca.pem:/etc/ssl/certs/demo_ca.pem" + depends_on: + - hapi-left + - node-left + extra_hosts: + - "left.local:172.90.10.2" + - "node.left.local:172.90.10.2" + - "right.local:172.90.10.2" + - "node.right.local:172.90.10.2" + networks: + demo: + ipv4_address: 172.90.10.7 + demo-right: + <<: *demo + volumes: + - "./docker-compose/right/config/demo/server.config.yaml:/app/server.config.yaml" + - "./docker-compose/right/config/demo/customers.json:/app/customers.json" + - "./docker-compose/right/data/demo:/app/data" + - "./docker-compose/lb/tls/ca.pem:/etc/ssl/certs/demo_ca.pem" + depends_on: + - hapi-right + - node-right + networks: + demo: + ipv4_address: 172.90.10.8 + hapi-left: &hapi + image: hapiproject/hapi:v5.5.2 + environment: + hapi.fhir.fhir_version: DSTU3 + hapi.fhir.partitioning.allow_references_across_partitions: "false" + expose: + - 8080 + networks: + demo: + ipv4_address: 172.90.10.9 + volumes: + - "./docker-compose/left/data/hapi:/usr/local/tomcat/target" + hapi-right: + <<: *hapi + networks: + demo: + ipv4_address: 172.90.10.10 + volumes: + - "./docker-compose/right/data/hapi:/usr/local/tomcat/target" +networks: + demo: + ipam: + config: + - subnet: 172.90.0.0/16 + ip_range: 172.90.10.0/24 diff --git a/docker-compose.yml b/docker-compose-nginx.yml similarity index 100% rename from docker-compose.yml rename to docker-compose-nginx.yml diff --git a/docker-compose/lb/config/nginx-apisix.conf b/docker-compose/lb/config/nginx-apisix.conf new file mode 100644 index 00000000..3bcbb78f --- /dev/null +++ b/docker-compose/lb/config/nginx-apisix.conf @@ -0,0 +1,97 @@ +user nginx; +worker_processes 1; + +error_log /var/log/nginx/error.log debug; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + keepalive_timeout 65; + + include /etc/nginx/conf.d/*.conf; + + server { + server_name node.left.local; + listen 443 ssl; + http2 on; + ssl_certificate /etc/nginx/ssl/node.left.local.pem; + ssl_certificate_key /etc/nginx/ssl/node.left.local.pem; + ssl_protocols TLSv1.3; + + location / { + proxy_pass http://node-left:8080; + } + } + server { + server_name admin.left.local; + listen 443 ssl; + http2 on; + ssl_certificate /etc/nginx/ssl/admin.left.local.pem; + ssl_certificate_key /etc/nginx/ssl/admin.left.local.pem; + ssl_protocols TLSv1.3; + + location / { + proxy_pass http://admin-left:1305; + } + } + server { + server_name left.local; + listen 443 ssl; + http2 on; + ssl_certificate /etc/nginx/ssl/left.local.pem; + ssl_certificate_key /etc/nginx/ssl/left.local.pem; + ssl_protocols TLSv1.3; + + location / { + proxy_pass http://pep-left:9080; + } + } + server { + server_name node.right.local; + listen 443 ssl; + http2 on; + ssl_certificate /etc/nginx/ssl/node.right.local.pem; + ssl_certificate_key /etc/nginx/ssl/node.right.local.pem; + ssl_protocols TLSv1.3; + + location / { + proxy_pass http://node-right:8080; + } + } + server { + server_name admin.right.local; + listen 443 ssl; + http2 on; + ssl_certificate /etc/nginx/ssl/admin.right.local.pem; + ssl_certificate_key /etc/nginx/ssl/admin.right.local.pem; + ssl_protocols TLSv1.3; + + location / { + proxy_pass http://admin-right:1305; + } + } + server { + server_name right.local; + listen 443 ssl; + http2 on; + ssl_certificate /etc/nginx/ssl/right.local.pem; + ssl_certificate_key /etc/nginx/ssl/right.local.pem; + ssl_protocols TLSv1.3; + + location / { + proxy_pass http://pep-right:9080; + } + } +} diff --git a/docker-compose/left/config/pep/apisix.yaml b/docker-compose/left/config/pep/apisix.yaml new file mode 100644 index 00000000..b6c55ea0 --- /dev/null +++ b/docker-compose/left/config/pep/apisix.yaml @@ -0,0 +1,44 @@ +routes: + - id: demo_public + uri: /* + upstream_id: demo + - id: fhir_server + uri: /fhir/* + upstream_id: fhir + plugin_config_id: introspect-and-opa + - id: demo_authorized + uri: /web/external/transfer/notify/* + upstream_id: demo + plugin_config_id: introspect-and-opa +upstreams: + - id: demo + nodes: + demo-left:1304: 1 + type: roundrobin + - id: fhir + nodes: + hapi-left:8080: 1 + type: roundrobin +# - id: node-internal +# nodes: +# node-left:8081: 1 +# type: roundrobin +# - id: pip +# nodes: +# pip-left:8080: 1 +# type: roundrobin +plugin_configs: + - id: introspect-and-opa + plugins: + openid-connect: + client_id: none + client_secret: none + discovery: none + introspection_endpoint: "http://node-left:8081/internal/auth/v2/accesstoken/introspect" + bearer_only: true + realm: "go-nuts" + introspection_endpoint_auth_method: none + opa: + host: "http://pip-left:8080" + policy: apisix +#END \ No newline at end of file diff --git a/docker-compose/right/config/pep/apisix.yaml b/docker-compose/right/config/pep/apisix.yaml new file mode 100644 index 00000000..578b27e4 --- /dev/null +++ b/docker-compose/right/config/pep/apisix.yaml @@ -0,0 +1,44 @@ +routes: + - id: demo_public + uri: /* + upstream_id: demo + - id: fhir_server + uri: /fhir/* + upstream_id: fhir + plugin_config_id: introspect-and-opa + - id: demo_authorized + uri: /web/external/transfer/notify/* + upstream_id: demo + plugin_config_id: introspect-and-opa +upstreams: + - id: demo + nodes: + demo-right:1304: 1 + type: roundrobin + - id: fhir + nodes: + hapi-right:8080: 1 + type: roundrobin +# - id: node-internal +# nodes: +# node-right:8081: 1 +# type: roundrobin +# - id: pip +# nodes: +# pip-right:8080: 1 +# type: roundrobin +plugin_configs: + - id: introspect-and-opa + plugins: + openid-connect: + client_id: none + client_secret: none + discovery: none + introspection_endpoint: "http://node-right:8081/internal/auth/v2/accesstoken/introspect" + bearer_only: true + realm: "go-nuts" + introspection_endpoint_auth_method: none + opa: + host: "http://pip-right:8080" + policy: apisix +#END \ No newline at end of file diff --git a/domain/fhir/client.go b/domain/fhir/client.go index 1fc6d0f7..f669fff2 100644 --- a/domain/fhir/client.go +++ b/domain/fhir/client.go @@ -86,7 +86,7 @@ func (h httpClient) Create(ctx context.Context, resource interface{}, result int return fmt.Errorf("unable to write FHIR resource (path=%s): %w", requestURI, err) } if !resp.IsSuccess() { - logrus.Warnf("FHIR server replied: %s", resp.String()) + logrus.WithField("func", "Create").Warnf("FHIR server replied: %s", resp.String()) return fmt.Errorf("unable to write FHIR resource (path=%s,http-status=%d): %s", requestURI, resp.StatusCode(), string(resp.Body())) } if result != nil { @@ -106,7 +106,7 @@ func (h httpClient) CreateOrUpdate(ctx context.Context, resource interface{}, re return fmt.Errorf("unable to write FHIR resource (path=%s): %w", requestURI, err) } if !resp.IsSuccess() { - logrus.Warnf("FHIR server replied: %s", resp.String()) + logrus.WithField("func", "CreateOrUpdate").Warnf("FHIR server replied: %s", resp.String()) return fmt.Errorf("unable to write FHIR resource (path=%s,http-status=%d): %s", requestURI, resp.StatusCode(), string(resp.Body())) } if result != nil { @@ -126,7 +126,7 @@ func (h httpClient) ReadMultiple(ctx context.Context, path string, params map[st } err = json.Unmarshal([]byte(resourcesJSON), results) if err != nil { - logrus.Warnf("FHIR server replied: %s", raw.String()) + logrus.WithField("func", "ReadMultiple").Warnf("FHIR server replied: %s", raw.String()) return fmt.Errorf("unable to unmarshal FHIR result (path=%s,target-type=%T): %w", path, results, err) } return nil @@ -139,7 +139,7 @@ func (h httpClient) ReadOne(ctx context.Context, path string, result interface{} } err = json.Unmarshal([]byte(raw.String()), &result) if err != nil { - logrus.Warnf("FHIR server replied: %s", raw.String()) + logrus.WithField("func", "ReadOne").Warnf("FHIR server replied: %s", raw.String()) return fmt.Errorf("unable to unmarshal FHIR result (path=%s,target-type=%T): %w", path, result, err) } return nil @@ -154,7 +154,7 @@ func (h httpClient) getResource(ctx context.Context, path string, params map[str } if !resp.IsSuccess() { - logrus.Warnf("FHIR server replied: %s", resp.String()) + logrus.WithField("func", "getResource").Warnf("FHIR server replied: %s", resp.String()) return gjson.Result{}, fmt.Errorf("unable to read FHIR resource (path=%s,http-status=%d)", path, resp.StatusCode()) } diff --git a/setup.sh b/setup.sh index 9f35280a..0884d8fa 100644 --- a/setup.sh +++ b/setup.sh @@ -1,10 +1,14 @@ #!/usr/bin/env bash +# first argument is the docker compose file to use. +# Defaults to docker-compose-nginx.yml if no argument is provided. The setup is independent of the PEP, so usually fine to not set. +DOCKER_FILE=${1-docker-compose-nginx.yml} + echo "----------------------------------------" echo "Removing data and restarting nodes..." echo "----------------------------------------" # stop all containers so we can delete all data -docker compose down +docker compose -f ${DOCKER_FILE} down sleep 0.5 # If containers fail to restart below, make this longer # delete all data @@ -12,7 +16,7 @@ rm -r ./docker-compose/{left,right}/data/*/* rm -r ./docker-compose/{left,right}/config/demo/customers.json touch ./docker-compose/{left,right}/config/demo/customers.json # or docker will create directories for these mounts during startup -docker compose up --wait +docker compose -f ${DOCKER_FILE} up --wait echo "----------------------------------------" echo "Creating DIDs..." @@ -84,4 +88,4 @@ echo "----------------------------------------" printf "{\n\t\"1\":{\"active\":false,\"city\":\"Enske\",\"did\":\"$DID_LEFT\",\"domain\":\"\",\"id\":1,\"name\":\"Left\"}\n}\n" > ./docker-compose/left/config/demo/customers.json printf "{\n\t\"1\":{\"active\":false,\"city\":\"Enske\",\"did\":\"$DID_RIGHT\",\"domain\":\"\",\"id\":1,\"name\":\"Right\"}\n}\n" > ./docker-compose/right/config/demo/customers.json -docker compose down # at the minimum a restart is needed to load the new customers.json file \ No newline at end of file +docker compose -f ${DOCKER_FILE} down # at the minimum a restart is needed to load the new customers.json file \ No newline at end of file