Skip to content

Instantly share code, notes, and snippets.

@Paraphraser
Last active December 24, 2022 02:45
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Paraphraser/9f3aa21fddd5d4e8141a7ab03ffb4dd7 to your computer and use it in GitHub Desktop.
Save Paraphraser/9f3aa21fddd5d4e8141a7ab03ffb4dd7 to your computer and use it in GitHub Desktop.
Enabling authentication in InfluxDB for SensorsIot/IOTstack

Tutorial: Enabling authentication in InfluxDB

Assumptions:

  • you are running SensorsIot/IOTstack with InfluxDB as one of the containers
  • you want to enable authentication for your InfluxDB databases.

Note: This tutorial is specific to SensorsIot/IOTstack.

Definition:

  • the environment means environment variables in either:
    • ~/IOTstack/services/influxdb/influxdb.env; or
    • ~/IOTstack/docker-compose.yml

Useful alias:

I define the following alias in my .profile and I use it throughout this tutorial:

alias influx='docker exec -it influxdb influx -precision=rfc3339'

Having that alias installed lets me type influx, press return, and get straight into the influx CLI.

Typing exit or pressing Control+D terminates the influx CLI and returns to the normal user shell.

The alias is a shortcut for the following commands:

$ docker exec -it influxdb bash
# influx -precision=rfc3339

The -precision=rfc3339 argument tells the influx CLI that I would prefer to see dates in human-readable form. If you omit that argument then you will see nanoseconds since 1970-01-01 which, to me, is as close to utterly useless as makes no difference.

Warning:

This tutorial also assumes that you do not have any existing databases so it starts by creating two. One database will be provided with access controls but the other will be left alone so that the behaviour can be compared.

However, you need to understand that enabling authentication in InfluxDB is all-or-nothing. If you have any existing InfluxDB databases, you will need to:

  • define access rights for all of your databases; and
  • provide credentials to processes like Node-Red and Grafana that access your databases.

If you do not do this, your existing Node-Red flows, Grafana dashboards and other processes that write to or query your databases will stop working as soon as you activate authentication in Step 4 below.

Step 1 – create two test databases

Create two databases named "mydatabase1" and "mydatabase2":

$ influx
> CREATE DATABASE "mydatabase1"
> CREATE DATABASE "mydatabase2"

Typing influx didn't work? See useful alias above.

Step 2 – define users

Define an administrative user. In this example, that user is "dba" (database administrator) with the password "supremo":

> CREATE USER "dba" WITH PASSWORD 'supremo' WITH ALL PRIVILEGES
  • Key point: the mixture of "double" and 'single' quotes is intentional and required.

Define some garden-variety users:

> CREATE USER "nodered_user" WITH PASSWORD 'nodered_user_pw'
> CREATE USER "grafana_user" WITH PASSWORD 'grafana_user_pw'

You can define any usernames you like. The reason for using "nodered_" and "grafana_" prefixes in these examples is because those are common candidates in an IOTstack environment. The reason for the "_user" suffixes is to make it clear that a username is separate and distinct from a container name.

Step 3 – assign access rights

The user "dba" already has access to everything but, for all other users, you need to state which database(s) the user can access, and whether that access is:

  • READ (aka read-only)
  • WRITE (aka write-only)
  • ALL (implies both READ and WRITE)
> GRANT WRITE ON "mydatabase1" TO "nodered_user"
> GRANT READ ON "mydatabase1" TO "grafana_user"
  • Key point: you CREATE a user once but you need to GRANT access to every database to which that user needs access.

Once you have finished defining users and assigning access rights, drop out of the influx CLI:

> exit
$

Step 4 – activate authentication

Make sure you read the warning above, then edit the environment to add this key:

INFLUXDB_HTTP_AUTH_ENABLED=true

Put the change into effect by "upping" the container:

$ cd ~/IOTstack
$ docker-compose up -d influxdb

Recreating influxdb ... done

The up causes docker-compose to notice that the environment has changed, and to rebuild the container with the new settings.

  • Note: You should always wait for 30 seconds after a rebuild for InfluxDB to become available. Any time you see a message like this:

     Failed to connect to http://localhost:8086: Get http://localhost:8086/ping: dial tcp 127.0.0.1:8086: connect: connection refused
     Please check your connection settings and ensure 'influxd' is running.
    

    it simply means that you did not wait long enough. Be patient!

Step 5 – experiments

Start the influx CLI:

$ influx

Unless you have also set up the INFLUX_USERNAME and INFLUX_PASSWORD environment variables (described later under Authentication Hints), your session will not be authenticated as any user so you will not be able to access either database:

> USE mydatabase1
ERR: unable to parse authentication credentials
DB does not exist!
> USE mydatabase2
ERR: unable to parse authentication credentials
DB does not exist!
  • Key point: This is what will happen to any of your pre-existing databases if you enable authentication without a lot of care. You must define users and access rights for all of your databases, and you must provide those credentials to the relevant processes like Node-Red and Grafana.

Authenticate as "nodered_user" and try again:

> AUTH
username: nodered_user
password: 
> USE mydatabase1
Using database mydatabase1
> USE mydatabase2
ERR: Database mydatabase2 doesn't exist. Run SHOW DATABASES for a list of existing databases.
DB does not exist!

The "nodered_user" can access "mydatabase1" but not "mydatabase2", albeit with slightly different error messages. You will get the same behaviour for the "grafana_user" (try it).

Authenticate as the "dba" and try again:

> AUTH
username: dba
password: 
> USE mydatabase1
Using database mydatabase1
> USE mydatabase2
Using database mydatabase2

The super-user can access both databases.

To get a list of users:

> SHOW USERS
user         admin
----         -----
dba          true
nodered_user false
grafana_user false
  • Key point: you must be authenticated as the "dba" to run SHOW USERS.

To find out what privileges a user has on a database:

> SHOW GRANTS FOR "nodered_user"
database    privilege
--------    ---------
mydatabase1 WRITE
  • Key point: you must be authenticated as the "dba" to run SHOW GRANTS.

To test grants, you can try things like this:

AUTH
username: nodered_user
password: 
> USE "mydatabase1"
Using database mydatabase1
> INSERT example somefield=123

"nodered_user" has WRITE access to "mydatabase1".

> SELECT * FROM example
ERR: error authorizing query: nodered_user not authorized to execute statement 'SELECT * FROM example', requires READ on mydatabase1

"nodered_user" does not have READ access to "mydatabase1".

Authenticate as "grafana_user" and try the query again:

> AUTH
username: grafana_user
password: 
> SELECT * FROM example
name: example
time                         somefield
----                         ---------
2020-09-19T01:41:09.6390883Z 123

"grafana_user" has READ access to "mydatabase1". Try an insertion as "grafana_user":

> INSERT example somefield=456
ERR: {"error":"\"grafana_user\" user is not authorized to write to database \"mydatabase1\""}

"grafana_user" does not have WRITE access to "mydatabase1".

Change the privileges for "nodered_user" to ALL then try both an insertion and a query. Note that changing privileges requires first authenticating as "dba":

> AUTH
username: dba
password: 
> GRANT ALL ON "mydatabase1" TO "nodered_user"
> AUTH
username: nodered_user
password: 
> INSERT example somefield=456
> SELECT * FROM example
name: example
time                          somefield
----                          ---------
2020-09-19T01:41:09.6390883Z  123
2020-09-19T01:42:36.85766382Z 456

"nodered_user" has both READ and WRITE access to "mydatabase1".

Notes

  1. Some inferences to draw from the above:

    • user definitions are global rather than per-database. Grants are what tie users to particular databases.
    • setting INFLUXDB_HTTP_AUTH_ENABLED=true is how authentication is activated and enforced. If it is false, all enforcement goes away (a handy thing to know if you lose passwords or need to recover from a mess).
    • as the "HTTP" in INFLUXDB_HTTP_AUTH_ENABLED suggests, it applies to access via HTTP. This includes the influx CLI and processes like Node-Red and Grafana.
  2. Always keep in mind that the InfluxDB log is your friend:

    $ docker logs influxdb
    

Authentication Hints

After you enable authentication, there are a couple of ways of speeding-up your daily activities. You can pass the dba username and password on the end of the influx alias:

$ influx -database mydatabase1 -username dba -password supremo

but this is probably sub-optimal because of the temptation to hard-code your dba password into scripts. An alternative is to add these lines to the environment:

INFLUX_USERNAME=dba
INFLUX_PASSWORD=supremo

and then "up" the container as explained above to apply the changes.

Misunderstandings about the scope and purpose of INFLUX_USERNAME and INFLUX_PASSWORD are quite common so make sure you realise that the variables:

  • do not "set" any username or password within InfluxDB
  • only apply to starting the influx CLI – they are just synonyms for the -username and -password parameters on the influx CLI command
  • are not some kind of general-access credentials that apply to everything.

In other words, with INFLUX_USERNAME and INFLUX_PASSWORD added to the environment, the following two commands are identical:

$ influx -database mydatabase1 -username dba -password supremo
$ influx -database mydatabase1

The INFLUX_USERNAME and INFLUX_PASSWORD variables also work if you start a shell into the InfluxDB container and then invoke the influx CLI from there:

$ docker exec -it influxdb bash
# influx
>

Cleaning up

To undo the steps in this tutorial, first set INFLUXDB_HTTP_AUTH_ENABLED=false and then "up" influxdb. Then:

$ influx
> DROP USER "dba"
> DROP USER "nodered_user"
> DROP USER "grafana_user"
> DROP DATABASE "mydatabase1"
> DROP DATABASE "mydatabase2"
> exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment