mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-27 13:48:49 +08:00

* MF-448 - Option for Postgres SSL Mode Adds an option to choose the ssl mode when connecting to postgres. Only supporting disable or require for now with verify-ca and verify-full to come after more discussion. Signed-off-by: Michael Finley <Michael.Finley@target.com> * Changing package name back Accidentally changed the package name so reverting that! Signed-off-by: Michael Finley <Michael.Finley@target.com> * Adding section in getting-started for securing pgsql connections Signed-off-by: Michael Finley <Michael.Finley@target.com>
506 lines
17 KiB
Markdown
506 lines
17 KiB
Markdown
## Prerequisites
|
|
|
|
Before proceeding, install the following prerequisites:
|
|
|
|
- [Docker](https://docs.docker.com/install/)
|
|
- [Docker compose](https://docs.docker.com/compose/install/)
|
|
- [jsonpp](https://jmhodges.github.io/jsonpp/) (optional)
|
|
|
|
Once everything is installed, execute the following commands from project root:
|
|
|
|
```bash
|
|
docker-compose -f docker/docker-compose.yml up -d
|
|
```
|
|
|
|
## User management
|
|
|
|
### Account creation
|
|
|
|
Use the Mainflux API to create user account:
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "Content-Type: application/json" https://localhost/users -d '{"email":"john.doe@email.com", "password":"123"}'
|
|
```
|
|
|
|
Note that when using official `docker-compose`, all services are behind `nginx`
|
|
proxy and all traffic is `TLS` encrypted.
|
|
|
|
### Obtaining an authorization key
|
|
|
|
In order for this user to be able to authenticate to the system, you will have
|
|
to create an authorization token for him:
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "Content-Type: application/json" https://localhost/tokens -d '{"email":"john.doe@email.com", "password":"123"}'
|
|
```
|
|
|
|
Response should look like this:
|
|
```
|
|
{
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjMzODg0NzcsImlhdCI6MTUyMzM1MjQ3NywiaXNzIjoibWFpbmZsdXgiLCJzdWIiOiJqb2huLmRvZUBlbWFpbC5jb20ifQ.cygz9zoqD7Rd8f88hpQNilTCAS1DrLLgLg4PRcH-iAI"
|
|
}
|
|
```
|
|
|
|
## System provisioning
|
|
|
|
Before proceeding, make sure that you have created a new account, and obtained
|
|
an authorization key.
|
|
|
|
### Provisioning devices
|
|
|
|
Devices are provisioned by executing request `POST /things`, with a
|
|
`"type":"device"` specified in JSON payload. Note that you will also need
|
|
`user_auth_token` in order to provision things (both devices and application)
|
|
that belong to this particular user.
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "Content-Type: application/json" -H "Authorization: <user_auth_token>" https://localhost/things -d '{"type":"device", "name":"weio"}'
|
|
```
|
|
|
|
Response will contain `Location` header whose value represents path to newly
|
|
created thing:
|
|
|
|
```
|
|
HTTP/1.1 201 Created
|
|
Content-Type: application/json
|
|
Location: /things/81380742-7116-4f6f-9800-14fe464f6773
|
|
Date: Tue, 10 Apr 2018 10:02:59 GMT
|
|
Content-Length: 0
|
|
```
|
|
|
|
### Provisioning applications
|
|
|
|
Applications are provisioned by executing HTTP request `POST /things`, with
|
|
`"type":"app"` specified in JSON payload.
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "Content-Type: application/json" -H "Authorization: <user_auth_token>" https://localhost/things -d '{"type":"app", "name":"myapp"}'
|
|
```
|
|
|
|
Response will contain `Location` header whose value represents path to newly
|
|
created thing (same as for devices):
|
|
|
|
```
|
|
HTTP/1.1 201 Created
|
|
Content-Type: application/json
|
|
Location: /things/cb63f852-2d48-44f0-a0cf-e450496c6c92
|
|
Date: Tue, 10 Apr 2018 10:33:17 GMT
|
|
Content-Length: 0
|
|
```
|
|
|
|
### Retrieving provisioned things
|
|
|
|
In order to retrieve data of provisioned things that is written in database, you
|
|
can send following request:
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -H "Authorization: <user_auth_token>" https://localhost/things
|
|
```
|
|
|
|
Notice that you will receive only those things that were provisioned by
|
|
`user_auth_token` owner.
|
|
|
|
```
|
|
HTTP/1.1 200 OK
|
|
Content-Type: application/json
|
|
Date: Tue, 10 Apr 2018 10:50:12 GMT
|
|
Content-Length: 1105
|
|
|
|
{
|
|
"things": [
|
|
{
|
|
"id": "81380742-7116-4f6f-9800-14fe464f6773",
|
|
"type": "device",
|
|
"name": "weio",
|
|
"key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MjMzNTQ1NzksImlzcyI6Im1haW5mbHV4Iiwic3ViIjoiODEzODA3NDItNzExNi00ZjZmLTk4MDAtMTRmZTQ2NGY2NzczIn0.5s8s1hlK-l30kQAyHxEZO_M2NIQw53MQuy7b3Wf3OOE"
|
|
},
|
|
{
|
|
"id": "cb63f852-2d48-44f0-a0cf-e450496c6c92",
|
|
"type": "app",
|
|
"name": "myapp",
|
|
"key": "cbf02d60-72f2-4180-9f82-2c957db929d1"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
You can specify `offset` and `limit` parameters in order to fetch specific
|
|
group of things. In that case, your request should look like:
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -H "Authorization: <user_auth_token>" https://localhost/things?offset=0&limit=5
|
|
```
|
|
|
|
If you don't provide them, default values will be used instead: 0 for `offset`,
|
|
and 10 for `limit`. Note that `limit` cannot be set to values greater than 100. Providing
|
|
invalid values will be considered malformed request.
|
|
|
|
### Removing things
|
|
|
|
In order to remove you own thing you can send following request:
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X DELETE -H "Authorization: <user_auth_token>" https://localhost/things/<thing_id>
|
|
```
|
|
|
|
### Provisioning channels
|
|
|
|
Channels are provisioned by executing request `POST /channels`:
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "Content-Type: application/json" -H "Authorization: <user_auth_token>" https://localhost/channels -d '{"name":"mychan"}'
|
|
```
|
|
|
|
After sending request you should receive response with `Location` header that
|
|
contains path to newly created channel:
|
|
|
|
```
|
|
HTTP/1.1 201 Created
|
|
Content-Type: application/json
|
|
Location: /channels/19daa7a8-a489-4571-8714-ef1a214ed914
|
|
Date: Tue, 10 Apr 2018 11:30:07 GMT
|
|
Content-Length: 0
|
|
```
|
|
|
|
### Retrieving provisioned channels
|
|
|
|
To retreve provisioned channels you should send request to `/channels` with
|
|
authorization token in `Authorization` header:
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -H "Authorization: <user_auth_token>" https://localhost/channels
|
|
```
|
|
|
|
Note that you will receive only those channels that were created by authorization
|
|
token's owner.
|
|
|
|
```
|
|
HTTP/1.1 200 OK
|
|
Content-Type: application/json
|
|
Date: Tue, 10 Apr 2018 11:38:06 GMT
|
|
Content-Length: 139
|
|
|
|
{
|
|
"channels": [
|
|
{
|
|
"id": "19daa7a8-a489-4571-8714-ef1a214ed914",
|
|
"name": "mychan"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
You can specify `offset` and `limit` parameters in order to fetch specific
|
|
group of channels. In that case, your request should look like:
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -H "Authorization: <user_auth_token>" https://localhost/channels?offset=0&limit=5
|
|
```
|
|
|
|
If you don't provide them, default values will be used instead: 0 for `offset`,
|
|
and 10 for `limit`. Note that `limit` cannot be set to values greater than 100. Providing
|
|
invalid values will be considered malformed request.
|
|
|
|
### Removing channels
|
|
|
|
In order to remove specific channel you should send following request:
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X DELETE -H "Authorization: <user_auth_token>" https://localhost/channels/<channel_id>
|
|
```
|
|
|
|
## Access control
|
|
|
|
Channel can be observed as a communication group of things. Only things that
|
|
are connected to the channel can send and receive messages from other things
|
|
in this channel. things that are not connected to this channel are not allowed
|
|
to communicate over it.
|
|
|
|
Only user, who is the owner of a channel and of the things, can connect the
|
|
things to the channel (which is equivalent of giving permissions to these things
|
|
to communicate over given communication group).
|
|
|
|
To connect thing to the channel you should send following request:
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X PUT -H "Authorization: <user_auth_token>" https://localhost/channels/<channel_id>/things/<thing_id>
|
|
```
|
|
|
|
You can observe which things are connected to specific channel:
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -H "Authorization: <user_auth_token>" https://localhost/channels/<channel_id>
|
|
```
|
|
|
|
You should receive response with the lists of connected things in `connected` field
|
|
similar to this one:
|
|
|
|
```
|
|
{
|
|
"id": "19daa7a8-a489-4571-8714-ef1a214ed914",
|
|
"name": "mychan",
|
|
"connected": [
|
|
{
|
|
"id": "81380742-7116-4f6f-9800-14fe464f6773",
|
|
"type": "device",
|
|
"name": "weio",
|
|
"key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MjMzNTQ1NzksImlzcyI6Im1haW5mbHV4Iiwic3ViIjoiODEzODA3NDItNzExNi00ZjZmLTk4MDAtMTRmZTQ2NGY2NzczIn0.5s8s1hlK-l30kQAyHxEZO_M2NIQw53MQuy7b3Wf3OOE"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
If you want to disconnect your device from the channel, send following request:
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X DELETE -H "Authorization: <user_auth_token>" https://localhost/channels/<channel_id>/things/<thing_id>
|
|
```
|
|
|
|
## Sending messages
|
|
|
|
Once a channel is provisioned and thing is connected to it, it can start to
|
|
publish messages on the channel. The following sections will provide an example
|
|
of message publishing for each of the supported protocols.
|
|
|
|
### HTTP
|
|
|
|
To publish message over channel, thing should send following request:
|
|
|
|
```
|
|
curl -s -S -i --cacert docker/ssl/certs/mainflux-server.crt --insecure -X POST -H "Content-Type: application/senml+json" -H "Authorization: <thing_token>" https://localhost/http/channels/<channel_id>/messages -d '[{"bn":"some-base-name:","bt":1.276020076001e+09, "bu":"A","bver":5, "n":"voltage","u":"V","v":120.1}, {"n":"current","t":-5,"v":1.2}, {"n":"current","t":-4,"v":1.3}]'
|
|
```
|
|
|
|
Note that you should always send array of messages in senML format.
|
|
|
|
### WebSocket
|
|
|
|
To publish and receive messages over channel using web socket, you should first
|
|
send handshake request to `/channels/<channel_id>/messages` path. Don't forget
|
|
to send `Authorization` header with thing authorization token.
|
|
|
|
If you are not able to send custom headers in your handshake request, send it as
|
|
query parameter `authorization`. Then your path should look like this
|
|
`/channels/<channel_id>/messages?authorization=<thing_auth_key>`.
|
|
|
|
If you are using the docker environment prepend the url with `ws`. So for example
|
|
`/ws/channels/<channel_id>/messages?authorization=<thing_auth_key>`
|
|
|
|
#### Basic nodejs example
|
|
|
|
```javascript
|
|
const WebSocket = require('ws');
|
|
|
|
// do not verify self-signed certificates if you are using one
|
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
|
|
|
// cbf02d60-72f2-4180-9f82-2c957db929d1 is an example of a thing_auth_key
|
|
const ws = new WebSocket('wss://localhost/ws/channels/1/messages?authorization=cbf02d60-72f2-4180-9f82-2c957db929d1')
|
|
|
|
ws.on('open', () => {
|
|
ws.send('something')
|
|
})
|
|
|
|
ws.on('message', (data) => {
|
|
console.log(data)
|
|
})
|
|
ws.on('error', (e) => {
|
|
console.log(e)
|
|
})
|
|
```
|
|
|
|
### MQTT
|
|
|
|
To send and receive messages over MQTT you could use [Mosquitto tools](https://mosquitto.org),
|
|
or [Paho](https://www.eclipse.org/paho/) if you want to use MQTT over WebSocket.
|
|
|
|
To publish message over channel, thing should call following command:
|
|
|
|
```
|
|
mosquitto_pub -u <thing_id> -P <thing_key> -t channels/<channel_id>/messages -h localhost -m '[{"bn":"some-base-name:","bt":1.276020076001e+09, "bu":"A","bver":5, "n":"voltage","u":"V","v":120.1}, {"n":"current","t":-5,"v":1.2}, {"n":"current","t":-4,"v":1.3}]'
|
|
```
|
|
|
|
To subscribe to channel, thing should call following command:
|
|
|
|
```
|
|
mosquitto_sub -u <thing_id> -P <thing_key> -t channels/<channel_id>/messages -h localhost
|
|
```
|
|
|
|
If you are using TLS to secure MQTT connection, add `--cafile docker/ssl/certs/ca.crt`
|
|
to every command.
|
|
|
|
## Add-ons
|
|
|
|
The `<project_root>/docker` folder contains an `addons` directory. This directory is used for various services that are not core to the Mainflux platform but could be used for providing additional features.
|
|
|
|
In order to run these services, core services, as well as the network from the core composition, should be already running.
|
|
|
|
### Writers
|
|
|
|
Writers provide an implementation of various `message writers`. Message writers are services that consume normalized (in `SenML` format) Mainflux messages and store them in specific data store.
|
|
|
|
#### InfluxDB, InfluxDB-writer and Grafana
|
|
|
|
From the project root execute the following command:
|
|
|
|
```bash
|
|
docker-compose -f docker/addons/influxdb-writer/docker-compose.yml up -d
|
|
```
|
|
This will install and start:
|
|
|
|
- [InfluxDB](https://docs.influxdata.com/influxdb) - time series database
|
|
- InfluxDB writer - message repository implementation for InfluxDB
|
|
- [Grafana](https://grafana.com) - tool for database exploration and data visualization and analytics
|
|
|
|
Those new services will take some additional ports:
|
|
|
|
- 8086 by InfluxDB
|
|
- 8900 by InfluxDB writer service
|
|
- 3001 by Grafana
|
|
|
|
To access Grafana, navigate to `http://localhost:3001` and login with: `admin`, password: `admin`
|
|
|
|
#### Cassandra and Cassandra-writer
|
|
|
|
```bash
|
|
./docker/addons/cassandra-writer/init.sh
|
|
```
|
|
_Please note that Cassandra may not be suitable for your testing enviroment because it has high system requirements._
|
|
|
|
#### MongoDB and MongoDB-writer
|
|
|
|
```bash
|
|
docker-compose -f docker/addons/mongodb-writer/docker-compose.yml up -d
|
|
```
|
|
MongoDB default port (27017) is exposed, so you can use various tools for database inspection and data visualization.
|
|
|
|
### Readers
|
|
|
|
Readers provide an implementation of various `message readers`.
|
|
Message readers are services that consume normalized (in `SenML` format) Mainflux messages from data storage and opens HTTP API for message consumption.
|
|
Installing corresponding writer before reader is implied.
|
|
|
|
|
|
#### InfluxDB-reader
|
|
|
|
```bash
|
|
docker-compose -f docker/addons/influxdb-reader/docker-compose.yml up -d
|
|
```
|
|
Service exposes [HTTP API](https://github.com/mainflux/mainflux/blob/master/readers/swagger.yml) for fetching messages on port 8905
|
|
|
|
|
|
To read sent messages on channel with id `channel_id` you should send `GET` request to `/channels/<channel_id>/messages` with thing access token in `Authorization` header. That thing must be connected to channel with `channel_id`
|
|
|
|
```
|
|
curl -s -S -i -H "Authorization: <thing_token>" http://localhost:8905/channels/<channel_id>/messages
|
|
```
|
|
|
|
Response should look like this:
|
|
|
|
```
|
|
HTTP/1.1 200 OK
|
|
Content-Type: application/json
|
|
Date: Tue, 18 Sep 2018 18:56:19 GMT
|
|
Content-Length: 228
|
|
|
|
{
|
|
"messages": [
|
|
{
|
|
"Channel": 1,
|
|
"Publisher": 2,
|
|
"Protocol": "mqtt",
|
|
"Name": "name:voltage",
|
|
"Unit": "V",
|
|
"Value": 5.6,
|
|
"Time": 48.56
|
|
},
|
|
{
|
|
"Channel": 1,
|
|
"Publisher": 2,
|
|
"Protocol": "mqtt",
|
|
"Name": "name:temperature",
|
|
"Unit": "C",
|
|
"Value": 24.3,
|
|
"Time": 48.56
|
|
}
|
|
]
|
|
}
|
|
```
|
|
Note that you will receive only those messages that were sent by authorization token's owner.
|
|
You can specify `offset` and `limit` parameters in order to fetch specific group of messages. In that case, your request should look like:
|
|
|
|
```
|
|
curl -s -S -i -H "Authorization: <thing_token>" http://localhost:8905/channels/<channel_id>/messages?offset=0&limit=5
|
|
```
|
|
If you don't provide them, default values will be used instead: 0 for `offset`, and 10 for `limit`.
|
|
|
|
#### Cassandra-reader
|
|
|
|
```bash
|
|
docker-compose -f docker/addons/cassandra-reader/docker-compose.yml up -d
|
|
```
|
|
Service exposes [HTTP API](https://github.com/mainflux/mainflux/blob/master/readers/swagger.yml) for fetching messages on port 8903
|
|
|
|
Aside from port, reading request is same as for other readers:
|
|
|
|
```
|
|
curl -s -S -i -H "Authorization: <thing_token>" http://localhost:8903/channels/<channel_id>/messages
|
|
```
|
|
|
|
#### MongoDB-reader
|
|
|
|
```bash
|
|
docker-compose -f docker/addons/mongodb-reader/docker-compose.yml up -d
|
|
```
|
|
Service exposes [HTTP API](https://github.com/mainflux/mainflux/blob/master/readers/swagger.yml) for fetching messages on port 8904
|
|
|
|
Aside from port, reading request is same as for other readers:
|
|
|
|
```
|
|
curl -s -S -i -H "Authorization: <thing_token>" http://localhost:8904/channels/<channel_id>/messages
|
|
```
|
|
|
|
## TLS Configuration
|
|
|
|
By default gRPC communication is not secure.
|
|
|
|
### Server configuration
|
|
|
|
### Securing PostgreSQL connections
|
|
|
|
By default, Mainflux will connect to Postgres using insecure transport.
|
|
If a secured connection is required, you can select the SSL mode.
|
|
|
|
`MF_USERS_DB_SSL_MODE` the SSL connection mode for Users.
|
|
|
|
`MF_THINGS_DB_SSL_MODE` the SSL connection mode for Things.
|
|
|
|
Currently supported modes are: `disabled` and `required`
|
|
|
|
#### Users
|
|
|
|
If either the cert or key is not set, the server will use insecure transport.
|
|
|
|
`MF_USERS_SERVER_CERT` the path to server certificate in pem format.
|
|
|
|
`MF_USERS_SERVER_KEY` the path to the server key in pem format.
|
|
|
|
#### Things
|
|
|
|
If either the cert or key is not set, the server will use insecure transport.
|
|
|
|
`MF_THINGS_SERVER_CERT` the path to server certificate in pem format.
|
|
|
|
`MF_THINGS_SERVER_KEY` the path to the server key in pem format.
|
|
|
|
### Client configuration
|
|
|
|
If you wish to secure the gRPC connection to `things` and `users` services you must define the CAs that you trust. This does not support mutual certificate authentication.
|
|
|
|
#### HTTP Adapter
|
|
|
|
`MF_HTTP_ADAPTER_CA_CERTS` - the path to a file that contains the CAs in PEM format. If not set, the default connection will be insecure. If it fails to read the file, the adapter will fail to start up.
|
|
|
|
#### Things
|
|
|
|
`MF_THINGS_CA_CERTS` - the path to a file that contains the CAs in PEM format. If not set, the default connection will be insecure. If it fails to read the file, the service will fail to start up.
|