Securing your Docker deployment

Prerequisites

Install required security tools:

  • NSC
  • mir tools install

Have a mir deployment ready to be used:

Setup

Mir Security CLI wraps NSC commands with a set of preset to make securing Mir ecoystem easier. It offers a set of basic commands to manipulate credentials. Moreover, it offers premade scope for the three types of users in Mir:

  • Modules (server components)
  • Clients (access CLI and other frontend)
  • Devices (connect devices)

The CLI uses the current context to help manage which server to target. Use mir config editto add a new context with server name and url:

# If using local setup
- name: local
  target: nats://localhost:4222
  grafana: localhost:3000

You can overwrite the Operator, Account and URL arguments using flags. This requires more familiarity with the NSC tool. Moreover, you can use flag --no-exec on each command to see NSC commands.

Step 1: Initialize Mir Operator

Create a new NATS operator for your deployment:

mir tools security init

This creates:

  • Operator signing keys
  • Default account named Mir
  • System account for internal operations

Step 2: Configure NATS Server

Generate Resolver Configuration used to launch Nats Server:

# Generate NATS resolver configuration
mir tools security generate-resolver -p ./resolver.conf

Update NATS Configuration

Edit ./mir-compose/natsio/config.conf and uncomment or add this line include resolver.conf.

Start server docker compose up.

The server is now running with authorization. To validate, run mir device ls and you should see nats: Authorization Violation. Similar for the logs of Mir server.

Moreover, if you run mir tools sec list accounts you should see two accounts: SYS and mir.

Step 3: Create Module Credentials

Let's get the Mir server up & running by generating credentials taylored for it.

# Create new user of type Module
mir tools security add module mir_srv
# Sync user with server
mir tools security push
# Create credentials file for it
mir tools security generate-creds mir_srv -p ./mir_srv.creds

Now let's launch the server with the credentials file. Edit ./mir-compose/mir/local-config.yaml and set the path of the credentials files under mir.credentials. Edit ./mir-compose/mir/compose.yaml to mount the file.

# Restart server
docker compose down
docker compose up

You should see a successfull connection without any errors.

Step 4: Create Client Credentials

Let's create a Client credentials to have full access to the system.

# Create new user of type Client
# use -h to see options
mir tools security add client ops --swarm
# Sync user with server
mir tools security push
# Generate credentials
mir tools security generate-creds ops -p ./ops.creds

Edit CLI configuration file to add the credentials mir tools config edit:

- name: local
  target: nats://localhost:4222
  grafana: localhost:3000
  credentials: <path>/ops.creds

If you run mir dev ls, you should now see the list of devices.

Step 5: Create Device Credentials

The last type of users is of Device type. Refer to Integrating Mir to create a device.

# Create new user of type Device
# add --wildcard to have the same credentials for all devices.
# Else it is bound to this device id.
mir tools security add device dev1
# Sync user with server
mir tools security push
# Generate credentials
mir tools security generate-creds dev1 -p ./dev1.creds

There are a few options to load the credentials file with the DeviceSDK.

# Using Builder with fix path
device := mir.NewDevice().
    WithTarget("nats://nats.example.com:4222").
    WithCredentials("/<path>/dev1.creds").
    WithDeviceId("dev1").
    Build()
# Using Builder with default lookup
#   ./device.creds
#   ~/.config/mir/device.creds
#   /etc/mir/device.creds
device := mir.NewDevice().
    WithTarget("nats://nats.example.com:4222").
    DefaultUserCredentialsFile().
    Build()

It is also possible to load the credentials from the config file:

# Using Builder with config file
device := mir.NewDevice().
    WithTarget("nats://nats.example.com:4222").
    DefaultConfigFile().
    Build()
mir:
  credentials: "<path>/dev1.creds"
  device:
    id: "dev1"

Run the device and no auth errors should be displayed. Now run mir dev ls and you should see:

➜ mir dev ls
NAMESPACE/NAME                                DEVICE_ID        STATUS     LAST_HEARTHBEAT      LAST_SCHEMA_FETCH    LABELS
default/dev1                                  dev1             online     2025-09-18 16:16:27  2025-09-18 16:15:18

Other commands

# View current operator configuration
mir tools security env

# Sync with remote credential store
mir tools security push
mir tools security pull

# List users
mir tools security list [operators|accounts|users]

Summary

Mir's integration with NATS security provides:

  • Strong authentication using JWT and nkeys
  • Flexible authorization with subject-based permissions
  • Simple management through the Mir CLI
  • Production-ready security model for IoT deployments

For additional security features, see: