
Research
Supply Chain Attack on Axios Pulls Malicious Dependency from npm
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.
freecontrol
Advanced tools
Scripted setup, deployment, and management of FreeBSD machine clusters
DESCRIPTION
freecontrol manages the power to serve. Use freecontrol to securely manage initial installation, setup, app deployment, maintenance, and monitoring of clusters of one or more FreeBSD machines in parallel using scripted, repeatable ssh tasks and port sets while logging all commands sent and responses received from every machine in the cluster.
If new to FreeBSD, follow included instructions to set up bare metal or virtual FreeBSD machines with the standard minimal installation, which is all that is needed for acquisition and control. freecontrol is for general FreeBSD administration, but, if a Node user, use built in tasks to setup any number of production-ready FreeBSD Node servers with a single command.
freecontrol is based on Node (node.js), which includes the V8 JavaScript engine and allows easy scripting of your own custom tasks. Remote machines do not require any special software except a minimal install of FreeBSD with the sshd daemon running, which can be configured during minimal installation of FreeBSD. The local control machine simply requires Node and OpenSSH (does not have to be FreeBSD).
MODULE INSTALLATION
Clone this repository with git or download the latest version using the GitHub repository Downloads link. Then use as a standard Node module by requiring the node-control directory in your tasks file (discussed below).
If you use npm:
npm install freecontrol
MACHINE CREATION
If you have FreeBSD machines already setup, skip to CONFIGURATION.
If you are starting from scratch, you can either install FreeBSD on bare metal or virtual machines within your current operating system using virtualization software such as VMWare or Parallels. See the VM file for instructions on how to create new FreeBSD virtual machines.
For either bare metal or virtual machine installation, see the INSTALL file for instructions on how to perform minimal installations of FreeBSD and prepare the machines for remote administration. Make sure to read the post installation networking notes in the POSTINSTALL file to get network access to your newly installed machines after completing the installation process.
CONFIGURATION
freecontrol requires that you create a configuration task to identify the machine or machines you want to administer and set various options that will be discussed below. To do this, simply create a JavaScript file similar to the below:
var control = require('./freecontrol'), task = control.task;
task('mycluster', 'Config for my cluster', function () { var config, addresses; config = { user: 'mylogin', packages: true }; addresses = [ 'a.mydomain.com', 'b.mydomain.com', 'c.mydomain.com' ]; return control.hosts(config, addresses); });
control.begin();
If you install the npm package, use this require statement instead:
var control = require('freecontrol'),
This tells freecontrol what machines you want to administer when you invoke this configuration while executing a work task. Addresses can be IP or DNS addresses. The user is the administrative user that you use on the remote administration machine (using the root user is discouraged and it is easy to setup a non-root admin user as you will see below). If you have less or more machines you want to administer, just edit the addresses array accordingly. If you only want to administer one machine, just place one address in the addresses array.
You can define many different configuration tasks for different clusters or different environments in the same file, such as stage versus production. Just name them accordingly and use them as the config tasks when executing work tasks as you will see below. You can name your tasks file whatever you like, but this README assumes you name it mycontroller.js. freecontrol directly extends node-control and you can read more about config tasks here:
http://github.com/tsmith/node-control
ACQUIRING CONTROL
If you already have keypair authentication established with the remote machines you want to control, skip to BOOTSTRAPPING.
If you are installing from scratch or have procured one or more dedicated servers from a data center, at this point you will generally have one or more FreeBSD machines with a root user, known root password, and sshd running. Ideally, you want to move out of using password authentication and close down logging in as root by creating another admin user as soon as possible. Establishing keypair authentication for that new admin user will allow all future tasks to run without password entry.
To acquire root control of the remote machines, execute the following task with the path of a public key of a keypair in your local user .ssh directory. For example:
node mycontroller.js mycluster acquire ~/.ssh/id_dsa.pub
This will log into the machines and copy your public key over for the root user so that you can use the root user at least temporarily without having to enter a password on every command. You will have to enter the root password of the remote machines here twice for each machine, but this is the last time. If you are setting up a lot of remote machines, you will want to find a way to image them with a public key so you an skip this step.
BOOTSTRAPPING
If you have one or more FreeBSD machines already setup with users, ports, and packages and want to use custom tasks and port sets to administer and monitor these existing machines, skip to CUSTOM TASKS below.
Otherwise, if you have freshly installed machines with keypair authentication established for the root user, you will want to perform the following to bootstrap your initial admin user and secure the machines against root and password login.
First, shift the server time zone to UTC, synch clock, and install sudo:
node mycontroller.js mycluster bootstrap
Then create a non-root admin user matching the user you specified in the configuration task and ready the machines for administration by this user:
node mycontroller.js mycluster bootstrap:admin 'Your Name' newpassword path/to/public_key
The security-conscious administrator will test that key-based access as the new non-root user is working:
node mycontroller.js mycluster uname
Then, if that succeeds on all machines, turn off remote root and password-based login:
node mycontroller.js mycluster secure
NODE
If you have performed all the steps in BOOTSTRAPPNG above and now want to install Node on all the remote machines, run:
node mycontroller.js mycluster portsets:node
However if you want a production ready Node server all in one go, including all the bootstrap tasks above, just execute bootstrap:node after acquiring control:
node mycontroller.js mycluster bootstrap:node 'Your Name, newpassword, path/to/public_key
TIME SYNCHRONIZATION
When dealing with clusters of machines, time synchronization becomes very important to establishing time lines of events occurring across the cluster. Remote machines' time will be synchronized via NTP during initial bootstrap, but to keep time synchronized, run one of the following depending on whether the remote machine is a bare metal machine or a (VMWare) virtual machine:
node mycontroller.js mycluster bootstrap:nettime // Bare metal machine node mycontroller.js mycluster bootstrap:vmtools // VMWare virtual machine
In the latter case, it is assumed that the host machines' clocks are being synchronized. The vmtools work for VMWare virtual machines - you will need to find out the proper tools if you use other virtualization solutions.
CUSTOM TASKS
The built-in tasks are just to get you started. Everyone has different needs for their machines and strategies for deploying applications, but everyone faces the same problem of being able to reliably execute the same commands across many different machines or environments with a low error rate, high repeatability, good logging, and speed of execution. With freecontrol, you can create any number of custom tasks and execute them just like the example bootstrap tasks above.
For information on creating custom tasks, see the node-control README (freecontrol extends node-control):
http://github.com/tsmith/node-control
To list all built-in and custom tasks:
node mycontroller.js mycluster list
PORTSETS
A significant portion of time administering FreeBSD machines involves managing ports and packages. Although you can create custom tasks with the explicit commands to do as much port and package management as you want, freecontrol provides a PortSet object that can install sets of ports for you using ports or packages, configurable csup tags, configurable package directories, and configurable package files based on the list of ports you add to the portset and certain properties you add to the config object in your configuration task.
Here's an example of a portset being used to install node and curl to download and install npm (the Node package manager, which is not itself a FreeBSD port):
PortSet = require('./portset').PortSet;
task('portset:node', 'Install just node and npm', function (host) { var set = new PortSet(); set.add('www', 'node'); // Specify both category and port name set.add('ftp', 'curl'); set.install(host, function () { // Callback is optional host.ssh('curl -# http://npmjs.org/install.sh | sudo sh'); }); });
A portset installs ports and packages in the order they are declared, and deinstalls them in opposite order. Both the install() and deinstall() methods take the host object as the first argument and an optional callback as the second argument, to be executed when the full portset has finished being installed or deinstalled.
By default, portsets install ports from a local ports collection. If you want to use packages instead, set the packages property to true on your config object in your config tasks:
config.packages = true;
If you did not install a local ports collection during installation, or want to update your local ports collection, use the ports:csup task:
node mycontroller.js mycluster ports:csup
This can take some time. If you want to use a different FreeBSD repository CSV tag for the local ports collection than HEAD, you can specify the csupTag property on the config object in your config tasks:
config.csupTag = 'RELENG_8_1_0_RELEASE';
When building from ports, sometimes you want to pass in compilation options for a particular port. You can do this simply by specifying the additional options in a string when you use the add() method to add a port to a portset:
set.add('devel', 'git', '-DGUI -DSVN')
When using packages, you can optionally specify the particular version of a package you want to install by setting the packageVersion property of your config object to a hash containing the names of packages mapped to versions in your config tasks:
config.packageVersions = { curl: '7.20.1', node: '0.1.99' };
Note that if you use explicit package versions, you need to specify a package site that has a folder of versioned package files in it that contains all the packages you want installed:
config.packageSite = 'ftp://ftp.freebsd.org/pub/FreeBSD/ports/amd64/packages-8.1-release/All'
FreeBSD package sites generally have an All directory, where all the package files are versioned (like curl-7.30.1.tbz) and a Latest directory, where all the package files are not versioned (like curl.tbz). Even if you do not use explicit package versions, you can still configure the packageSite property to a site containing unversioned packages:
config.packageSite = 'ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-current/Latest'
Finally, you can have packages installed from files in a folder on the remote machines. To do this, set packageRemoteDir to the directory on the remote machine where the package files are staged and packageFiles to a hash of package name to package file names on the config object in your config tasks:
config.packageRemoteDir = 'mypackages'; // Defaults to 'packages' if not given config.packageFiles = { curl: 'curl-7.20.1.tbz', node: 'node-0.1.99.tbz' };
In most cases you will not need this level of configuration when using packages, but these can be useful for some organizations that maintain their own package sites or collections. Generally this arises when port collections are not installed on production machines and packages are pre-built and tested on development or stage machines, then the built (and tested) packages are deployed out to the production machines.
FILE TASKS
When configuring machines, you often have to make modifications to configuration files - adding lines, changing lines, removing lines. freecontrol includes a few tasks to make this easier.
To add a line to a file, execute the file:mkline task, passing in the file name on the remote machine and the line to add as arguments:
node mycontroller.js mycluster file:mkline path/to/file 'new line'
file:mkline will create the file and add the line to it if the file does not exist on the remote machine.
To change a line in a file, execute the file:chline task, passing in the file name on the remote machine, a matching string, and the replacement for the matched string:
node mycontroller.js mycluster file:chline path/to/file 'matching text' 'replacement text'
To remove a line in a file, execute the file:rmline task, passing in the file name on the remote machine and a matching string.
node mycontroller.js file:rmline path/to/file 'matching text'
Changing and removing is done using sed, and the matching string and replacement is inserted into a sed substitution command:
s/match/replacement
Therefore, you can use regular expressions in the match string. Note also that all lines that match will be changed or removed, so make sure to test and craft your matching string to match only the line you want changed or removed.
These tasks can also be used as subtasks within other custom tasks you create. Here is an example of file:chline being used as a subtask to disable root login:
perform('file:chline', host,
'/etc/ssh/sshd_config',
'PermitRootLogin yes',
'PermitRootLogin no');
LOGGING
All commands sent to remote machines and received are logged locally in a file suitable for easy analysis with standard text manipulation tools such as grep. See the LOGGING section of the node-control README for more details:
http://github.com/tsmith/node-control
OVERRIDING BUILT-IN TASKS
If you do not like a choice made in one of the built-in tasks, you can simply override it by declaring your own task of the same name in your control file. The new logic will be used whenever that task is called, even as a subtask of the remaining built-in tasks.
SECURITY NOTES
Different organizations and different administrators have different levels of security consciousness and need. freecontrol attempts to balance strong security with convenience and assumes the control machine or machines are themselves secure. This section notes a few choices made by freecontrol that extremely security-conscious administrators should be aware of:
By default, the acquire task (and only the acquire task) disables host key checking so the host keys of the new machines are automatically added to your known_hosts files (skipping an interactive prompt for each machine). If this is not appropriate for your situation, you can disable it by setting the 'strictly' argument of the acquire task to true:
node mycontroller.js mycluster acquire ~/.ssh/id_dsa.pub true
The built-in bootstrap task gives permissions to all wheel group (admin) users to use sudo without a password on the remote machine. This enables sudo operations in subsequent tasks to succeed without interactive prompts. If this not appropriate for your situation, you can disable this modification to sudo permissions at the point of bootstrap by passing true for the 'sudopwd' argument of the bootstrap task:
node mycontroller.js mycluster bootstrap true
The user:new task takes a password as one of its arguments. If executed on the command line, the password of the user that will be created on the remote machines will be visible on your local console and may appear in your shell command history. If this is not appropriate for your situation, you can create an encapsulating task that sources the password in some other way and calls user:new as a subtask using the perform() function. If you name this encapsulating task bootstrap:admin, it will be used during the bootstrap process in place of the built-in one.
freecontrol does not provide any built-in password or key caching or forwarding. Please use ssh-agent in conjunction with freecontrol if you want those features (such as not having to enter a password for your private key on each ssh command execution and allowing remote machines to perform remote or repository operations without interactive prompting for passwords).
FEEDBACK
Feedback welcome at node@thomassmith.com or the Node mailing list.
FAQs
Scripted setup, deployment, and management of FreeBSD machine clusters
We found that freecontrol demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.

Security News
TeamPCP is partnering with ransomware group Vect to turn open source supply chain attacks on tools like Trivy and LiteLLM into large-scale ransomware operations.