Bash · Linux · VPS · env vars

Setting Environment Variables - in a VPS

I’ve written a very simple twitter bot (you can find the source at github.com/shaneHowearth/proverbs), that takes some content from a local database, logs into twitter and posts that content.

Running this bot on a VPS presents challenges, the authentication credentials that the bot requires are not something you can leave lying around. You certainly should not include them with the source code of the application when that source code is hosted publicly.

The Twelve Factor App methodology provides for a way for the application to receive the credentials it needs to complete its tasks, via environment variables.

The user that you typically use on your VPS will get used a lot for miscellaneous activities, like moving files around, administrating services, or even as an IRC jump host. It’s not a great candidate for knowing sensitive information, for a few reasons. The most prominent being, its high usage means that there’s a strong possibility of a mistake being made, eg. a copy/paste error when using IRC.

Having root own the file that holds the credentials seems ideal, but then the bot is being run as root, which is definitely not good (any mistake made by the bot could have catastrophic consequences).

The requirements have become, run the application as a non-root user, but store the credentials in a file that only root can read and/or write.

Working toward that goal, the first task is to create a system account

useradd -r bot

This excerpt from the man page for useradd explains the advantages of the system account

     -r, --system
           Create a system account.

           System users will be created with no aging information in
           /etc/shadow, and their numeric identifiers are chosen in the
           SYS_UID_MIN-SYS_UID_MAX range, defined in /etc/login.defs, instead
           of UID_MIN-UID_MAX (and their GID counterparts for the creation of
           groups).

           Note that useradd will not create a home directory for such a user,
           regardless of the default setting in /etc/login.defs (CREATE_HOME).
           You have to specify the -m options if you want a home directory for
           a system account to be created.

Having created a user dedicated to the task of running the bot, the next task is to inform that user of the authentication information when the bot is run (and, preferably, only whilst the bot is being run).

As root the su command will switch to the nominated user, the -c flag means that the following string is a command to be run by that user. The magic part is that running this inside a script means that the environment variables set inside the script are available to the user temporarily (for the life of the script, and only in this shell instance).

So create a script that root will execute, that contains the authentication information, and the su call - an example is below, and you will forgive me if I redact the actual auth information passed to the bot.

Note that the command being executed is inside quotes, this is to allow the type flag to be passed to the application, rather than have su try to use it as a flag for itself.

Bot.sh

#/bin/bash

# Run this script - setting env vars, then running the twitter bot as bot
export TWITTER_API_KEY="REDACTED"
export TWITTER_API_SECRET="REDACTED"
export TWITTER_BEARER_TOKEN="REDACTED%REDACTED%REDACTED"
export TWITTER_ACCESS_TOKEN="REDACTED-REDACTED"
export TWITTER_ACCESS_TOKEN_SECRET="REDACTED"
export POSTGRES_HOST="localhost"
export POSTGRES_DATABASE="user=bot dbname=REDACTED sslmode=disable password=REDACTED"
export POSTGRES_USER="bot"
export POSTGRES_PASSWORD="REDACTED"

su bot -c '/usr/local/bin/proverbs -type=proverb'

This setup can then be run from root’s cron. As root run the following command

crontab -e

And run the script every day at (say) 4am local time

# m h  dom mon dow   command
0 4 * * * /root/Bot.sh

And, done. The application is being run by user bot who is passed the credentials it requires for authentication to various services via environment variables that only root knows.

Published:
comments powered by Disqus