Augeas-augtool: Manipulate configuration files programmatically
Background
Part of my tasks at work includes ensuring configurations aligns with organisation compliance policies. I faced some difficulties in attempting to programmatically update the sshd_config file to configure our remote SSH access settings. I was required to update specific settings such as:
- Denying specific users from being able to have remote access via SSH (
/etc/ssh/sshd_config
) - Restricting su access (
/etc/sudoers
)
Blockers
I typically tries to avoid installing additional dependencies and use native commands to perform the automation steps through shell-scripting.
While I have an account with elevated privileges (but not root), I seemingly faced some permission issues despite using sudo
. Hence, I could not use conventional means such as echo
or sed
to add and/or update the existing values.
Another issue I faced was configuration files may already have some settings, and it may not be as easer to try to search and replace values without using some complex regex to retrieve the values.
Why Augeas-augtool
I stumbled upon the augeas-augtool when searching for alternatives for automated configuration means. Augeas is a configuration editing tool by parising the configuration files and transform them into a tree.
In PythonLearner's answer in this StackOverflow post, I could consider to use
- Configuration Management Tools such as Puppet, Chef and Cfengine
- Augeas
As I wanted to avoid the hassle of setting up for the configuration management tools for this small use case, I decided to go with Augeas as it has a command line tool augtool
. Furthermore, within the same StackOverflow post, Cristian Ciupitu's answer provided some insights on how the CLI tool could be used.
Setup
Environment
I am running a Ubuntu instance on AWS on ubuntu
user for this walkthrough.
Just in case you do not have access to such file, you can create a local file using this generic default sshd_config file here.๐ฌ
Installation
To install augtool on Ubuntu, run the following commands
# Get the latest package information
sudo apt-get update -y
# Install Augeas
sudo apt-get install -y augeas-tools
Deepdive into augtool's features
Modes of augtool
- Non-interactive: This runs augtool as command and you pass augtool specific parameters to parse. You can also use augtool in combination with other native commands such as
grep
. However, it can be difficult to debug as nothing is printed when there is error in the command. - Interactive: This is useful for testing and verifying the nodes to retrieve and update. You can enter interactive mode by entering
augtool
command in the terminal. Remember to run thesave
command if you want your changes to be saved!. To exit the augtool CLI, enterquit
. - Via command file: The
-f
option in augtool will read commands from a file. You can test and consolidate the commands executed in interactive mode into an external file and used as part of your automation process. This is especially useful if you would like to manage the augtool commands and the main automation scripts separately.
# General Syntax
sudo augtool -s -f "<filename>"
## Example: commands.txt is where all the augtool command used in interactive mode is saved in
sudo augtool -s -f "commands.txt"
"CRUD" Operations
We can take a look at augtool's operations in reading, creating, updating and deleting specific values in the config files. I will be covering the commands used in non-interactive mode.
- The
-s
option is included to automatically save all changes at the end of the session. This is important as the changes will not be applied by default. - If you would like to try running the commands in the interactive mode, you can do by only using the parameters after the augtool CLI parameters.
## E.g. Printing the setup for /etc/ssh/sshd_config file
## Non-interactive mode
sudo augtool print "/files/etc/ssh/sshd_config"
### Interactive mode
print "/files/etc/ssh/sshd_config"
Read Operation
To get the current setup of your target configuration file
# General Syntax
sudo augtool print "/files/<filename>"
## E.g. Printing the setup for /etc/ssh/sshd_config file
sudo augtool print "/files/etc/ssh/sshd_config"
From here, you will be able to view the hierarchy structure and path to the intended values.
Create Operation
In my use case, I needed to configure DenyUsers
to block specific users from remote SSH access to the instance.
As this parameter does not exists by default, I need to insert a new node into the configuration file. Some caveats for sshd_config file:
- By default, Augeas will write new parameters at the end of the file
- In sshd_config, the Match blocks must be located at the end of the file.
- Augeas will refuse to save the changes in sshd_config file if the Match blocks are not located at the end of the file.
- To create a new parameter as the right place, you must first create a new Augeas node before the Match section.
I decided to create a new node for the new parameter after the PasswordAuthentication
parameter as it is located at the top of the file for ease of finding the parameters later. You can use the ins
keyword to create a new node and after
keyword to indicate the location of the new node after a specific node.
# General Syntax
sudo augtool -s ins "<param_node_to_insert>" after "<target_parameter_node>"
## Example: Creating new node for DenyUsers parameter to be inserted after the PasswordAuthentication parameter
sudo augtool -s ins "DenyUsers" after "/files/etc/ssh/sshd_config/PasswordAuthentication"
Update Operation
To update the value for the parameter, you can use the set
keyword. I will be using an example users with the name user1
and user2
respectively for illustration.
# General Syntax
sudo augtool -s set "/files/<target_file>/<target_param>/<target_position>"
## Example: To configure to deny remote SSH access to user1 and user2
sudo augtool -s set "/files/etc/ssh/sshd_config/DenyUsers/1" "user1"
sudo augtool -s set "/files/etc/ssh/sshd_config/DenyUsers/2" "user2"
Delete Operation
To remove a parameter node completely in your configuration, you can use the rm
keyword.
I will remove user2
from the DenyUsers parameter for illustration.
# General Syntax
sudo augtool -s rm "/files/<target_file>/<target_param>/<target_position>"
## Example: To remove `user2` from the DenyUsers parameter
sudo augtool -s rm "/files/etc/ssh/sshd_config/DenyUsers/2"
Other operations
Dynamic retrieval of path to target value
In some use cases, you may want your automation scripts to be able to retrieve the right parameter node. For example, you have multiple users as shown in the image below
You can use the match
keyword to find the path to your target node. You can use wildcard (*) if needed.
# General Syntax
sudo augtool match "/files/<target_file>/<target_param>" "<value_to_match>"
## Example trying to find user5
sudo augtool match "/files/etc/ssh/sshd_config/DenyUsers/*" "user5"
Sample Output
Increment by index
I wanted to append the !/bin/su
for a user into the /etc/sudoers
file. In the example below, I am using user1
for illustration.
# Original setting
user1 ALL=(ALL) ALL
# Intended setting
user1 ALL=(ALL) ALL, !/bin/su
In this usage, it illustrates that order matters in the execution. I took reference from hercules-team from Github on how to add nodes to the tree.
# Get the base path
getBasePath=$(sudo augtool match "/files/etc/sudoers/*/user" "user1" | sed 's|\/user||g')
# Configure to restrict su access, get the last index & increment
sudo augtool -s set "$getBasePath/host_group/command[last()+1]" "/bin/su"
# Get the command index after configuring in order to add the negate tag
getCommandPath=$(sudo augtool match "$getBasePath/host_group/command" "/bin/su")
sudo augtool -s set "$getCommandPath/negate"
I initially thought that the negate symbol (!) should be indicated first just like typing the config manually, from left to right. Clearly, that's not how a computer would read ๐. So yes, the parameter node /bin/su
should exists first before attaching the negate tag to it.
Final Thoughts
Depending on how stringent your environment is, augeas-augtool can be integrated into your automation script and may provide a more versatile way to manipulate changes in your configuration files.
In hindsight, I found out from a fellow engineer that the reason why sudo echo
did not was due to the elevated privilege being tied to the command echo
rather than the required configuration file. I could have used something like echo <some_value> | sudo tee -a <filename>
whereby the output is duplicated and append into the target file. Nonetheless, I am grateful to have tried out augeas-augtool.๐ซฐ๐ผ
Hope this article can help you kickstart in using augeas-augtool! Cheers๐ป
Resources
General
- SSH: How to change value in config file in one command
- hercules-team/augeas - Adding nodes to the tree
- Generic sshd_config sample config
- Generic sudoers sample config