Category Archives: Systems Administration

Building a Chef Omnibus package for Raspbian / Raspberry Pi

There are various guides about how to get Chef on a Raspberry Pi, but none I could find about how to build a proper Chef client package. People used to Omnibus packages (Chef, ChefDK) expect a certain consistency when deploying stuff.

I’m using the pi user for the following script under Raspbian Buster:

sudo apt-get install build-essential git ruby bundler
git clone https://github.com/chef/chef
cd chef
# checkout the desired Chef release tag, for example
git checkout v15.7.32
cd omnibus bundle install --without development --path vendor/bundle
sudo mkdir -p /var/cache/omnibus /opt/chef
sudo chown pi:pi /var/cache/omnibus /opt/chef # if building under the pi user
# git is being bit of a git - use proper values on an actual box, unless it's just
# a build box
git config --global user.email "[email protected]"
git config --global user.name "Your Name"
bundle exec omnibus build chef
# wait for an extreme amount of time...

# check the build results
ls -l pkg
total 32320
-rw-r--r-- 1 root root 33033164 Feb 7 22:07 chef_15.7.32+20200207193316-1_armhf.deb
-rw-r--r-- 1 root root 52348 Feb 7 22:07 chef_15.7.32+20200207193316-1_armhf.deb.metadata.json
-rw-r--r-- 1 root root 6894 Feb 7 22:07 version-manifest.json

dpkg -I pkg/chef_15.7.32+20200207193316-1_armhf.deb
new Debian package, version 2.0.
size 33033164 bytes: control archive=327544 bytes.
298 bytes, 11 lines control
1552093 bytes, 12722 lines md5sums
3190 bytes, 111 lines * postinst #!/bin/sh
1226 bytes, 50 lines * postrm #!/bin/sh
837 bytes, 23 lines * preinst #!/bin/sh
Package: chef
Version: 15.7.32+20200207193316-1
License: Chef EULA
Vendor: Omnibus <[email protected]>
Architecture: armhf
Maintainer: Chef Software, Inc. <[email protected]>
Installed-Size: 121364
Section: misc
Priority: extra
Homepage: https://www.chef.io
Description: The full stack of chef

In fact, other than the pi user, none of the above steps are Raspbian specific. They work on pretty much all Debian-based distributions. With the exception of the apt-get line, all the steps are in fact distribution agnostic, but I had to learn them the hard way.

After a huge amount of wait, behold a chef deb ready to be installed. That amount may be significantly shorter on a Raspberry Pi 3 or 4B as Omnibus makes use of all CPU cores.

Emulating a Raspberry Pi

While this may not be necessary, I don’t always have a Raspberry Pi I can kill (read stress, I never had one fail) with package builds. It was quite the challenge to find the winning combination. While the build benefits from better storage and more RAM, the CPU speed isn’t impressive. However, speed isn’t the purpose. While it’s possible to use this under native qemu, regardless of host OS, I went the VM route to have more predictable results. The macOS qemu is painful to work with anyway.

Vagrant to the rescue:

Vagrant.configure('2') do |config|
  config.vm.box = 'bento/ubuntu-16.04'
  config.vm.box_check_update = true

  config.vm.provider 'virtualbox' do |vb|
    vb.name = 'ubuntu-pi'
    vb.cpus = 4
    vb.memory = 2048
    vb.customize ['modifyvm', :id, '--nictype1', 'virtio']
  end
end

This is a fairly standard Vagrantfile. The vb.customize bit makes sure the network interface uses virtio. I’ve had issues in the past with wobbly performance using the default NIC type.

The actual setup for chroot-ing into a qemu-user-static container is excellently described on the Debian Wiki. The only change was Raspbian Buster which is the current release. I have increased the Raspbian root volume by 4096 MiB.

I have used systemd-nspawn, then after chroot-ing, killed the entry in /etc/ld.so.preload as it spams the shell with messages about failing to load a rather useless library in this setup.

Then, simply use the Raspbian script that I have used on actual Raspberry Pi’s.

Using persistent OpenSSH connections

I found out that using persistent connections greatly improves the productivity when working with SSH. However, finding the appropriate configuration turned out to be a complicated task. I wanted it to be as unobtrusive as possible, to restart the connection when the socket is closed, and to work without blocking timeouts.

After reading the ssh_config man page and some articles, here’s the best thing I came up with:

Host *
	ControlPath ~/.ssh/master-%[email protected]%h:%p
	ControlMaster auto
	ControlPersist 4h
	TCPKeepAlive no
	GSSAPIAuthentication no
	ServerAliveInterval 60
	ServerAliveCountMax 2

The only issue with this configuration is with long hosts (eg: a really long name) as it hits the UNIX_PATH_MAX limit. Unfortunately, the proper solution to this issue isn’t merged into upstream.

The OS X users who also use brew may easily include the patch for the path issue by editing the openssh formula for OpenSSH 6.6p1 with “brew edit openssh”:

  patch do
    url "http://www.mirrorservice.org/sites/downloads.sourceforge.net/m/ma/mancha/misc/openssh-6.6p1-mux-hash.diff"
    sha1 "31f6df29ff7ce3bc22ba9bad94abba9389896c26"
  end

With this patch, a value like ~/.ssh/master-%m works for ControlPath. %m is replaced by SHA1(lhost(%l) + rhost(%h) + rport(%p) + ruser(%r)) and it keeps things short and sweet.

Getting a HTTPS certificate information into the shell

Due to the HeartBleed SNAFU, I needed a quick solution for getting the information from a certificate deployed on a remote machine. As I rarely leave the comfort of my terminal, as always, I simply dumped a new function into the shell’s ~/.*rc file.

Here it is:

Defaults to port 443 if the second argument is unspecified. Example:

 

portspoof trolling

Marius once told me about portspoof. A service to troll those who use various scanners by feeding the scanners with false results. Well, while the idea is good, I’m wary about a service like this as this is the kind of service where you wouldn’t want a buffer overflow.

Giving it a run inside a VM, I noticed something odd when using nmap’s service and version detection probes. This happened on the lower ports (1-50). Then I started to look at something that started to look like a pattern, therefore I increased the port range to include 1-50. portspoof is indeed a tool that trolls baddies and pen testers.

Ran it with:

nmap -sV --version-all -p 1-50
 

Really smooth guys, really smooth. Sometimes you have to see the big picture:
big-picture

Splitting a string every nth char in shell

I needed some reusable stuff that splits a string every nth char. Then I remembered that bash and zsh, the shells that I usually use, support string slicing. Kinda like Python does. Or the other way around. Made a shell function. Dropped in into .bashrc / .zshrc. Enjoy.

function string_split()
{
	str="$1"
	count=$2
	while [ ! -z "$str" ]
	do
		echo "${str:0:$count}"
		str="${str:$count}"
	done
}

Example:

string_split abcd 2
ab
cd