Skip to content

Instantly share code, notes, and snippets.

@efrecon
Last active November 14, 2018 10:28
Show Gist options
  • Save efrecon/d1181fc93f63e54ede2a94ae176a6c29 to your computer and use it in GitHub Desktop.
Save efrecon/d1181fc93f63e54ede2a94ae176a6c29 to your computer and use it in GitHub Desktop.
Easy InfluxDB initialisation

UNIX-Style InfluxDB Initialisation

Introduction

This script aims at easily initialising access rights for users in InfluxDB databases in a UNIX:y way. The script will read a configuration file where fields are separated by the colon (:) sign (e.g. analogical to /etc/password). The file is able to express and map rwx-style permissions onto GRANT-style privileges with the database, thus simplifying initialisation of the authorisations, but also use of users created in other parts of a cloud system.

Options

The script itself takes a few internal options, any other dash-led option will be passed further to influx at each execution, thus making it easy to pass further authentication- or connection- oriented options. A double-dash should mark the end of the option list and all arguments after the double-dash will be path to access files, which will be used for user creation and access rights definitions.

The options specific to the script are the following:

  • -i or --influx to give the exact path to the influx binary.
  • --verbose to turn on verbosity in the script.

Provided a file called access.cfg in the format described below, the following command would create users and give them access rights as of the file at a remote PostgreSQL instance.

influx-init.sh --verbose -- access.cfg

Configuration

Syntax

The syntax of the access rights files is as described below. Empty lines will be ignored. Lines starting with a hash-sign (#) will be ignored. Files MUST end with an empty line, otherwise the last line will not be parsed. Apart from empty or commenting lines, lines should contain 4 fields separated by colon-signs. These are described in order below:

  1. List of databases, separated by commas, that the user will have access to. The script will attempt to create the databases if they do not already exist.

  2. Name of user to be created

  3. Password for user. When the password is empty, a random password of 16 characters length will be generated for the user and printed out.

  4. Access specification to the databases. These specifications are a combination, in any order, of the letters r, w and x where r stands for read, w for writes and x for admin rights. These are mapped onto InfluxDB READ or WRITE GRANT clauses.

Example

The following example content for an access specification file would arrange for the creation of an administrator with access to all databases and the creation of a database called db and a user called user with read and write access.

:admin:FyKzmSYnygbBMrRzcf4drcWC:rwx
db:user:gZU6JE5A7xz3mVFubNJn4LZ2:rw
#!/bin/sh
######
#
# This script can be used to initialise databases and users in an Influx DB
# installation. Most dash-led options are passed further to the influx
# command-line tool. All file paths that follows the -- separator contain
# user/db configurations that will be understood by this script. In these
# configuration files, lines starting with a hash-sign and empty lines are
# ignored. Otherwise, lines should contain a number of colon separated fields,
# which are understood as follows:
#
# * colon separated list of databases accessible by user, empty for none
# * name of user
# * password, empty for auto-generated
# * combination of rwx (read, write, x is for all privileges, i.e. admin rights)
#
# Note that leading and trailing whitespaces are removed from user and database
# names automatically. Autogenerated passwords will be printed out on the
# standard error.
#
# When called without authorisation details, this tool will automatically pick
# the first administrator that it discovers to perform all further operations on
# users and databases. This ensures that, when an administrator is the first
# user declared and InfluxDB is configured to force authorisation, all
# operations will properly succeed.
#
# It is possible to specify a specific binary (full path, different command)
# with the -i (or --influx) option. Specifying --verbose will allow to print
# out internal decisions, at the expense of printing out sensitive passwords.
#
######
# Eat all options so we can pass them to influx when calling it, all remaining
# stuff should be file names.
INFLUX="influx"
OPTS=""
VERBOSE=0
while [ $# -gt 0 ]; do
case "$1" in
--)
# End of options, everything that follows will be filenames
shift
break
;;
-i|--influx)
# Capture separate path to binary, just in case
INFLUX="$2"
shift 2
;;
--verbose)
VERBOSE=1
shift
;;
*)
# All other options are supposed to take an argument (which isn't
# entirely true), store them and arrange to capture them for further
# invokation of influx.
OPTS="${OPTS} $1 $2"
shift 2
;;
esac
done
verbose() {
if [ "$VERBOSE" = "1" ]; then printf "%s\n" "$*" 1>&2; fi
}
warn() {
printf "%s\n" "$*" 1>&2
}
callinflux() {
verbose "InfluxQL (${OPTS}): $1"
${INFLUX} ${OPTS} -execute "$1"
}
for fname in "$@"; do
DBS=""
# See http://mywiki.wooledge.org/BashFAQ/024 for the loop...
while IFS= read -r line; do
line=$(echo "${line}" | sed '/^[[:space:]]*$/d' | sed '/^[[:space:]]*#/d')
if [ -n "${line}" ]; then
dbs=$(echo -e "${line}"|cut -d: -f1)
user=$(echo -e "${line}"|cut -d: -f2)
pass=$(echo -e "${line}"|cut -d: -f3)
access=$(echo -e "${line}"|cut -d: -f4)
# Create, amend the user and take care of admin privieges early.
user=$(echo -e "${user}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
if [ -z "${pass}" ]; then
pass=$(strings /dev/urandom | grep -o '[[:alnum:]]' | head -n 16 | tr -d '\n')
warn "Generated password '$pass' for $user"
fi
if [ -n "${user}" ]; then
# Create the user if it does not already exist.
already=$(callinflux "SHOW USERS;" | tail -n +3 | grep ${user})
if [ -z "${already}" ]; then
admin=$(echo "${access}" | grep x)
# Check privileges (represented by an x)
if [ -z "${admin}" ]; then
verbose "Creating user ${user}"
callinflux "CREATE USER \"${user}\" WITH PASSWORD '${pass}';"
else
verbose "Creating administrator ${user}"
callinflux "CREATE USER \"${user}\" WITH PASSWORD '${pass}' WITH ALL PRIVILEGES;"
hasauth=$(echo -e "${OPTS}"|grep '\-username')
if [ -z "${hasauth}" ]; then
verbose "Automatically using ${user} as an administrator for all further calls!"
OPTS="${OPTS} -username ${user} -password ${pass}"
fi
fi
else
verbose "Amending password for ${user}"
callinflux "SET PASSWORD FOR \"${user}\" = '${pass}';"
admin=$(echo "${access}" | grep x)
already=$(callinflux "SHOW USERS;" | tail -n +3 | grep ${user} | grep true)
if [ -z "${admin}" -a -n "${already}" ]; then
verbose "Revoking privileges for ${user}"
callinflux "REVOKE ALL PRIVILEGES FROM \"${user}\";"
fi
if [ -n "${admin}" -a -z "${already}" ]; then
verbose "Granting privileges for ${user}"
callinflux "GRANT ALL PRIVILEGES TO \"${user}\";"
fi
fi
fi
# Parse the list of databases, separated by comas
for db in $(echo "${dbs}" | tr "," "\n"); do
db=$(echo -e "${db}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
if [ -n "${db}" ]; then
# Create the database if it does not already exist.
already=$(callinflux "SHOW DATABASES;" | tail -n +3 | grep ${db})
if [ -z "${already}" ]; then
verbose "Creating database ${db}"
callinflux "CREATE DATABASE ${db};"
else
verbose "Database ${db} already exists"
fi
# Keep record of databases specified in file
already=$(echo ${DBS}|grep ${db})
if [ -z "${already}" ]; then
DBS="${DBS} ${db}"
fi
# Grant R/W privileges to user.
read=$(echo "${access}" | grep r)
write=$(echo "${access}" | grep w)
if [ -n "${read}" ] && [ -n "${write}" ]; then
verbose "Granting all access to ${db} for ${user}"
callinflux "GRANT ALL ON \"${db}\" TO \"${user}\";"
else
if [ -n "${read}" ]; then
verbose "Granting read access to ${db} for ${user}"
callinflux "GRANT READ ON \"${db}\" TO \"${user}\";"
fi
if [ -n "${write}" ]; then
verbose "Granting write access to ${db} for ${user}"
callinflux "GRANT WRITE ON \"${db}\" TO \"${user}\";"
fi
fi
fi
done
fi
done < ${fname}
done
Copyright (c) <2018>, <Emmanuel Frécon>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment