Dedicated OpenBSD-WireGuard Server; Part Two
Welcome to part two of using WireGuard on OpenBSD! The first post was about the initial release of the project; This followup is about one new role added to the playbook. Now in the initial release, I wasn't attempting to compile wg or wireguard within the playbook itself. I had just planned to update the binaries every day/week with a cronjob run on one of my servers. However, thank you reddit user techsnapp for pointing out that there is actually a script that wireguard provides to assist in compiling the software on OpenBSD. This post will go over the new role written to reliably download and compile wg, wg-quick, and wireguard-go.
As many may know, there is no precompiled WireGuard binary package available in OpenBSD, currently. Luckily with the script that WireGuard has provided, compiling the software on OpenBSD is easy. However, while the script obviously does the job, I would prefer create an ansible roles for such matters. Ansible provides a very modular method for configuring servers, if roles are written properly. I strive to write ansible roles that are as independent as possible, so that roles can be swapped easily between new and old playbooks. This makes creating new playbooks extremely simple, once a handful of core roles have been created.
From WireGuard's script, comes our WireGuard binary playbook.
[Edit 4/27/19]: The original link to the wireguard playbook has been removed. The wireguard playbook has been integrated into my OpenBSD Dev repo, found here, and can be installed using the following command, which will pull down the repo, and install the wireguard binaries. This is meant to run on a new install of OpenBSD, as it could clobber previously installed configs:
ftp -o - https://raw.githubusercontent.com/findelabs/openbsd-ansible-deploy/master/bootstraps/bootstrap_wireguard.sh | sh
wireguard-binaries/vars/main.yml
+++
required_go_version: 1.11
build_utils:
- bash
- gmake
- git
- xz
- gtar-1.30p0
Since the rest of the tasks may rely on these variables, we should go over these first. The required go version was pulled directly from the wireguard script. If the script ever gets updated, that var will have to be updated. The build_utils are the packages required for compiling Go on OpenBSD.
wireguard-binaries/tasks/main.yml
+++
# Required packages are installed with a loop, so that any packages newly installed can be identified at the end of the
# role for removal. These packages are used for both Go (if compiled), and for compiling the wireguard binaries.
- name: Install packages required to build binaries
openbsd_pkg:
name: "{{ item }}"
state: present
register: build_list
loop: "{{ build_utils }}"
- import_tasks: install-go.yml
# The distro list downloaded is simply a list of all versions of wireguard currently available for all systems.
- name: Get wireguard distro list
shell: ftp -v -o - https://build.wireguard.com/distros.txt
register: distros
ignore_errors: true
changed_when: false
# Any possible files that may remain should be removed
- name: Clean up any existing files
file:
path: /usr/src/wireguard
state: absent
# Since the folder was removed, we need to recreate it
- name: Create /usr/src/wireguard
file:
path: /usr/src/wireguard
state: directory
owner: root
group: wheel
mode: 0755
# Import both tasks, one for kmodtools, and one for wireguard-go
- import_tasks: build-wireguard-kmodtools.yml
- import_tasks: build-wireguard-go.yml
# Remove all files created during build
- name: Clean up any remaining files
file:
path: /usr/src/wireguard
state: absent
# Remove any packages installed at the beginning of this role. This was a frustrating task to get working.
- name: Remove packages installed during build
openbsd_pkg:
name: "{{ item.name }}"
state: absent
ignore_errors: true
when: item.changed == true
loop: "{{ build_list.results }}"
wireguard-binaries/tasks/install-go.yml
+++
# Use pkg_info to find the latest binary version of Go available
- name: Check current binary packaged go version
shell: pkg_info -Q go | grep "^go-[0-9]" | cut -d- -f 2 | awk '{print $1}'
register: packaged_go_version
ignore_errors: true
changed_when: false
# Find the current snapshot version
- name: Find most current go version available from source
shell: ftp -v -o - https://golang.org/src/ | sed -E -n 's/.*goVersion = "go([0-9.]+)";.*/\1/p'
register: current_go_version
ignore_errors: true
changed_when: false
# Check to see if Go is installed, and get the version
- name: Check installed go version
shell: "command -v go >/dev/null && (go version | sed -E -n 's/^go version go([^ ]+) .*/\\1/p') || echo 1.00"
register: installed_go_version
ignore_errors: true
changed_when: false
# Install Go with pkg_add, if the binary version matches or is greater than required Go version
- name: Install go binary package
openbsd_pkg:
name: "{{ item }}"
state: present
register: install_go
with_items:
- go
when:
- installed_go_version.stdout is version(required_go_version, '<')
- packaged_go_version.stdout is version(required_go_version, '>=')
# If the installed version is less that the required version, and if the packaged version is not new enough,
# compile Go from source
- import_tasks: compile-go.yml
when:
- installed_go_version.stdout is version(required_go_version, '<')
- packaged_go_version.stdout is version(required_go_version, '<')
wireguard-binaries/tasks/compile-go.yml
+++
# A lesser version of Go is required to compile this version of Go from source.
# This will get removed at the end
- name: Temporarily install go binary package
openbsd_pkg:
name: "{{ item }}"
state: present
register: install_go
with_items:
- go
- name: Download go source
get_url:
url: "https://dl.google.com/go/go{{ current_go_version.stdout }}.src.tar.gz"
dest: /tmp
changed_when: false
- name: Extract go source
unarchive:
src: "/tmp/go{{ current_go_version.stdout }}.src.tar.gz"
dest: /usr/src/
remote_src: yes
# Make the binary
- name: Compile go
shell: cd /usr/src/go/src && ./make.bash
changed_when: false
# And finally, let's remove the binary Go package
- name: Remove go binary package
openbsd_pkg:
name: "{{ item }}"
state: absent
with_items:
- go
# Copy the Go binary over /usr/local/bin
- name: Install go to /usr/local/bin/
copy:
src: /usr/src/go/bin/go
dest: /usr/local/bin/
remote_src: yes
mode: 0755
You may notice that I do not remove the src folder that Go was compiled in. This was a slight compromise, as I typically do not let remnant code remain behind. However, whenever the wireguard binaries will be updated with this playbook, Go will be required. And as the packaged version of Go is not up to snuff, I would rather let the compiled binary remain instead of compiling Go every time the playbook is ran. Luckily, at this time the packaged binary is current enough.
wireguard-binaries/tasks/build-wireguard-kmodtools.yml
+++
# Most of these tasks were cut directly out of the script. Here we get the current version available
- name : Get current kmodtools version
shell: "echo \"{{ distros.stdout }}\" | grep upstream.*kmodtools | cut -f 3"
register: kmodtools_version
ignore_errors: true
changed_when: false
- name: Download WireGuard source
get_url:
url: "https://git.zx2c4.com/WireGuard/snapshot/WireGuard-{{ kmodtools_version.stdout }}.tar.xz"
dest: /tmp/
- name: Extract WireGuard source
unarchive:
src: "/tmp/WireGuard-{{ kmodtools_version.stdout }}.tar.xz"
dest: /usr/src/wireguard/
# Again, copied from the script
- name: Prepare wg and wg-quick Makefile for OpenBSD
shell: "cd /usr/src/wireguard && sed -i 's/install -v/install/g;s/@install/install/g' \"WireGuard-{{ kmodtools_version.stdout }}/src/tools/Makefile\""
changed_when: false
# Here's where I mix some things up. We do not run make install here.
- name: Build wg and wg-quick
shell: "cd /usr/src/wireguard && gmake -j$(sysctl -n hw.ncpu) -C \"WireGuard-{{ kmodtools_version.stdout }}/src/tools\" WITH_WGQUICK=yes PREFIX=/usr/local"
changed_when: false
# Instead, we check here if the wireguard binary is different than the version installed.
# Let's not replace binaries that do not need replacing
- name: Check if new wg binary is different than installed version
shell: "test $(md5 -q /usr/src/wireguard/WireGuard-{{ kmodtools_version.stdout }}/src/tools/wg) == $(md5 -q /usr/local/bin/wg)"
register: wg_md5
ignore_errors: true
changed_when: false
# Same goes here, check if the wg-quick is different than what is installed currently
- name: Check if new wg-quick script is different than installed version
shell: "test $(md5 -q /usr/src/wireguard/WireGuard-{{ kmodtools_version.stdout }}/src/tools/wg-quick/openbsd.bash) == $(md5 -q /usr/local/bin/wg-quick)"
register: wgquick_md5
ignore_errors: true
changed_when: false
# Here we only install the binaries if either of the previous two files were different
- name: Install wg and wg-quick
shell: "cd /usr/src/wireguard && gmake -j$(sysctl -n hw.ncpu) -C \"WireGuard-{{ kmodtools_version.stdout }}/src/tools\" WITH_WGQUICK=yes PREFIX=/usr/local install"
changed_when: false
when: wg_md5.rc != 0 or wgquick_md5.rc != 0
wireguard-binaries/tasks/build-wireguard-go.yml
+++
# This info is pulled out of the distro info gathered in main.yml
- name : Get current wireguard version
shell: "echo \"{{ distros.stdout }}\" | grep upstream.*go | cut -f 3"
register: wireguard_version
ignore_errors: true
changed_when: false
- name: Download WireGuard-go source
get_url:
url: "https://git.zx2c4.com/wireguard-go/snapshot/wireguard-go-{{ wireguard_version.stdout }}.tar.xz"
dest: /tmp/
- name: Extract WireGuard-go source
unarchive:
src: "/tmp/wireguard-go-{{ wireguard_version.stdout }}.tar.xz"
dest: /usr/src/wireguard/
# This is also pulled directly out of the script
- name: Prepare WireGuard-go Makefile for OpenBSD
shell: "cd /usr/src/wireguard && sed -i 's/install -v/install/g;s/@install/install/g' \"wireguard-go-{{ wireguard_version.stdout }}/Makefile\""
changed_when: false
# This matches kmodtools. Do not install unless the binary is different.
- name: Build wireguard-go
shell: "cd /usr/src/wireguard && gmake -j$(sysctl -n hw.ncpu) -C \"wireguard-go-{{ wireguard_version.stdout }}\" PREFIX=/usr/local"
changed_when: false
- name: Check if new wireguard-go binary is different than installed version
shell: "test $(md5 -q /usr/src/wireguard/wireguard-go-{{ wireguard_version.stdout }}/wireguard-go) == $(md5 -q /usr/local/bin/wireguard-go)"
register: wireguardgo_md5
ignore_errors: true
changed_when: false
# Only install the binary if the new binary is different than the installed binary
- name: Install wireguard-go
shell: "cd /usr/src/wireguard && gmake -j$(sysctl -n hw.ncpu) -C \"wireguard-go-{{ wireguard_version.stdout }}\" PREFIX=/usr/local install"
changed_when: false
when: wireguardgo_md5.rc != 0
I am sometimes shocked at how complicated ansible playbooks can be compared to shell scripts. Personally, it is much easier for me to compose offhand in shell than in ansible. Though, as stated in the beginning, I believe ansible has the advantage of being more powerful in the grand scheme. Using the entire OpenBSD-WireGuard playbook, I can deploy new wireguard VM's within minutes, anywhere in the world with Vultr.
Has been tested on OpenBSD 6.4 and 6.5