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 prodcution. 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 pre-requisites 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
- trigger the bootstrap process on the production devices as indicated below
- depending on the network quality, you might want to run the qbee-bootstrap command in a loop until file /var/lib/qbee/inputs/promises.cf is present
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)
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/"
POLICY_DIR="$CLIENT_DIR/var/lib/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" "$POLICY_DIR"
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
# Copy qbee ca in place
cp -a "$QBEE_CA" "$CONF_DIR/ppkeys"
# 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"
cat > ${BOOTSTRAP_FILE} << EOF
{"fqhost": "$CLIENT_NAME","pub_key":$PUB_KEY_JSON,"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.app.qbee.io/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"
echo '{"server":"device.app.qbee.io","port":"443"}' > "$CONF_DIR/qbee-agent.json"
echo "INFO: Provisioned client '$CLIENT_NAME' with config, certs and keys in $CONF_DIR"
echo "INFO: Copy these files over to the device and run '/opt/qbee/bin/qbee-bootstrap -F' to complete bootstrap."
echo "INFO: Depending on the network quality, you might want to run the qbee-bootstrap command in a loop until file /var/lib/qbee/inputs/promises.cf is present"
Then you need to create a bootstrap key that has auto-accept and a group assignment enabled.
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.
On the device you need to run /opt/qbee/bin/qbee-bootstrap -F
until you have the file /var/lib/qbee/inputs/promises.cf
. Depending on the network this might need to be run in a loop.