• Weeknotes - Vault Agent, WireGuard, more WireGuard

    Not a ton of side project work the last week or so. Though, I’ve been slowly incorporating Go into my toolbox at work. Think SSO OAuth API calls wrapped in a friendly, portable CLI tool.

    I did however update query-bot to use Slack’s “App” API authentication flow. Thanks to this PR finally merging. Expect a proper release soon-ish!

    Dynamic WireGuard configurations with Vault Agent Templates

    Also in the background I’ve been toiling away on a project to bring together a WireGuard-gated Nomad, Consul, and Vault deployment model that is packed full of things like mTLS, ACLs, and dynamic, Vault-derived secrets.

    Last week I implemented a Vault Agent Template for my WireGuard configuration and it’s been great not having to bake my WireGuard peer configurations into my machine images.

    A sample of the template:

    Address =,fd10::1/64
    ListenPort = 51800
    PostUp = /etc/wireguard/postup.sh
    PostDown = /etc/wireguard/postdown.sh
    {{- with secret "kv/node/wireguard" }}
    PrivateKey = {{ .Data.data.private_key }}
    {{ end }}
    {{ range secrets "kv/metadata/node/wireguard-peers/" -}}
    {{ with secret (printf "kv/node/wireguard-peers/%s" .) -}}
    # {{ .Data.data.description }}
    PublicKey = {{ .Data.data.public_key }}
    AllowedIPs = {{ .Data.data.allowed_ips }}
    {{ end }}
    {{- end }}

    Vault Agent configuration:

    # WireGuard templates
    template {
      source      = "/etc/wireguard/wg0.conf.tpl"
      destination = "/etc/wireguard/wg0.conf"
      command     = "systemctl restart [email protected]"

    I know that I can use wg syncconf to hot-reload the configuration, but I have yet to implement that due to some blocking factors.


    WireGuard Endpoint Discovery and NAT Traversal using DNS-SD

    • This type of deep-dive is my happy place. WireGuard + DNS + NAT trickery further makes the case for WireGuard as a minimal, secure, and performant tunnel technology.

    Notes on building debugging puzzles

    • Julia Evans never stops introducing novel methods of knowledge sharing, and this post about her foray into interactive, debugging puzzles is right in line with her usual high-quality content. Plus, it’s about DNS!
  • Weeknotes - query-bot, HCL2, Docker without Docker

    So I’ve ended up writing 246 lines of Go in my quest to build a Slack bot…introducing query-bot.

    As I put it simply in the README:

    query-bot is an unintelligent Slack bot for writing HTTP query responses to a given channel when user messages match pre-defined commands.

    It’s basically a Slack bot for curl.

    It’s pretty bare-bones currently, and I have a pending feature branch with non-legacy authentication and some key refactoring. Though I have to say that I love working with Go. Error handling is dead simple, Viper is a killer configuration module, and my container image is only 14MB!

    Packer templates in HCL2

    Let’s leave JSON templates behind:

    packer hcl2_upgrade template.json

    Note: v1.7.1 required if you want the above command to also upgrade variables to HCL2 local variables

    Hashicorp’s introduction to Packer and HCL2.


    Docker without Docker

    • fly.io is a platform that I have been wanting to try out (multi-region containers with BGP Anycast + Firecracker micro-VMs!) and this deep dive on their blog about their container to micro-VM deployment pipeline speaks volumes about their investment in building a cool product.

    How to make an awesome Python package in 2021

    • When you want to make that one-off Python utility a little more official…
  • Weeknotes - ACLs, e-ink, PGP git commits

    This week I’ve continued work on my Nomad/Consul architecture and began using the allure of Slack bots to learn a bit of Go.

    Also, I’m trying to let myself post a bit more than a few bookmarks per week—hence the renaming of these weekly posts from Goodies –> Weeknotes (à la Simon Willison’s blog). He’s quite industrious!

    Consul ACLs

    It’s dead simple to automate the deployment a dual-stack Nomad/Consul cluster, but ensuring that proper and sane ACL bootstrapping is part of the process is less than straightforward. HashiCorp documentation is great though often contradicting! Here’s a good primer.


    Creating a digital newspaper from a 32” e-ink display

    • Absolutely the type of project that’s been on my list for quite some time. If only e-ink displays weren’t so expensive.

    What does a PGP signature on a git commit prove?

    • An informative piece on how cryptographic signatures on git commits can help guarantee the validity of a repository’s history.
  • Weeknotes - DNS tool in Go, not your normal binary


    A fun web tool (built with VueJS and Golang on Netlify functions) to make DNS queries

    Another deep dive into personal data warehouse infrastructure

    A run-everywhere web server binary that is also the zip archive containing page source.
    Completely nuts.

    Sendy - Affordable, self-hosted newsletter platform using Amazon SES

    Apple Platform Security - Apple Support

  • Weeknotes - S3 sync, mission control, personal data warehouses


    Papercraft Models by Rocky Bergen

    Replacing Dropbox in favor of DigitalOcean spaces (or other S3 storage)

    Open MCT - Open Source Mission Control Software by NASA

    The Big Little Guide to Message Queues

    Personal Data Warehouses: Reclaiming Your Data by Simon Willison

  • Weeknotes - 2 million containers, thermometer firmware

    This is the first post of a maybe-once-a-week series of things that I found on the internet that may be worth a look.


    Hashicorp - The 2 Million Container Challenge

    fasterthanli.me - A half-hour to learn Rust

    Julia Evans - Docker Compose: a nice way to set up a dev environment

    Custom firmware for the Xiaomi Thermometer LYWSD03MMC

  • Make a DaemonSet schedule a pod on the master node(s)

    Who hasn’t been building a small Pi-based Kubernetes cluster at home?

    Well, on mine I wanted to deploy a DaemonSet with node_exporter for my external Prometheus service to scrape metrics of each node in the cluster, so I wrote up a DaemonSet manifest and applied it to my cluster. On first glance everything seemed happy, but quickly I noticed that the master node was not running a node-exporter pod!

    A quick Stack Overflow search led me to this answer and informed me that since Kubernetes 1.6 you have to add a toleration to the Pod spec section of your DaemonSet manifest:

      - key: node-role.kubernetes.io/master
        effect: NoSchedule

    I added this, and my master node was now running a node-exporter pod—just as I wished.

  • Using Vim to record a maintenance event timeline

    Vim can do lots of things

    After-hours maintenance is something my team and I encounter frequently. Whether it’s customer turn-ups, circuit migrations, or firmware upgrades—we get used to the 10pm to early morning working hours!

    Often, we like to record a rough timeline of events during the maintenance period in order to have timestamped context for re-tracing our steps and/or investigating persistent issues before/during/after the maintenance period. Historically I’ve manually inserted timestamps as we never keep too granular of a timeline. However, this last go-around I decided to dig a little into Vim and look into how to automate the insertion of timestamps whenever I start a new line in the editor.

    Insert mode maps

    Vim/vi is nearly limitless in its customization. One of the configurable properties is key mappings. Key mappings allow the creation of a shortcuts for the purpose of repeating a sequence of keys or commands.

    In my use case, I want to map the automatic input of the formatted, current time using Vim’s internal strftime() function whenever we drop down to a new line in the editor. The mapping below is what I came up with:

    :imap <buffer> <CR> <CR><C-R>=strftime("%Y-%m-%d %H:%M:%S :: ")<CR>
    • imap tells Vim that this is an insert mode map
    • <buffer> tells Vim to only consider the mapping in the buffer in which it is defined
    • The first <CR> is the left-hand-side of the map command, which defines the keys used to activate the shortcut. <CR> and <Enter> are synomymous
    • <C-R> tells vim to insert the following expression at the cursor
    • =strftime("%Y-%m-%d %H:%M:%S :: ") is our strftime() function to grab the current date and time in the preferred format
    • The final <CR> executes the expression

    If the above is entered as a Vim command, a timestamp will be inserted at the beginning of the line every time Enter is pressed while in insert mode.

    Make it a Vim filetype

    Now that we have the functionality we want, the next step is to automate the key mapping when it’s suitable.

    First, enable the filetype plugin in your .vimrc file:

    filetype plugin on

    Create the following directories:

    • ~/.vim/ftdetect
    • ~/.vim/ftplugin

    In my example, I’m going to define a new filetype called toe (timeline of events) with the extension of .toe.

    Let’s define our filetype detection file:


    autocmd BufNewFile,BufRead *.toe set filetype=toe

    This sets the Vim filetype to toe when the filename ends in .toe.

    Lastly, we define the command(s) we want active when the filetype is toe:


    imap <buffer> <CR> <CR><C-R>=strftime("%Y-%m-%d %H:%M:%S :: ")<CR>

    Now, whenever you manually set the filetype to toe or open a file that ends in .toe, Vim will know to insert a timestamp at the beginning of each new line.

    Originally, I wanted to make a quick CLI tool in Go to replicate this behavior, but I’m glad that I went down the route of learning a bit more about Vim/vi.