API Service

Introduction

DCP provides an API Gateway as an entry point for programmatically access to the data stored in the platform. The default access is provided to endpoints which doesn't change/manipulate data stored in the system. The access is read-only. The implementation is based Ocelot, a .NET API Gateway and aimed at people using .NET running a micro services / service oriented architecture that need a unified point of entry into their system. However, it will work with anything that speaks HTTP so that modules using a different technology stacks can be accessed as well. Simplified Ocelot is mapping an API endpoint on the Gateway (Upstream Path) to the correct server and API endpoint on the corresponding microservice (Downstream Path).

The documentation on the gateway is provided by SwaggerForOcelot, which allows viewing and using swagger documentation for downstream services directly through the Ocelot project. It's the responsibility of the underlying modules to provide respective documentation.

Configuration

The Gateway is configured using multiple (module specific) configuration files. The currently active (and combined) configuration can be viewed in the ocelot.json file on the project root directory. This file is recreated on start-up (e.g. application pool recycle) based on the configuration files in the ./Configuration directory. The following files provide configuration and are merged:

  • A global configuration file for ocelot: ocelot.global.json
  • A configuration for mapping the swagger files/documentation: ocelot.swagger.json
  • A module specific configuration file, providing the routes per module: ocelot.{moduleName}.json

The module specific configuration files are included in the source code of the module.

Inside .NET based API controllers, a custom boolean attribute (APIGateWay(IsExposed = true)) can be used to mark endpoints which should be available on the Gateway level. A console application named GatewayFileBuilder can be used to generate the module specific ocelot.{module}.json file.

The creation of module specific configuration file is happening on build time. During the publish command, files are created at publish/bin/APIGateway/. The CI/CD process is taking care of moving the file to the data directory of the server hosting DCP framework.

Runtime changes

In order to activate or deactivate an API at runtime. The following workflow is implemented:

  • Configuration files are copied/deleted:
    • On Activate: copy the module specific file from the data directory to the Configuration directory of the API gateway
    • On Deactivate: remove the file from the Configuration folder in the APIGateway directory
  • Restart IIS site in order to make the changes effective. This is achieved by injecting IHostApplicationLifetime into the app to enable a request triggered stop of the IIS Site. If deployed using IIS the next request to the website will start up the application again. With the startup, the configuration changes are applied.

Rate Limiting

Ocelot implements Rate Limiting to secure against overloading. Rate Limiting default parameters are:

  • ClientWhitelist: [],
  • EnableRateLimiting: true,
  • Period: 1s,
  • PeriodTimespan: 1,
  • Limit: 50

On the global level, a rate limit is indicated by a 429 status code and the message: "Exceeds DCP Rate Limit". For configuring the rate limiting see the Ocelot documentation.

Security

In order to provide access to the API swagger files on production environments where API documentation should be disabled for security reasons, as a tradeoff, only endpoints exposed via the gateway are available and only through the gateway. This is implemented as following: a header X-DCPGateway-SwaggerKey with a randomized key value is added on the gateway layer before passing the request to the downstream services. In production mode all requests to the swagger files of a microservice are rejected as not authorized by the middleware (DownstreamSwaggerHeaders in UseSwaggerForOcelotUI) if the header is missing or the value is incorrect. A similar workflow is implemented to avoid the abuse of client credentials outside the context of the APIGateway, before passing the request to the downstream mapping a header (X-DCPGateway-Key) is added to the request. The permission checks in the downstream microservices are extended if the grant_type is 2 (client credentials): only requests with a matching X-DCPGateway-Key are served. If the underlying resources reuses the client credentials to access information from another microservice a X-DCPMircoservice-Key header is added, following the same principle for internal communication.

Gateway Filebuilder

In order to simplify the process of generating the ocelot.module.json files, which are used to configure the API Gateway a console application was developed. The application is provided as a docker container or can be run locally using dotnet.

Usage

The gateway filebuilder can be used from a docker container. In order to use the application from the docker container, mount the output directory of the .NET project to the /api path in the docker container.

docker run \
    -v .DigitalClonePlatform.MVDA.API/bin/Dev/net8.0:/api \
    ${registry_domain}/digitalclone/platform/be2/gateway-filebuilder --VaultUser="user" --VaultPassword="Password" --ModulePath="/api/DigitalClonePlatform.MVDA.API.dll"

Configuration of the filebuilder is based on two main files or can be provided via CLI:

  • module.config.json
  • appsettings.json

In the example above the configuration --VaultPassword= and VaultPassword= are provided via CLI. It does not matter from where the configuration is provided.

The module.config.json has the following structure:

{
  "ModuleHost": "dc-dev-nongxp.localhost",
  "ModulePort": 8188,
  "SwaggerKey": "MVDA",
  "ModuleShort": "mvda"
}

The property has the following structure:

Property Description
ModuleHost The FQDN where the API is deployed/the gateway should route to
ModulePort The port where the module API is deployed
SwaggerKey The key used in the routes to expose the API on the Gateway
ModuleShort The short short used for module identification (filenames, keys, etc.)

The appsettings.json has the following structure:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "DCPMicroserviceHeaderName": "X-DCPMicroservice-Key",
  "AuthenticationScheme": "ApiGateWaySchema",
  "DCPAPIGatewayHeaderName": "X-DCPGateway-Key",
  "DCPAPIGatewaySwaggerHeaderName": "X-DCPGateway-SwaggerKey",
  //SecretConfigurationProvider
  "VaultServerUri": "https://vault.service.domain.com",
  "VaultNamespace": "dcp",
  "VaultAuthMethod": "UserPass",
  "VaultAppConfigMountPoint": "app-config/",
  "VaultHeadersPath": "dev/headers",
  "CSRFHeaderName": "X-Requested-With"
}

In this example - secret configuration is provided by HashiCorpVault (keys used: VaultServerUri, VaultNamespace, VaultAuthMethod, VaultAppMountPoint, VaultHeadersPath), if you want you use a different SecretProvider - you can change the dependency injection - in these cases different configuration keys might be required. See the SecretConfigurationProvider section in the DCP Framework.

Property Description
AllowedHosts The list of host which are allowed to consume the gateway - as a default every host are allowed
DCPAPIGatewayHeaderName The name of the header added on the gateway - used for the authentication
DCPAPIGatewaySwaggerHeaderName The name of the header added on the gateway - used for the authentication
ModuleShort The short short used for module identification (filenames, keys, etc.)

The docker image contains some default configuration - the jq utility is installed in the container and can be used to overwrite some keys. An example, can be found below:

jq '.Name="test"' appsettings.json

in order to do this overwrite the entrypoint of the container to /bin/bash.

This page was last edited on 03 May 2024, 08:19 (UTC).