Configuring Add-on Service
In the current EdgeX security serivces, we set up and configure all security related properties and environments
for the existing default serivces like core-data
, core-metadata
, device-virtual
, and so on.
The settings and service environment variables are pre-wired and ready to run in secure mode without any update
or modification to the Docker-compose files. However, there are some pre-built add-on services like some device services
(e.g.device-camera
, device-modbus
), and some of application services (e.g. app-http-export
, app-mqtt-export
)
are not pre-wired for by default. Also if you are adding on your custom application service,
there is no pre-wiring for it and thus need some configuration efforts to make them run in secure mode.
EdgeX provides a way for a user to add and configure those add-on services into EdgeX Docker
software stack running in secure mode. This can be done vai Docker-compose files with a few additional
environment variables and some modification of micro-service's Dockerfile. From edgex-compose
repository,
the compose-builder
utility provides some ways to deal with those add-on services like through add-security.yml
via make
targets to generate docker-compose
file for running them in secure mode. For more details, please refer to
README documentation of compose-builder.
The above same guidelines can also be applied to custom device and application services, i.e. non-EdgeX built services.
One of the major security features in EdgeX Ireland release is to utilize the service security-bootstrapper
to ensure the right starting sequence so that all services have their needed security dependencies
when they start up.
Currently EdgeX uses Vault
as the default implementation for secret store and Consul as the configuration
and/or registry server if user chooses to do so. There are some default services pre-configured to have
Secret Stores
created by default such as EdgeX core/support services, device-virtual, device-rest, and
app-rules-engine services.
For running additional add-on services (e.g. device-camera
, app-http-export
) in secure mode,
their Secret Stores
are not generated by default but they can be generated
through some configuring steps as shown below.
In the following scenario, we assume the EdgeX services are running in Docker environments,
and thus the examples are given in terms of Docker-compose ways. It should not be much or bigger
difference for snap
running environment to apply the same steps or concepts if found to do so.
If users want to configure and set up an add-on service, e.g. device-camera
,
they can achieve this by following the steps that are outlined below:
Make add-on services security-bootstrapper compatible
To use the Docker entrypoint scripts for gating mechanism from security-bootstrapper
,
the Dockerfile of device-camera
should inherit shell scripting capability like alpine
-based
as the base Docker image and should install dumb-init
(see details in
Why you need an init system)
via apk add --update
command.
Dockerfile example using alpine-base image and add dumb-init
:
......
FROM alpine:3.12
# dumb-init needed for injected secure bootstrapping entrypoint script when run in secure mode.
RUN apk add --update --no-cache dumb-init
......
and then for the service itself should add /edgex-init/ready_to_run_wait_install.sh
as the entrypoint script for the service in gating fashion and add related Docker volumes
for edgex-init
and for Secret Store
token, which will be outlined in the next section.
A good example of this will be like app-service-rules
:
...
app-service-rules:
entrypoint: ["/edgex-init/ready_to_run_wait_install.sh"]
command: "/app-service-configurable ${DEFAULT_EDGEX_RUN_CMD_PARMS}"
volumes:
- edgex-init:/edgex-init:ro,z
- /tmp/edgex/secrets/app-rules-engine:/tmp/edgex/secrets/app-rules-engine:ro,z
depends_on:
- security-bootstrapper
...
Note that we also add command
directive override in the above example because we override
Docker's entrypoint script in the original Dockerfile and Docker ignores the original command
when the entrypoint script is overridden. In this case, we also override the command
for
app-service-rules
service with arguments to execute.
Configure the service's Secret Store
to use
Make sure the TOML configuration file of add-on service like device-camera
contains
the proper [SecretStore]
section.
Example:
[SecretStore]
Type = "vault"
Host = "localhost"
Port = 8200
Path = "device-camera/"
Protocol = "http"
RootCaCertPath = ""
ServerName = ""
TokenFile = "/tmp/edgex/secrets/device-camera/secrets-token.json"
[SecretStore.Authentication]
AuthType = "X-Vault-Token"
Note that the service key device-camera
must be used for the Path
and in the TokenFile
path
to keep it consistent and easier to maintain.
And then add the add-on service's service key to EdgeX service secretstore-setup
's
ADD_SECRETSTORE_TOKENS
environment variable in the environment
section of docker-compose
as the example shown below:
...
secretstore-setup:
container_name: edgex-secretstore-setup
depends_on:
- security-bootstrapper
- vault
environment:
ADD_SECRETSTORE_TOKENS: 'device-camera'
...
With that, secretstore-setup
then will generate Secret Store
token from Vault
and store it in
the TokenFile
path specified in the TOML configuration file like the above example.
Also note that the value of ADD_SECRETSTORE_TOKENS
can take more than one service in a form of
comma separated list like "device-camera
, device-modbus
" if needed.
(Optional) Configure known secrets for add-on services
The ADD_KNOWN_SECRETS
environment variable on secretstore-setup
allows for known secrets
to be added to an add-on service's Secret Store
.
For the Ireland release, the only known
secret is the Redis DB credentials
identified by
the name redisdb
. Any add-on service needing access to the Redis DB
such as
App Service HTTP Export with Store and Forward enabled will need the Redis DB credentials
put in its Secret Store
. Also, since the Redis DB
service is now used for the MessageBus implementation,
all services that connect to the MessageBus also need the Redis DB credentials
Note that the steps needed for connecting add-on services to the Secure MessageBus
are:
- Utilizing the
security-bootstrapper
to ensure proper startup sequence - Creating the
Secret Store
for the add-on service - Adding the
redisdb
's known secret to the add-on service'sSecret Store
and if the add-on service is not connecting to the bus or the Redis database, then this step can be skipped.
So given an example for service device-virtual
to use the Redis
message bus in secure mode,
we need to tell secretstore-setup
to add the redisdb
known secret to Secret Store
for device-virtual
.
This can be done through the configuration of adding redisdb[device-virtual]
into the environment variable
ADD_KNOWN_SECRETS
in secretstore-setup
service's environment section, in which redisdb
is the name of
the known secret
and device-virtual
is the service key of the add-on service.
...
secretstore-setup:
container_name: edgex-secretstore-setup
depends_on:
- security-bootstrapper
- vault
environment:
ADD_SECRETSTORE_TOKENS: 'device-camera, my-service'
ADD_KNOWN_SECRETS: redisdb[app-rules-engine],redisdb[device-rest],redisdb[device-virtual]
...
In the above docker-compose
section of secretstore-setup
, we specify the known secret of
redisdb
to add/copy the Redis database credentials to the Secret Store
for the app-rules-engine
,
device-rest
, and device-virtual
services.
We can also use the alternative or simpler form of ADD_KNOWN_SECRETS
environment variable's value like
ADD_KNOWN_SECRETS: redisdb[app-rules-engine, device-rest, device-virtual]
in which all add-on services are put together in a comma separated list associated with the
known secret redisdb
.
(Optional) Configure the ACL role of configuration/registry to use if the service depends on it
This is a new step coming from securing Consul
security features as part of EdgeX Ireland release.
If the add-on service uses Consul
as the configuration and/or registry service, then we also need to
configure the environment variable ADD_REGISTRY_ACL_ROLES
to tell security-bootstrapper
to generate
an ACL role for Consul
to associate with its token.
An example of configuring ACL roles of the registry Consul
for the add-on services
device-modbus
and app-http-export
is shown as follows:
...
consul:
container_name: edgex-core-consul
depends_on:
- security-bootstrapper
- vault
entrypoint:
- /edgex-init/consul_wait_install.sh
environment:
ADD_REGISTRY_ACL_ROLES: app-http-export,device-modbus
...
The configuration of Edgex service consul
's environment variable ADD_REGISTRY_ACL_ROLES
tells
the security-bootstrapper
to set up Consul
ACL role so that the ACL token is generated,
hence the permission is granted for that service with the access to Consul
in secure mode.
Without this step the add-on service will get status Forbidden
(HTTP status code = 403) error
when the service is depending on Consul and attempting to access Consul for configuration or
service registry.
(Optional) Configure the API gateway access route for add-on service
If it is desirable to let user or other application services outside EdgeX's Docker network access
the endpoint of the add-on service, then we can configure and add it via proxy-setup
service's
ADD_PROXY_ROUTE
environment variable. proxy-setup
adds those services listed in that environment
variable into the API gateway (also known as Kong) route so that the endpoint can be accessible
using Kong's proxy endpoint.
One example of adding API gateway access routes for both device-camera
and device-modbus
is given as follows:
...
edgex-proxy:
...
environment:
...
ADD_PROXY_ROUTE: "device-camera.http://edgex-device-camera:59985, device-modbus.http://edgex-device-modbus:59901"
...
...
where in the comma separated list, the first part of configured value device-camera
is the service key
and the URL format is the service's hostname with its docker network port number 59985
for device-camera
. The same idea applies to device-modbus
with its values.
With that setup, we can then access the endpoints of device-camera
from Kong's host like
https://<HostName>:8443/device-camera/{device-name}/name
assuming the caller can resolve
<HostName>
from DNS server.
For more details on the introduction to the API gateway and how it works, please see APIGateway documentation page.