Nginx Component of API Gateway
Edge Xpert uses Nginx as a component of the API gateway, as described below:
Service | Description |
---|---|
nginx | The main component of API Gateway. Started when the --api-gateway option is used with the edgexpert up command |
proxy-auth | The proxy-auth is used to process advanced authentication request for Nginx. The proxy-auth contains the secrets-config utility to assist in common configuration tasks. The commands and options are described in the EdgeX Foundry documentation. Started when the --api-gateway option is used with the edgexpert up command |
redis | The database used by proxy-auth. Started as default service with the edgexpert up command |
Introduction
Edge Xpert used kong
as the API gateway before v2.2 release.
Although kong
is fast, highly-extensible with its feature-advanced plugins, it does not officially support arm32 platform
and has a relatively high memory footprint and image size compared to other microservices.
Therefore, we decided to replace kong
with nginx
since nginx
is lightweight and it supports more architecture which kong
is also built on top of it. As nginx
does not support complicated authentication and authorization mechanisms, proxy-auth
is a dedicated microservice that handles JWT, LDAP authentication and role-based access control authorization.
As demonstrated above, nginx
provides similar functionality to kong
when combined with http_auth_request_module and the proxy-auth
microservice.
Start the Nginx
To start the Nginx, use the following command:
edgexpert up --api-gateway
Using a Bring-Your-Own External TLS Certificate for API Gateway
The API gateway will generate a default self-signed TLS certificate that is used for external communication. Since this certificate is not trusted by client software, it is common to replace this auto-generated certificate with one generated from a known certificate authority, such as an enterprise PKI, or a commercial certificate authority.
The process for obtaining a certificate is out-of-scope for this documentation. For the purposes of the example, the X.509 PEM-encoded certificate is assumed to be called cert.pem and the unencrypted PEM-encoded private key is called key.pem. Do not use an encrypted private key otherwise the API gateway will hang on startup in order to prompt for a password.
For the purposes of the example, the external DNS name of the API gateway is assumed to be edge001.example.com
. The API gateway requires a client to support Server Name Identification (SNI) and that the client connects to the API gateway using a DNS host name. The API gateway uses the host name supplied by the client to determine which certificate to present to the client. The API gateway will continue to serve the default (untrusted) certificate if clients connect via IP address or do not provide SNI at all.
First copy the default nginx configuration at /etc/edgexpert/nginx.conf.xpert and update it:
ssl_certificate /edgex/secrets/nginx/nginx.crt;
ssl_certificate_key /edgex/secrets/nginx/nginx.key;
ssl_certificate /cert.pem;
ssl_certificate_key /key.pem;
Then update docker-compose-security.yml to mount the certificate, private key and updated nginx.conf file to nginx container:
services:
nginx:
volumes:
<path_to_cert.pem>:/cert.pem
<path_to_key.pem>:/key.pem
<path_to_updated_nginx.conf>:/etc/nginx/nginx.conf
Note
You can directly modify the default /etc/edgexpert/docker-compose-security.yml or keep the local -compose-security.yml and leverage docker-compose override mechanism
The following command can verify the certificate installation was successful.
echo "GET /" | openssl s_client -showcerts -servername edge001.example.com -connect 127.0.0.1:8443
Using API Gateway to Proxy Existing EdgeX Microservices
Once the resource mapping and access token to API gateway are in place, a client can use the access token to use the protected EdgeX REST API resources behind the API gateway. Again, without the API Gateway in place, here is the sample request to hit the ping endpoint of the Core Data using curl:
curl http://<host-system-ip>:59880/api/v2/ping
With the security service and JWT authentication enabled, the command changes to:
curl -k -H 'Authorization: Bearer <JWT>' https://<host-system-ip>:8443/core-data/api/v2/ping
For information on creating JWTs to access the gateway, refer to Creating Access Token for API Gateway Authentication.
The /core-data/
path in the URL is used to identify which EdgeX microservice the request is routed to.
Since each EdgeX microservice has a dedicated service port open to accept incoming requests, there is a mapping table kept by the API gateway that maps the path to the microservice port.
Microservice | Path |
---|---|
Core Data | core-data |
Core Metadta | core-metadata |
Core Command | core-command |
Support Notifications | support-notifications |
Support Scheduler | support-scheduler |
System Management Agent | sys-mgmt-agent |
Device Virtual | device-virtual |
Kuiper | rules-engine |
Consul | consul |
API Gateway management interfaces
Edge Xpert provides default nginx configuration file at /etc/edgexpert/nginx.conf.xpert
:
events { }
http {
resolver 127.0.0.11;
map $1 $upstream_host {
core-consul core-consul:8500;
core-data core-data:59880;
core-metadata core-metadata:59881;
core-command core-command:59882;
support-notifications support-notifications:59860;
support-scheduler support-scheduler:59861;
sys-mgmt-agent sys-mgmt:58890;
rules-engine kuiper:59720;
device-virtual device-virtual:59900;
device-rest device-rest:59986;
device-mqtt device-mqtt:59982;
device-opc-ua device-opc-ua:59953;
device-bacnet-ip device-bacnet-ip:59980;
device-bacnet-mstp device-bacnet-mstp:59981;
device-modbus device-modbus:59901;
device-s7 device-s7:59958;
device-gps device-gps:59987;
}
server {
listen 8443 ssl;
ssl_certificate /edgex/secrets/nginx/nginx.crt;
ssl_certificate_key /edgex/secrets/nginx/nginx.key;
error_page 500 @process_proxy_auth_error;
location ~ ^/([\w'-]+)/(.+)$ {
auth_request /_auth-jwt;
auth_request_set $backend_status $upstream_status;
proxy_pass http://$upstream_host/$2$is_args$args;
}
location = /_auth-jwt {
internal;
proxy_method GET;
proxy_pass_request_body off;
proxy_pass_request_headers on;
proxy_set_header Content-Length "";
# required for proxy-auth RBAC authorization
proxy_set_header X-Original-Uri $request_uri;
proxy_set_header X-Original-Method $request_method;
proxy_pass http://proxy-auth:8079/jwt-auth;
}
location @process_proxy_auth_error {
if ($backend_status = 400) {
return 400;
}
if ($backend_status = 401) {
return 401;
}
if ($backend_status = 403) {
return 403;
}
if ($backend_status = 500) {
return 500;
}
}
}
}