- EdgeX Foundry Geneva / Hanoi / Ireland release
- Using
edgexfoundry/docker-app-service-configurable:1.3.1
for Geneva / Hanoi - Using
edgexfoundry/app-service-configurable:2.0.1
for Ireland
- Using
- Insecure mode (without Secret Store)
- Disclaimer
- Prepare key and certs to authenticate your EdgeX Foundry
- Prepare Google IoT Core
- Prepare JWT
- Prepare EdgeX Foundry
- Verify your data is available on IoT Core
JWT is required to authenticate with Google IoT Core, and since there is no mechanism in the current app-service-configurable
to automatically renew JWT, it is impossible to use this for a long time if you use app-service-configurable
as is.
Create work directory.
mkdir certs
cd certs
Create an RSA key with a self-signed X.509 certificate.
openssl req -x509 -nodes -newkey rsa:2048 -keyout rsa_private.pem -out rsa_cert.pem -subj "/CN=unused" -days 3650
Download minilal root CA set and convert it to PEM format.
curl -O https://pki.goog/gtsltsr/gtsltsr.crt
curl -O https://pki.goog/gsr4/GSR4.crt
openssl x509 -in gtsltsr.crt -inform DER -out gtsltsr.pem -outform PEM
openssl x509 -in GSR4.crt -inform DER -out GSR4.pem -outform PEM
cat gtsltsr.pem GSR4.pem > rootca.pem
Now you have rsa_cert.pem
, rsa_private.pem
, and rootca.crt
at least.
$ ls -l
-rw-rw-r-- 1 kuro kuro 1389 Oct 16 07:36 rootca.pem
-rw-rw-r-- 1 kuro kuro 1107 Oct 16 07:32 rsa_cert.pem
-rw------- 1 kuro kuro 1704 Oct 16 07:32 rsa_private.pem
- Open [BIG DATA] > [IoT Core] and [ENABLE] API if disabled
- Create new registry
- Click [CREATE REGISTRY]
- Enter any [Registry ID] and [Region]
- Click [Select a Cloud Pub/Sub topic] > [CREATE A TOPIC], then enter any [Topic ID] and click [CREATE TOPIC]
- Click [CREATE] to create registry
- Register your EdgeX Foundry as "Device"
- Open [Devices] and click [CREATE A DEVICE]
- Open [COMMUNICATION, CLOUD LOGGING, AUTHENTICATION] and move to [Authentication (optional)] section
- Select [RS256_X509], then paste your
rsa_cert.pem
- Click [CREATE] to create device
Note that JWT expire after a short time, and since there is no mechanism in the current app-service-configurable
to automatically renew JWT, it is impossible to use this for a long time if you use app-service-configurable
as is.
The Python script is based on the official sample.
# Prepare Python
python3 -m venv .venv
. .venv/bin/activate
python3 -m pip install -U pip
python3 -m pip install pyjwt==2.2.0 cryptography
# Create minimal helper script
cat <<EOF > create_jwt.py
import datetime, os, jwt
def create_jwt(project_id, private_key_file, algorithm):
token = {
"iat": datetime.datetime.utcnow(),
"exp": datetime.datetime.utcnow() + datetime.timedelta(hours=23),
"aud": project_id,
}
with open(private_key_file, "r") as f:
private_key = f.read()
return jwt.encode(token, private_key, algorithm=algorithm)
if __name__ == "__main__":
project_id = os.environ["GOOGLE_IOT_PROJECT"]
private_key_file = os.environ["GOOGLE_IOT_PRIVATE_KEY_FILE"]
algorithm = os.environ["GOOGLE_IOT_ALGORITHM"]
print(create_jwt(project_id, private_key_file, algorithm))
EOF
# Create JWT
export GOOGLE_IOT_PROJECT=<YOUR_PROJECT_ID>
export GOOGLE_IOT_PRIVATE_KEY_FILE=rsa_private.pem
export GOOGLE_IOT_ALGORITHM=RS256
python3 create_jwt.py
Keep your JWT to use later.
This is the snippet for app-service-configurable
for your docker-compose.yml
. Note that the name of environment variable is case sensitive.
See the comments for details.
app-service-mqtt:
# It is recommended that you use the images from the Hanoi release for Geneva too
# as the issue have been fixed.
# https://github.com/edgexfoundry/go-mod-bootstrap/issues/111
image: edgexfoundry/docker-app-service-configurable:1.3.1
ports:
- "127.0.0.1:48097:48097"
container_name: edgex-app-service-configurable-mqtt
hostname: edgex-app-service-configurable-mqtt
networks:
- edgex-network
environment:
<<: *common-variables
edgex_profile: mqtt-export
Service_Host: edgex-app-service-configurable-mqtt
Service_Port: 48097
MessageBus_SubscribeHost_Host: edgex-core-data
Binding_PublishTopic: events
# Requied to use MQTTSecretSend
Writable_Pipeline_ExecutionOrder: "TransformToJSON, MQTTSecretSend, MarkAsPushed"
# Use LTS domain
# https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#using_a_long-term_mqtt_domain
Writable_Pipeline_Functions_MQTTSecretSend_Parameters_brokeraddress: tcps://mqtt.2030.ltsapis.goog:8883
# Topic has to be formatted as "/devices/DEVICE_ID/events"
# https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#publishing_telemetry_events
Writable_Pipeline_Functions_MQTTSecretSend_Parameters_topic: /devices/edgex-foundry/events
# Client ID has to be formatted as "projects/PROJECT_ID/locations/REGION/registries/REGISTRY_ID/devices/DEVICE_ID"
# https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#configuring_mqtt_clients
Writable_Pipeline_Functions_MQTTSecretSend_Parameters_clientid: projects/iot-project-000000/locations/asia-east1/registries/iot-registry/devices/edgex-foundry
# Auth with username and password (JWT)
Writable_Pipeline_Functions_MQTTSecretSend_Parameters_authmode: usernamepassword
# Skip verify to accept unknown authority
Writable_Pipeline_Functions_MQTTSecretSend_Parameters_skipverify: "true"
# Seems any value is ok, but respect the document
# https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#configuring_mqtt_clients
Writable_InsecureSecrets_mqtt_Secrets_username: unused
# Paste your JWT. JWT can be generated using create_jwt.py
Writable_InsecureSecrets_mqtt_Secrets_password: eyJ0eXAiOiJKV1Qi...G7zjg6YRVzoIYZqA
# Contents from rootca.pem
Writable_InsecureSecrets_mqtt_Secrets_cacert: |
-----BEGIN CERTIFICATE-----
MIIBxTCCAWugAwIBAgINAfD3nVndblD3QnNxUDAKBggqhkjOPQQDAjBEMQswCQYD
VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzERMA8G
A1UEAxMIR1RTIExUU1IwHhcNMTgxMTAxMDAwMDQyWhcNNDIxMTAxMDAwMDQyWjBE
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
QzERMA8GA1UEAxMIR1RTIExUU1IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATN
8YyO2u+yCQoZdwAkUNv5c3dokfULfrA6QJgFV2XMuENtQZIG5HUOS6jFn8f0ySlV
eORCxqFyjDJyRn86d+Iko0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw
AwEB/zAdBgNVHQ4EFgQUPv7/zFLrvzQ+PfNA0OQlsV+4u1IwCgYIKoZIzj0EAwID
SAAwRQIhAPKuf/VtBHqGw3TUwUIq7TfaExp3bH7bjCBmVXJupT9FAiBr0SmCtsuk
miGgpajjf/gFigGM34F9021bCWs1MbL0SA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
ewv4n4Q=
-----END CERTIFICATE-----
depends_on:
- consul
- data
Then start your EdgeX Foundry, and send some data from your device. For testing purpose, device-virtual
can be used to send dummy data.
# Start EdgeX Foundry
$ docker-compose up -d
...
# Check logs after sending some data from your device
$ docker logs edgex-app-service-configurable-mqtt
...
level=INFO ts=2021-10-16T08:04:20.540954927Z app=AppService-mqtt-export source=mqttsecret.go:125 msg="Connecting to mqtt server for export"
level=INFO ts=2021-10-16T08:04:20.777252528Z app=AppService-mqtt-export source=mqttsecret.go:134 msg="Connected to mqtt server for export"
This is the snippet for app-service-configurable
for your docker-compose.yml
.
See the comments for details.
app-service-mqtt:
container_name: edgex-app-mqtt-export
depends_on:
- consul
- data
environment:
CLIENTS_CORE_COMMAND_HOST: edgex-core-command
CLIENTS_CORE_DATA_HOST: edgex-core-data
CLIENTS_CORE_METADATA_HOST: edgex-core-metadata
CLIENTS_SUPPORT_NOTIFICATIONS_HOST: edgex-support-notifications
CLIENTS_SUPPORT_SCHEDULER_HOST: edgex-support-scheduler
DATABASES_PRIMARY_HOST: edgex-redis
EDGEX_PROFILE: mqtt-export
EDGEX_SECURITY_SECRET_STORE: "false"
MESSAGEQUEUE_HOST: edgex-redis
REGISTRY_HOST: edgex-core-consul
SERVICE_HOST: edgex-app-mqtt-export
TRIGGER_EDGEXMESSAGEBUS_PUBLISHHOST_HOST: edgex-redis
TRIGGER_EDGEXMESSAGEBUS_SUBSCRIBEHOST_HOST: edgex-redis
# Use LTS domain
# https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#using_a_long-term_mqtt_domain
WRITABLE_PIPELINE_FUNCTIONS_MQTTEXPORT_PARAMETERS_BROKERADDRESS: tcps://mqtt.2030.ltsapis.goog:8883
# Topic has to be formatted as "/devices/DEVICE_ID/events"
# https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#publishing_telemetry_events
WRITABLE_PIPELINE_FUNCTIONS_MQTTEXPORT_PARAMETERS_TOPIC: /devices/edgex-foundry/events
# Client ID has to be formatted as "projects/PROJECT_ID/locations/REGION/registries/REGISTRY_ID/devices/DEVICE_ID"
# https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#configuring_mqtt_clients
WRITABLE_PIPELINE_FUNCTIONS_MQTTEXPORT_PARAMETERS_CLIENTID: projects/iot-project-000000/locations/asia-east1/registries/iot-registry/devices/edgex-foundry
# Auth with username and password (JWT)
WRITABLE_PIPELINE_FUNCTIONS_MQTTEXPORT_PARAMETERS_AUTHMODE: usernamepassword
# Skip verify to accept unknown authority
WRITABLE_PIPELINE_FUNCTIONS_MQTTEXPORT_PARAMETERS_SKIPVERIFY: "true"
# Seems any value is ok, but respect the document
# https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#configuring_mqtt_clients
WRITABLE_INSECURESECRETS_MQTT_SECRETS_USERNAME: unused
# Paste your JWT. JWT can be generated using create_jwt.py
WRITABLE_INSECURESECRETS_MQTT_SECRETS_PASSWORD: eyJ0eXAiOiJKV1Qi...G7zjg6YRVzoIYZqA
# Contents from rootca.pem
WRITABLE_INSECURESECRETS_MQTT_SECRETS_CACERT: |
-----BEGIN CERTIFICATE-----
MIIBxTCCAWugAwIBAgINAfD3nVndblD3QnNxUDAKBggqhkjOPQQDAjBEMQswCQYD
VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzERMA8G
A1UEAxMIR1RTIExUU1IwHhcNMTgxMTAxMDAwMDQyWhcNNDIxMTAxMDAwMDQyWjBE
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
QzERMA8GA1UEAxMIR1RTIExUU1IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATN
8YyO2u+yCQoZdwAkUNv5c3dokfULfrA6QJgFV2XMuENtQZIG5HUOS6jFn8f0ySlV
eORCxqFyjDJyRn86d+Iko0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw
AwEB/zAdBgNVHQ4EFgQUPv7/zFLrvzQ+PfNA0OQlsV+4u1IwCgYIKoZIzj0EAwID
SAAwRQIhAPKuf/VtBHqGw3TUwUIq7TfaExp3bH7bjCBmVXJupT9FAiBr0SmCtsuk
miGgpajjf/gFigGM34F9021bCWs1MbL0SA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
ewv4n4Q=
-----END CERTIFICATE-----
hostname: edgex-app-mqtt-export
image: edgexfoundry/app-service-configurable:2.0.1
networks:
edgex-network: {}
ports:
- 127.0.0.1:59702:59702/tcp
read_only: true
security_opt:
- no-new-privileges:true
user: 2002:2001
Then start your EdgeX Foundry, and send some data from your device. For testing purpose, device-virtual
can be used to send dummy data.
# Start EdgeX Foundry
$ docker-compose up -d
...
# Check logs after sending some data from your device
$ docker logs edgex-app-mqtt-export
...
level=INFO ts=2021-10-16T08:10:38.436078396Z app=app-mqtt-export source=mqttsecret.go:152 msg="Connecting to mqtt server for export"
level=INFO ts=2021-10-16T08:10:38.751541321Z app=app-mqtt-export source=mqttsecret.go:161 msg="Connected to mqtt server for export"
- Open [BIG DATA] > [IoT Core] and select [Telemetry Pub/Sub topics] of your registry
- Create new subscription
- Click [CREATE SUBSCRIPTION] > [Create subscription]
- Enter any [Subscription ID], and for testing, [10] minutes for [Message retention duration], [1] day for [Expiration period]
- Click [CREATE] to create subscription
- On [Subscription details] page, open [MESSAGES] tab
- Click [PULL]
- Ensure your data is displayed