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.
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:
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.
In order to activate or deactivate an API at runtime. The following workflow is implemented:
Ocelot implements Rate Limiting to secure against overloading. Rate Limiting default parameters are:
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.
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.
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.
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:
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
.