Skip to content
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

Merged
merged 4 commits into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions examples/mosquitto/README.md
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 \
Copy link
Collaborator

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.

Copy link
Contributor Author

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?

Copy link
Collaborator

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.

-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:
Copy link
Collaborator

Choose a reason for hiding this comment

The 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 ./examples/moquitto/... Just want to make sure we are consistent with the what directory we are running these commands from

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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/#
```
20 changes: 20 additions & 0 deletions examples/mosquitto/connect.sh
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
19 changes: 19 additions & 0 deletions examples/mosquitto/helper.conf
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"
19 changes: 19 additions & 0 deletions examples/mosquitto/mosquitto.conf
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
Loading