Create a pool of pre-bootstrapped keys
How to create pre-seeded keys beforehand and transfer these to devices in production
It is possible to pre-create qbee-keys for production. In this tutorial we show you how to bootstrap devices beforehand and transfer the necessary files and keys to devices afterwards. This allows to pre-breed qbee keys that can be used in a production process that does not want to run the bootstrap procedure due to timing or no internet.
Steps and prerequisites for creating qbee-keys:
- a defined bootstrap key that assigns devices to a group and allows auto-accept
- a device to create these keys on
- download the script to your device and run it
You can find our qbee-preseed.sh
script here:
qbee-preseed.sh
#!/usr/bin/env bash
BASEDIR=$(cd $(dirname "$0") && pwd)
HOSTNAME_PREFIX="$(basename $0 .sh)-"
JQ=$(command -v jq)
CURL=$(command -v curl)
OPENSSL=$(command -v openssl)
DEVICE_API_HOST=${DEVICE_API_HOST:-device.app.qbee.io}
DEVICE_VPN_SERVER=${DEVICE_VPN_SERVER:-vpn.app.qbee.io}
CLIENT_NAME="${HOSTNAME_PREFIX}$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13)"
CLIENT_DIR="$BASEDIR/clients/$CLIENT_NAME"
CONF_DIR="$CLIENT_DIR/etc/qbee"
if [[ -d "$CLIENT_DIR" ]]; then
echo "Client $CLIENT_NAME already provisioned, exiting..."
exit 1
fi
if [[ -z "$JQ" ]]; then
echo "Command line utility 'jq' not found, exiting..."
exit 1
fi
if [[ -z "$CURL" ]]; then
echo "Command line utility 'curl' not found, exiting..."
exit 1
fi
if [[ -z "$OPENSSL" ]]; then
echo "Command line utility 'openssl' not found, exiting..."
exit 1
fi
mkdir -p "$CONF_DIR/ppkeys"
mkdir -p "$BASEDIR/common"
PRIVKEY="$CONF_DIR/ppkeys/qbee.key"
PUBKEY="$CONF_DIR/ppkeys/qbee.pub"
CLIENT_CERT="$CONF_DIR/ppkeys/qbee.cert"
QBEE_CA="$BASEDIR/common/qbee-ca-cert.pem"
if [[ ! -f "$QBEE_CA" ]]; then
# Retrieve the qbee ca cert
curl -o "$QBEE_CA" -sfL https://cdn.qbee.io/app/device/ca-cert.pem
fi
# Generate the device priv key
$OPENSSL ecparam -name secp521r1 -genkey -noout -out $PRIVKEY > /dev/null 2>&1
# Generate the device pubkey
$OPENSSL ec -in $PRIVKEY -pubout -out $PUBKEY > /dev/null 2>&1
#key Generate bootstrap info
PUB_KEY_JSON=$(head -c -1 $PUBKEY | jq -R -s -c 'split("\n")')
BOOTSTRAP_FILE="$CLIENT_DIR/bootstrap.tmp.json"
INVENTORY_FILE="$CLIENT_DIR/inventory.tmp.json"
cat > ${BOOTSTRAP_FILE} << EOF
{"fqhost": "$CLIENT_NAME","pub_key":$PUB_KEY_JSON,"host":"$CLIENT_NAME","uqhost":"$CLIENT_NAME"}
EOF
cat > ${INVENTORY_FILE} << EOF
{"system":{"fqhost": "$CLIENT_NAME","host":"$CLIENT_NAME","uqhost":"$CLIENT_NAME"}}
EOF
RESPONSE="{}"
ITER_MAX=5
ITER=0
while [[ "$(echo $RESPONSE | jq -e 'has("cert")')" == "false" ]]; do
RESPONSE=$($CURL -k -sf --cacert $QBEE_CA -XPOST -H "Authorization: token $1" https://${DEVICE_API_HOST}/v1/org/device/xauth/bootstrap -d@${BOOTSTRAP_FILE})
if [[ -z $RESPONSE ]]; then
echo "ERROR: Bootstrap of preseed device $CLIENT_NAME failed, please check that you are using the correct bootstrap key"
rm $CLIENT_DIR -rf
exit 1
fi
((ITER++))
if [[ $ITER -ge $ITER_MAX ]]; then
echo "ERROR: Bootstrap of preseed device $CLIENT_NAME failed after $ITER_MAX attempts, please check that you are using an auto accept bootstrap key"
rm $CLIENT_DIR -rf
exit 1
fi
done
echo $RESPONSE | jq -r '.cert | join("\n")' > "$CLIENT_CERT"
# Post inventory to complete bootstrap
curl -X PUT --cacert $QBEE_CA --key $PRIVKEY --cert $CLIENT_CERT https://${DEVICE_API_HOST}/v1/org/device/auth/inventory/system -d@$INVENTORY_FILE
cat > $CONF_DIR/qbee-agent.json << EOF
{"server":"${DEVICE_API_HOST}","port":"443","vpn_server":"${DEVICE_VPN_SERVER}"}
EOF
echo
echo "INFO: Provisioned client '$CLIENT_NAME' with config, certs and keys in $CONF_DIR"
echo "INFO: Transfer the following files to the preseed host:"
echo "INFO: $CLIENT_CERT -> /etc/qbee/ppkeys/qbee.cert"
echo "INFO: $PRIVKEY -> /etc/qbee/ppkeys/qbee.key"
echo "INFO: $CONF_DIR/qbee-agent.json -> /etc/qbee/qbee-agent.json"
Then you need to create a bootstrap key that has auto-accept.
Then run ./qbee-preseed.sh <bootstrap-key>
.
This will create a client config structure that needs to be copied to the individual device. Each time you run it a new folder will be created that has a new unique ID. Thus you can initiate multiple of these runs below without overwriting the seeded keys and files.