-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mosquitto Example #76
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
# User authentication in Mosquitto using SVIDs with DNS names | ||
|
||
This is an example of how **spiffe-helper** can be used to authenticate users to | ||
a **Mosquitto** broker using x509 SVIDs. | ||
|
||
Mosquitto can be configured to use the CN of a certificate as a username to | ||
authenticate the client. This is done by setting the following two options in | ||
the `mosquitto.conf` file: | ||
``` | ||
require_certificate true | ||
use_identity_as_username true | ||
``` | ||
|
||
## Guide | ||
|
||
### Prerequisites | ||
|
||
We will do this test using three virtual machines (VMs) running Ubuntu 22.04 on | ||
the same virtual network. The setup will be as follows: | ||
| hostname | IP | Description | | ||
| --- | --- | --- | | ||
| node0 | 10.211.55.2 | SPIRE server | | ||
| node1 | 10.211.55.20 | Mosquitto broker | | ||
| node2 | 10.211.55.21 | Mosquitto client | | ||
|
||
### 1. Configure and Run Spire Server on Node0 | ||
|
||
Download or build the latest version of SPIRE and extract it to `/opt/spire` on | ||
`node0`. Edit the `conf/server/server.conf` file to set the `bind_address` to | ||
`10.211.55.2` and the `trust_domain` to `example.org`. The rest of the | ||
configuration can be left as is. | ||
|
||
After editing the configuration file the `server` config should look similar to | ||
this: | ||
``` | ||
server { | ||
bind_address = "10.211.55.2" | ||
bind_port = "8081" | ||
socket_path = "/tmp/spire-server/private/api.sock" | ||
trust_domain = "example.org" | ||
data_dir = "./.data" | ||
log_level = "DEBUG" | ||
} | ||
``` | ||
|
||
Start the server with: | ||
```bash | ||
cd /opt/spire | ||
./bin/spire-server run -config conf/server/server.conf | ||
``` | ||
|
||
*NOTE:* Make sure `/opt/spire` directory has the right permissions for the | ||
server to write to it. | ||
|
||
### 2. Configure and Run Spire Agent on Node1 & Node2 | ||
|
||
Just like with the server, install Spire under `/opt/spire` and edit the agent | ||
configuration file to set the `bind_address` to the IP of the spire server (i.e. | ||
node0) and the `trust_domain` to `example.org`. The rest of the configuration | ||
can be left as is. | ||
|
||
Before we can start the agents up on `node1` and `node2` we need to register | ||
them with the server. | ||
|
||
### 3. Register Node1 Agent | ||
|
||
On `node0` run the following command: | ||
```bash | ||
./bin/spire-server token generate -spiffeID spiffe://example.org/node1 | ||
``` | ||
This will output a join token. Copy it and run the following command on `node1`: | ||
```bash | ||
./bin/spire-agent run -config ./conf/agent/agent.conf -joinToken ${JOIN_TOKEN} | ||
``` | ||
Make sure to replace `${JOIN_TOKEN}` with the token you got from the server. | ||
|
||
### 4. Register Node2 Agent | ||
|
||
On `node0` run the following command: | ||
```bash | ||
./bin/spire-server token generate -spiffeID spiffe://example.org/node2 | ||
``` | ||
This will output a join token. Copy it and run the following command on `node2`: | ||
```bash | ||
./bin/spire-agent run -config ./conf/agent/agent.conf -joinToken ${JOIN_TOKEN} | ||
``` | ||
Make sure to replace `${JOIN_TOKEN}` with the token you got from the server. | ||
|
||
### 5. Install Mosquitto Broker on Node1 | ||
|
||
Install latest [Mosquitto](https://mosquitto.org/) broker on `node1`. You can | ||
best use the package that comes with the distribution. On Ubuntu this is done by | ||
running: | ||
```bash | ||
sudo apt install mosquitto | ||
``` | ||
|
||
Once installed, make sure to stop it as we will be running it with the | ||
spiffe-helper instead: | ||
```bash | ||
sudo systemctl stop mosquitto | ||
``` | ||
|
||
### 6. Register Mosquitto Broker Workload with Spire Server | ||
|
||
On `node0` run the following command: | ||
```bash | ||
cd /opt/spire | ||
./bin/spire-server entry create \ | ||
-spiffeID spiffe://example.org/mosquitto-server \ | ||
-parentID spiffe://example.org/node1 \ | ||
-selector unix:user:mosquitto \ | ||
-ttl 600 \ | ||
-dns node1 | ||
``` | ||
|
||
For `-dns` we use the hostname that the client will use to connect to the | ||
broker. In this case we are using the hostname of `node1`. We also use the | ||
unix attestation selector with user `mosquitto` to identify the workload. | ||
|
||
For testing purposes we also set the `-ttl` to 10 minutes. | ||
|
||
### 6. Configure Spiffe Helper and Run Mosquitto Broker on Node1 | ||
|
||
Download and build the spiffe helper on `node1`. Note that we will be running | ||
the spiffe helper with user `mosquitto` so make sure that the location where | ||
you install the spiffe-helper binary has the right permissions for reading the | ||
configuration files: | ||
```bash | ||
chmod -R o+r ./examples/mosquitto | ||
``` | ||
|
||
Now start up the mosquitto broker using the spiffe helper: | ||
```bash | ||
sudo mkdir -p /opt/spire/certs/mosquitto | ||
sudo chown mosquitto:mosquitto /opt/spire/certs/mosquitto | ||
sudo -u mosquitto ./bin/spiffe-helper -config ./examples/mosquitto/helper.conf | ||
``` | ||
|
||
### 7. Install Mosquitto Client on Node2 | ||
|
||
Make sure to install the mosquitto client tools on node2. On Ubuntu this is done | ||
with: | ||
```bash | ||
sudo apt install mosquitto-clients | ||
``` | ||
|
||
We will be running the client under a dedicated user called `mosquitto-client`. | ||
Create the user with: | ||
```bash | ||
sudo useradd mosquitto-client | ||
``` | ||
|
||
### 7. Register the Mosquitto Client Workload with Spire Server | ||
|
||
On `node0` run the following command: | ||
```bash | ||
cd /opt/spire | ||
./bin/spire-server entry create \ | ||
-spiffeID spiffe://example.org/mosquitto-client \ | ||
-parentID spiffe://example.org/node2 \ | ||
-selector unix:user:mosquitto-client \ | ||
-ttl 600 \ | ||
-dns jdoe | ||
``` | ||
|
||
For `-dns` we use the username that the client will use to connect to the | ||
broker. In this case we are using the username `jdoe`. We also use the unix | ||
attestation selector with user `mosquitto-client` to identify the workload. | ||
|
||
For testing purposes we also set the `-ttl` to 10 minutes. | ||
|
||
### 8. Run the Mosquitto Client | ||
|
||
First create a directory for the client certificates: | ||
```bash | ||
mkdir -p /tmp/mosquitto/svids | ||
sudo chown mosquitto-client:mosquitto-client /tmp/mosquitto/svids | ||
``` | ||
|
||
Copy over the script [./connect.sh] to `node2` and run it with: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the connect.sh you just reference the current directory but above you use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point! I will double check the references to the files. |
||
```bash | ||
sudo -u mosquitto-client ./examples/mosquitto/connect.sh | ||
``` | ||
|
||
The script will connect to the broker and subscribe to the topic `test`. To send | ||
a message simply type something and hit enter. | ||
|
||
If you check the script, it is important to see that we use the hostname as | ||
we set it in the `-dns` flag when registering the client workload. If you don't | ||
do this (e.g. use the IP address instead) the connection will fail with: | ||
``` | ||
Error: host name verification failed. | ||
OpenSSL Error[0]: error:0A000086:SSL routines::certificate verify failed | ||
Error: A TLS error occurred. | ||
``` | ||
|
||
To view the published messages on the broker, you can go to `node1` and run: | ||
```bash | ||
mosquitto_sub -t test/# | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#!/usr/bin/env bash | ||
|
||
# Directory to store the certificate, key and bundle fetched from the Workload API | ||
declare -r SVIDS_DIR=/tmp/mosquitto/svids | ||
|
||
# Fetch SVIDs from SPIRE agent | ||
/opt/spire/spire-agent api fetch -write ${SVIDS_DIR} | ||
|
||
# Connect to mosquitto broker using the certificates fetched | ||
mosquitto_pub --cafile $SVIDS_DIR/bundle.0.pem \ | ||
--cert $SVIDS_DIR/svid.0.pem \ | ||
--key $SVIDS_DIR/svid.0.key \ | ||
--tls-version tlsv1.3 \ | ||
--host node1 \ | ||
--port 8883 \ | ||
--username jdoe \ | ||
--id jdoe \ | ||
-t test/hello \ | ||
--stdin-line \ | ||
-d |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# SPIRE agent unix socket path | ||
agentAddress = "/tmp/spire-agent/public/api.sock" | ||
|
||
# psql binary path | ||
cmd = "/usr/sbin/mosquitto" | ||
|
||
# Query for configuration reloading | ||
cmdArgs = "-c ./examples/mosquitto/mosquitto.conf" | ||
|
||
# Directory to store certificates (must match with the ssl setings in postgresql.conf) | ||
certDir = "/opt/spire/certs/mosquitto" | ||
|
||
# No renew signal is used in this example | ||
renewSignal = "SIGHUP" | ||
|
||
# Certificate, key and bundle names must match those configured in mosquitto.conf | ||
svidFileName = "svid.pem" | ||
svidKeyFileName = "svid.key" | ||
svidBundleFileName = "svid_bundle.pem" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
sys_interval 10 | ||
user mosquitto | ||
log_dest stdout | ||
log_type all | ||
connection_messages true | ||
log_timestamp true | ||
per_listener_settings true | ||
|
||
listener 1883 localhost | ||
allow_anonymous true | ||
|
||
listener 8883 | ||
certfile /opt/spire/certs/mosquitto/svid.pem | ||
cafile /opt/spire/certs/mosquitto/svid_bundle.pem | ||
keyfile /opt/spire/certs/mosquitto/svid.key | ||
tls_version tlsv1.3 | ||
require_certificate true | ||
use_identity_as_username true | ||
allow_anonymous false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the ttl is not strictly necessary i would leave it out and let it be default value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is similar to the PostgreSQL sample that also adjusts the ttl to show the certificate expiry. I think it is a nice touch to clearly show the benefit of using spiffe. Maybe I should make it clearer that the ttl is purely for testing and in production you would want to keep it the default or some larger sensible value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, i think its fine to leave.