Dockerized Vault with Consul Backend

I recently wanted to get a working vault instance running. Since my goal is to sharpen my devops skillset, I had some specific features I wanted to make sure I had nailed down:

  • Run vault in server mode, rather than dev
  • Run it in Docker, ideally using docker-compose
  • Have other containers access the vault for secrets
  • Use a persistent storage mechanism for the backend
    • I didn’t want to use files for this

To meet the storage requirements, after looking into it a little bit it became apparent that Consul was probably the right move (as of this post, it’s the only database engine that’s officially supported by Hashicorp for Vault — which makes sense since they make both products).

It turns out that getting Vault and Consul up and running – and talking to each other – is not as straightforward as it could be. I found lots of examples, but most of them did not work anymore, and all of them used version 2 of the docker-compose spec. After much trial and error and a ton of failure, I finally got things running successfully. If you want to try it out, you can check it out at

One thing to note: as configured in the repo the Vault container talks to Consul over HTTP. Since the secret is encrypted inside vault, no sensitive data is being passed in plaintext over the network (in theory), but it’s still not the best-practice to use HTTP here.

The problem is that there’s a bit of a chicken/egg problem with using HTTPS… specifically: you need to securely get certificates and privatekeys into the Vault and Consul containers in order for TLS to work properly. But doing that means either:

1) checking the certs into a repo, or
2) passing them into the container via something like a volume or ENV var.

Neither of these are ideal.

I’ll probably ultimately end up opting for passing them in via a bootstrap volume of some kind, but am still thinking over how best to handle this.

Ubuntu and SNMP MIBs

Just a quick note: if you’re trying to run something that queries a specific MIB like:
snmpwalk -v1 -c public ${host} system

and you get an error like:
Unknown Object Identifier (Sub-id not found: (top) -> system)

This is because MIBs are not “free”, so Ubuntu disables them by default.

To get them back, install the MIBS using 
# apt-get install snmp-mibs-downloader

Then go comment out the mibs : line in /etc/snmp/snmp.conf (it’s line 4 as of this post). Now run your query again and things should be better.

How To Run Your Own Cell Tower

This post is a collection of notes from about 2 years ago. I keep meaning to post them, but keep getting busy and not having time to get around to editing them for clarity and/or currency, but I keep wanting to reference them, so I’m finally just going to dump them here as-is.

NOTE: doing this may be illegal in your jurisdiction. Specifically, using the radio frequencies required for this to work could potentially be a federal offense (in the US). Be sure you understand the legalities before following this guide, etc.

Also note: this is specifically for GSM network cell traffic. If you are looking for something other than GSM, things are going to be different.

And with that all said, the following basically takes you from “I just installed Ubuntu” to “I have cell phones calling/texting each other through my ‘tower'” in roughly 10 minutes using a BladeRF and a laptop.


  • [ 1 ] of Lenovo Y50-70 Laptop:
  • [ 1 ] of BladeRF x40:
  • [ 1 ] of BladeRF case:
  • [ 2 ] of Superbat 5dbi 700-2600Mhz 4G LTE Omni Directional Antenna:

NOTE: OS used for this project was Linux Mint 17.3 – KDE Spin

$ cat /etc/lsb-release
DISTRIB_DESCRIPTION="Linux Mint 17.3 Rosa"

$ uname -srp
Linux 3.19.0-32-generic x86_64

Getting BladeRF Running

  • Add your username to the plugdev and dialout groups
$ sudo usermod -a -G plugdev <username>
$ sudo usermod -a -G dialout <username>
  • Install the bladeRF PPA and required software packages
$ sudo add-apt-repository ppa:bladerf/bladerf
$ sudo apt-get update
$ sudo apt-get install bladerf libbladerf-dev bladerf-firmware-fx3 bladerf-fpga-hostedx40
  • Create a ~/.Nuand/bladeRF directory
  • Store the FPGA image in the bladeRF directory so it can be autoloaded
$ mkdir -p ~/.Nuand/bladeRF
$ cd ~/.Nuand/bladeRF
$ wget

*NOTE: since we installed the FPGA from the bladeRF PPA, you could also just link to that from your bladeRF directory instead:

$ ln -s /usr/share/Nuand/bladeRF/hostedx40.rbf ~/.Nuand/bladeRF
  • Grab the latest firmware image
$ wget
  • Plug the bladeRF in
  • Verify the system sees the device
$ dmesg | grep usb
[  992.744233] usb 2-2: New USB device found, idVendor=1d50, idProduct=6066
[  992.744235] usb 2-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  992.744237] usb 2-2: Product: bladeRF
[  992.744239] usb 2-2: Manufacturer: Nuand
[  992.744240] usb 2-2: SerialNumber: d1c8b59ff5d36d39d43af24eaca005a3
  • Verify the system recognizes the bladeRF (using bladeRF-cli):
$ bladeRF-cli -p

  Backend:        libusb
  Serial:         d1c8b59ff5d36d39d43af24eaca005a3
  USB Bus:        2
  USB Address:    2

$ bladeRF-cli -i
[INFO @ version_compat.c:116] FPGA version (v0.4.1) is newer than entries in libbladeRF's compatibility table. Please update libbladeRF if problems arise.

bladeRF> info
  Serial #:                 d1c8b59ff5d36d39d43af24eaca005a3
  VCTCXO DAC calibration:   0x8ea1
  FPGA size:                40 KLE
  FPGA loaded:              yes
  USB bus:                  2
  USB address:              5
  USB speed:                SuperSpeed
  Backend:                  libusb
  Instance:                 0
  • Update the firmware on the bladeRF
$  cd /usr/share/Nuand/bladeRF/
$  bladeRF-cli --flash-firmware ./firmware.img

Install Yate

  • Checkout the source code from SVN and compile
$ mkdir svn
$ cd svn/
$ svn checkout yate
$ cd yate/
$ ./
$ ./configure
$ sudo make install
$ which -a yate-config

Install YateBTS

  • Checkout the source code from SVN and compile
$ cd ..
$ svn checkout yatebts
$ cd yatebts/
$ ./
$ ./configure
$ sudo make install
  • Pickup the new libraries
$ sudo ldconfig

Configure YateBTS

  • Setup the GSM band information by setting the following values in the configuration file:
$ sudo vi /usr/local/etc/yate/ybts.conf

Run YateBTS

  • Run the yate binary as root
$ sudo yate -vvvvvv
Yate (23748) is starting Tue Oct 20 14:03:52 2015
2015-10-20_14:03:52.041354 <ALL> Plugin::Plugin("filetransfer",false) [0x7f0204349880]
Loaded module File Transfer
2015-10-20_14:03:52.041441 <ALL> Plugin::Plugin("tonedetect",false) [0x7f0204139300]
Loaded module ToneDetector
2015-10-20_14:03:52.041509 <ALL> Plugin::Plugin("fileinfo",false) [0x7f0203f30c40]
Loaded module FileInfo
2015-10-20_14:03:52.041603 <ALL> Plugin::Plugin("extmodule",false) [0x7f0203d259c0]
Loaded module ExtModule
2015-10-20_14:03:52.041916 <ALL> Plugin::Plugin("javascript",true) [0x7f0203b11640]
Loaded module Javascript
2015-10-20_14:03:52.041998 <ALL> Plugin::Plugin("moh",false) [0x7f0203694440]
Loaded module MOH
2015-10-20_14:03:52.042148 <ALL> Plugin::Plugin("isaccodec",false) [0x7f020348a780]
Loaded module iSAC floating point - based on WebRTC iSAC library version 4.3.0 (SPL version 1.2.0)
2015-10-20_14:03:52.042348 <ALL> Plugin::Plugin("iax",false) [0x7f020324e5c0]
Loaded module YIAX
2015-10-20_14:03:52.042522 <ALL> Plugin::Plugin("yrtp",false) [0x7f0203012280]
Loaded module YRTP
2015-10-20_14:03:52.042643 <ALL> Plugin::Plugin("cdrfile",true) [0x7f0202deb240]
Loaded module CdrFile
2015-10-20_14:03:52.042750 <ALL> Plugin::Plugin("gsmcodec",false) [0x7f0202be6180]
Loaded module GSM - based on libgsm-1.0.10
2015-10-20_14:03:52.042836 <ALL> Plugin::Plugin("regexroute",false) [0x7f02027d1f80]
Loaded module RegexRoute
2015-10-20_14:03:52.042914 <ALL> Plugin::Plugin("callgen",false) [0x7f02025c58c0]
Loaded module Call Generator
2015-10-20_14:03:52.042975 <ALL> Plugin::Plugin("pbx",false) [0x7f02023ba540]
Loaded module PBX
2015-10-20_14:03:52.043061 <ALL> Plugin::Plugin("conf",false) [0x7f02021b34c0]
Loaded module Conference
2015-10-20_14:03:52.043150 <ALL> Plugin::Plugin("rmanager",false) [0x7f0201fa4900]
Loaded module RManager
2015-10-20_14:03:52.043240 <ALL> Plugin::Plugin("wave",false) [0x7f0201d949c0]
Loaded module WaveFile
2015-10-20_14:03:52.043326 <ALL> Plugin::Plugin("analyzer",false) [0x7f0201b83480]
Loaded module Analyzer
2015-10-20_14:03:52.043401 <ALL> Plugin::Plugin("stun",false) [0x7f0201978400]
Loaded module YSTUN
2015-10-20_14:03:52.043652 <ALL> Plugin::Plugin("sip",false) [0x7f020176d980]
Loaded module SIP Channel
2015-10-20_14:03:52.043754 <ALL> Plugin::Plugin("callfork",false) [0x7f02015084c0]
Loaded module Call Forker
2015-10-20_14:03:52.043824 <ALL> Plugin::Plugin("dumb",false) [0x7f02012fd200]
Loaded module DumbChannel
2015-10-20_14:03:52.043895 <ALL> Plugin::Plugin("cdrbuild",false) [0x7f02010f63c0]
Loaded module CdrBuild
2015-10-20_14:03:52.043978 <ALL> Plugin::Plugin("gvoice",false) [0x7f0200ee94c0]
Loaded module GVoice
2015-10-20_14:03:52.044048 <ALL> Plugin::Plugin("enumroute",false) [0x7f0200ce3240]
2015-10-20_14:03:52.044810 <ALL> Plugin::Plugin("jingle",false) [0x7f0200adbac0]
Loaded module YJingle
2015-10-20_14:03:52.044949 <ALL> Plugin::Plugin("msgsniff",false) [0x7f0200646540]
Loaded module MsgSniffer
2015-10-20_14:03:52.045010 <ALL> Plugin::Plugin("cdrcombine",false) [0x7f02004409c0]
Loaded module CdrCombine
2015-10-20_14:03:52.045128 <ALL> Plugin::Plugin("ilbccodec",false) [0x7f020023a080]
Loaded module iLBC - based on iLBC reference library
2015-10-20_14:03:52.045223 <ALL> Plugin::Plugin("socks",true) [0x7f0200017a80]
Loaded module YSOCKS
2015-10-20_14:03:52.045369 <ALL> Plugin::Plugin("ilbcwebrtc",false) [0x7f01ffe00600]
Loaded module iLBC - based on WebRTC iLBC library version 1.1.1
2015-10-20_14:03:52.045465 <ALL> Plugin::Plugin("tone",false) [0x7f01ffbe8680]
Loaded module ToneGen
2015-10-20_14:03:52.045484 <tone:ALL> Building comfort noise at level -10
2015-10-20_14:03:52.045537 <tone:ALL> Building tone of 1336 + 941 Hz
2015-10-20_14:03:52.046160 <tone:ALL> Building tone of 1209 + 697 Hz
2015-10-20_14:03:52.046751 <tone:ALL> Building tone of 1336 + 697 Hz
2015-10-20_14:03:52.047344 <tone:ALL> Building tone of 1477 + 697 Hz
2015-10-20_14:03:52.047936 <tone:ALL> Building tone of 1209 + 770 Hz
2015-10-20_14:03:52.048536 <tone:ALL> Building tone of 1336 + 770 Hz
2015-10-20_14:03:52.049135 <tone:ALL> Building tone of 1477 + 770 Hz
2015-10-20_14:03:52.049737 <tone:ALL> Building tone of 1209 + 852 Hz
2015-10-20_14:03:52.050321 <tone:ALL> Building tone of 1336 + 852 Hz
2015-10-20_14:03:52.050906 <tone:ALL> Building tone of 1477 + 852 Hz
2015-10-20_14:03:52.051496 <tone:ALL> Building tone of 1209 + 941 Hz
2015-10-20_14:03:52.052086 <tone:ALL> Building tone of 1477 + 941 Hz
2015-10-20_14:03:52.052677 <tone:ALL> Building tone of 1633 + 697 Hz
2015-10-20_14:03:52.053268 <tone:ALL> Building tone of 1633 + 770 Hz
2015-10-20_14:03:52.053867 <tone:ALL> Building tone of 1633 + 852 Hz
2015-10-20_14:03:52.054458 <tone:ALL> Building tone of 1633 + 941 Hz
2015-10-20_14:03:52.055048 <tone:ALL> Building tone of 2000 + 125 Hz
2015-10-20_14:03:52.056957 <tone:ALL> Building tone of 2000 modulated by 1000 Hz
2015-10-20_14:03:52.059324 <tone:ALL> Building tone of 2010 Hz
2015-10-20_14:03:52.059486 <tone:ALL> Building tone of 1780 Hz
2015-10-20_14:03:52.059799 <ALL> Plugin::Plugin("mux",true) [0x7f01ff9d8640]
Loaded module MUX

Use Yate Telnet Interface

  • Telnet to port 5038 on the host running YateBTS
telnet 5038
Connected to
Escape character is '^]'.
YATE 5.5.1-devel1 r6056 ( ready on localhost.
  • Get a list of registered devices
nib list registered
IMSI            MSISDN
--------------- ---------------
  • Get a list of rejected devices
nib list rejected
IMSI            No attempts register
--------------- ---------------
001010000000002    2
  • Observe rejections in the yate debug output:
2015-10-20_14:18:33.424894 <ybts-signalling:INFO> Received [0xcd0240]
Primitive: PhysicalInfo
Info: 0
Connection: 3

<PhysicalInfo>TA=0 TE=3.000 UpRSSI=1 TxPwr=33 DnRSSIdBm=-83 time=1445365112.943</PhysicalInfo>
2015-10-20_14:18:33.425026 <ybts-signalling:INFO> Received [0xcd0240]
Primitive: L3Message
Info: 0
Connection: 3


  <Message type="LocationUpdatingRequest">
2015-10-20_14:18:33.425160 <ybts-signalling:ALL> Added connection (0x7f01d4001330,3) [0xcd0240]
2015-10-20_14:18:33.425180 <ybts-mm:ALL> Handling LocationUpdatingRequest conn=3: ident=IMSI/001010000000002
LAI=00101_fffe [0xcd0620]
2015-10-20_14:18:33.425194 <ybts-mm:ALL> Added UE (0x7f01d4002b10) TMSI= IMSI=001010000000002 [0xcd0620]
2015-10-20_14:18:33.425206 <ybts-signalling:ALL> Connection 3 set UE (0x7f01d4002b10) TMSI= IMSI=001010000000
002 [0x7f01d4001330]
2015-10-20_14:18:33.425233 <ybts-signalling:INFO> Sending [0xcd0240]
Primitive: L3Message
Info: 0
Connection: 3

  <Message type="IdentityRequest">
2015-10-20_14:18:33.456519 <gsmtrx:ALL> ARFCN[0]: Slot 0. Excessive TOA error=-3 peak/mean=3.21735 count=1 [0
2015-10-20_14:18:33.796915 <gsmtrx:ALL> ARFCN[0]: Slot 6. Excessive TOA errors 8 [0x7f01d8016150]
2015-10-20_14:18:33.875678 <gsmtrx:ALL> ARFCN[0]: Slot 6. Excessive TOA error=-5 peak/mean=3.09984 count=1 [0
2015-10-20_14:18:34.045461 <gsmtrx:ALL> ARFCN[0]: Slot 5. Excessive TOA error=-5 peak/mean=3.8067 count=12 [0
2015-10-20_14:18:34.116751 <gsmtrx:INFO> ARFCN[0]: Slot 0. Receiver clipping 1.81203 dB (FN=189757) count=17
2015-10-20_14:18:34.130972 <ybts-signalling:INFO> Received [0xcd0240]
Primitive: PhysicalInfo
Info: 0
Connection: 3

<PhysicalInfo>TA=3 TE=-1.000 UpRSSI=1 TxPwr=30 DnRSSIdBm=-83 time=1445365112.931</PhysicalInfo>
2015-10-20_14:18:34.131057 <ybts-signalling:INFO> Received [0xcd0240]
Primitive: L3Message
Info: 0
Connection: 3

  <Message type="IdentityResponse">
2015-10-20_14:18:34.131165 <ybts:ALL> Started location updating thread for (0x7f01d4002b10) TMSI= IMSI=001010
000000002 [0x7f01d4001b70]
2015-10-20_14:18:34.131317 <nib:INFO> Got user.register for imsi='001010000000002', tmsi=''
2015-10-20_14:18:34.131425 <ybts:ALL> Location updating thread for (0x7f01d4002b10) TMSI= IMSI=00101000000000
2 terminated [0x7f01d4001b70]
2015-10-20_14:18:34.131439 <ybts-mm:ALL> UE (0x7f01d4002b10) TMSI= IMSI=001010000000002 register failed [0xcd
2015-10-20_14:18:34.131469 <ybts-signalling:INFO> Sending [0xcd0240]
Primitive: L3Message
Info: 0
Connection: 3

  <Message type="LocationUpdatingReject">
2015-10-20_14:18:34.131520 <ybts-signalling:ALL> Releasing connection (0x7f01d4001330,3) [0xcd0240]
2015-10-20_14:18:34.131530 <ybts-signalling:INFO> Sending [0xcd0240]
Primitive: ConnRelease
Info: 0
Connection: 3

Setting Wildcard Subscriber (IMSI Catcher Mode)

  • Edit /usr/local/etc/yate/subscribers.conf and set the following:
      * country_code=1 ; 1 for US, 44 for UK
      * regexp=.* ; catch all the things!

  • Start yate

$ yate -v
  • Verify registered devices using telnet interface
$ telnet 5038
Connected to
Escape character is '^]'.
YATE 5.5.1-devel1 r6056 ( ready on localhost.

nib list registered
IMSI            MSISDN
--------------- ---------------
001010000000002   10000002

SIM card setup

  • Install the pre-requisite packages
$ sudo apt-get install python-setuptools swig python-dev libpcsclite-dev pcsc-tools
  • Run pcsc_scan, then plug the device in, and insert a SIM card
$ pcsc_scan
PC/SC device scanner
V 1.4.23 (c) 2001-2011, Ludovic Rousseau <>
Compiled with PC/SC lite version: 1.8.11
Using reader plug'n play mechanism
Scanning present readers...
Waiting for the first reader...
Scanning present readers...
0: MSI StarReader SMART [Smart Card Reader Interface] (20070818000000000) 00 00
Tue Oct 20 19:26:25 2015
Reader 0: MSI StarReader SMART [Smart Card Reader Interface] (20070818000000000) 00 00
  • Download and compile pyscard
$ wget ''
$ tar zxvf pyscard-1.9.0.tar.gz
$ cd pyscard-1.9.0
$ sudo python build_ext install
  • Clone the pySim repository
$ git clone git:// pysim

Setting up SIP

  • Install Asterisk
$ sudo apt-get install asterisk asterisk-core-sounds-en* asterisk-moh-opsound-* asterisk-mp3 asterisk-mysql mysql-server postgresql postgresql-cont
rib asterisk-voicemail asterisk-doc libmyodbc oidentd
  • Install Kamailio SIP proxy software
$ sudo apt-get install kamailio kamailio-geoip-modules
  • Acquire a SIP account with a provider, ideally with a DID
      * I used, and created 2 DIDs, both routed to a single SIP URI (the main account I created when registering)
      * Make sure you set up e911 registration so if anyone on your tower dials 911 the call gets routed and 911 data populated.