Last active
February 15, 2022 21:01
-
-
Save itzg/2c0a8701ae87a032efaf to your computer and use it in GitHub Desktop.
My own simplified wrapper script to create certs and start CoreOS with QEMU/KVM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -e | |
KEY_BITS=2048 | |
CERT_DURATION="-days 1825" | |
init() { | |
is_redo= | |
while [ $# -gt 0 ]; do | |
case $1 in | |
-redo) | |
is_redo=true | |
shift 1 ;; | |
*) | |
echo "Usage: $0 init [ -redo ]" | |
exit 1 ;; | |
esac | |
done | |
if [ "$is_redo" = true ]; then | |
rm -f ca-key.pem ca.pem | |
fi | |
openssl req -new -x509 $CERT_DURATION -extensions v3_ca -keyout ca-key.pem -out ca.pem | |
chmod -c 400 ca-key.pem | |
chmod -c 444 ca.pem | |
echo " | |
Created CA cert andkey | |
" | |
} | |
create() { | |
is_redo= | |
is_server= | |
is_client= | |
if [ $# = 0 ]; then | |
echo " | |
NOTE: use -h to see extra options to use when creating certs | |
" | |
fi | |
while [ $# -gt 0 ]; do | |
case $1 in | |
-name) | |
name=$2 | |
shift 2 ;; | |
-cn) | |
cn=$2 | |
shift 2 ;; | |
-alt) | |
subjectAltName=$2 | |
shift 2 ;; | |
-client) | |
is_client=true | |
shift 1 ;; | |
-server) | |
is_server=true | |
shift 1 ;; | |
-redo) | |
is_redo=true | |
shift 1 ;; | |
*) | |
echo "Usage: $0 create -name NAME -cn SUBJECT [-alt SUBJECT_ALT_NAME] [-server] [-client] [-redo]" | |
exit 1 | |
esac | |
done | |
if [ -z "$name" ]; then | |
read -p "Name: " name | |
fi | |
if [ -z "$cn" ]; then | |
read -p "Subject canonical name: " cn | |
fi | |
if [ "$is_redo" = true ]; then | |
rm -f ${name}-{key,cert}.pem | |
fi | |
cnf_file="extfile.$$.cnf" | |
trap "rm -f $cnf_file" EXIT | |
touch $cnf_file | |
if [ ! -f ${name}-cert.pem ]; then | |
openssl req -subj "/CN=$cn" -new -nodes -keyout ${name}-key.pem -out ${name}.csr | |
echo >> $cnf_file <<END | |
subjectKeyIdentifier = hash | |
authorityKeyIdentifier = keyid | |
END | |
if [ -n "$subjectAltName" ]; then | |
if [[ ! $subjectAltName =~ ((email|URI|DNS|RID|IP|dirName|otherName):) ]]; then | |
echo " | |
ERROR: subjectAltName is missing types. See http://bit.ly/subjectAltName | |
" > /dev/stderr | |
exit 2 | |
fi | |
echo "subjectAltName = $subjectAltName" >> $cnf_file | |
fi | |
if [ "$is_client" = true -a "$is_server" = true ]; then | |
echo "extendedKeyUsage = serverAuth,clientAuth" >> $cnf_file | |
elif [ "$is_client" = true ]; then | |
echo "extendedKeyUsage = clientAuth" >> $cnf_file | |
elif [ "$is_server" = true ]; then | |
echo "extendedKeyUsage = serverAuth" >> $cnf_file | |
fi | |
if [ -f $cnf_file ]; then | |
ext_arg="-extfile $cnf_file" | |
fi | |
openssl x509 -req $CERT_DURATION -in ${name}.csr -CA ca.pem -CAkey ca-key.pem \ | |
-CAcreateserial -out ${name}-cert.pem $ext_arg | |
rm ${name}.csr | |
chmod -c 444 ${name}-cert.pem | |
fi | |
echo " | |
Created key and cert for $name | |
" | |
} | |
ssh() { | |
name= | |
host= | |
idfile= | |
user="core" | |
# Transfer to /tmp by default since $HOME might be read only filesystem | |
remote_path="/tmp" | |
if [ $# = 0 ]; then | |
echo " | |
NOTE: use -h to see extra options to use when transferring certs | |
" | |
fi | |
while [ $# -gt 0 ]; do | |
case $1 in | |
-host) | |
host=$2 | |
shift 2 ;; | |
-user) | |
user=$2 | |
shift 2 ;; | |
-path) | |
remote_path=$2 | |
shift 2 ;; | |
-name) | |
name=$2 | |
shift 2 ;; | |
-id) | |
idfile=$2 | |
shift 2 ;; | |
*) | |
echo "Usage: $0 ssh -name NAME -host REMOTE_HOST [ -user $user ] [ -path $remote_path ] [ -id IDFILE ]" | |
exit 1 | |
esac | |
done | |
if [ -z "$name" ]; then | |
read -p "Name: " name | |
fi | |
if [ ! -f ${name}-cert.pem ]; then | |
create -name $name | |
fi | |
if [ -z "$host" ]; then | |
host=$(openssl x509 -in ${name}-cert.pem -noout -subject -nameopt oneline | awk '{print $4}') | |
read -p "Remote host [$host]: " ans | |
host=${ans:-$host} | |
fi | |
if [ -n "$idfile" ]; then | |
id_args="-i $idfile" | |
fi | |
if scp $id_args ca.pem ${name}-key.pem ${name}-cert.pem ${user}@${host}:${remote_path} ; then | |
echo " | |
Transferred cert and key for $name and CA cert to ${remote_path} on ${user}@${host} | |
" | |
fi | |
} | |
bundle() { | |
name= | |
while [ $# -gt 0 ]; do | |
case $1 in | |
-name) | |
name=$2 | |
shift 2 ;; | |
*) | |
echo "Usage: $0 bundle -name NAME" | |
exit 1 | |
esac | |
done | |
if [ -z "$name" ]; then | |
read -p "Name: " name | |
fi | |
if [ ! -f ${name}-cert.pem ]; then | |
create -name $name | |
fi | |
out=/tmp/${name}-certs.tgz | |
tar zcf $out ca.pem ${name}-key.pem ${name}-cert.pem | |
chmod -c 400 $out | |
echo " | |
Bundled certificate files in $out | |
" | |
} | |
mkdir -p .certs | |
cd .certs | |
case $1 in | |
init|create|ssh|bundle) | |
cmd="$1" | |
shift | |
$cmd $@ | |
;; | |
*) | |
echo "Usage: $0 init|create|ssh|bundle" | |
;; | |
esac |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#cloud-config | |
ssh_authorized_keys: | |
- ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAkzIkq5Ez6lgyUZAtAEd+36SrP0cdP7K87hcl65Gt/c3K0BIqfJIBXcBV9D3EsJIJhaLu0jgXVxO3pPIdIlheY4NAYim9CjF9BDCbuCF5bxZDSXTvedv3+tBiu+qCblXsGzf7LFv8r0yP1rxVnISc0Vi3/r65ywu/gIGVvntRv1/GeztwYQwC4Jti2Lr90ZVnmQ1edTVKkP+CAJX6YyeKMwHNmutjaBSdMmZfG09HapPN8PDX2XSQoRirfUhemuc+hfI+AMGP/sjj5gXLn+JqKTpR9jjfSJ6Fz5RBxg0xL0tUBKSWfFAy5XZXa07gAOb5ODp+fPoqeOt9SL4eLAwiXQ== coreos-access | |
coreos: | |
units: | |
- name: 00-static.network | |
runtime: true | |
content: | | |
[Match] | |
Name=eth0 | |
[Network] | |
DNS=$dns | |
Address=$address_net | |
Gateway=$gateway | |
[Route] | |
Destination=169.254.0.0/16 | |
Scope=link | |
- name: 01-link-local.network | |
runtime: true | |
content: | | |
[Match] | |
Name=eth1 | |
[Network] | |
Address=169.254.169.254 | |
LinkLocalAddressing=no | |
IPv4LLRoute=true | |
- name: format-ephemeral.service | |
command: start | |
content: | | |
[Unit] | |
Description=Formats the ephemeral drive | |
[Service] | |
Type=oneshot | |
RemainAfterExit=yes | |
ExecStart=/usr/sbin/wipefs -f /dev/vdb | |
ExecStart=/usr/sbin/mkfs.btrfs -f /dev/vdb | |
- name: var-lib-docker.mount | |
command: start | |
content: | | |
[Unit] | |
Description=Mount ephemeral to /var/lib/docker | |
Requires=format-ephemeral.service | |
After=format-ephemeral.service | |
Before=docker.service | |
[Mount] | |
What=/dev/vdb | |
Where=/var/lib/docker | |
Type=btrfs | |
hostname: $name |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#cloud-config | |
ssh_authorized_keys: | |
- ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAkzIkq5Ez6lgyUZAtAEd+36SrP0cdP7K87hcl65Gt/c3K0BIqfJIBXcBV9D3EsJIJhaLu0jgXVxO3pPIdIlheY4NAYim9CjF9BDCbuCF5bxZDSXTvedv3+tBiu+qCblXsGzf7LFv8r0yP1rxVnISc0Vi3/r65ywu/gIGVvntRv1/GeztwYQwC4Jti2Lr90ZVnmQ1edTVKkP+CAJX6YyeKMwHNmutjaBSdMmZfG09HapPN8PDX2XSQoRirfUhemuc+hfI+AMGP/sjj5gXLn+JqKTpR9jjfSJ6Fz5RBxg0xL0tUBKSWfFAy5XZXa07gAOb5ODp+fPoqeOt9SL4eLAwiXQ== coreos-access | |
coreos: | |
units: | |
- name: 00-static.network | |
runtime: true | |
content: | | |
[Match] | |
Name=eth0 | |
[Network] | |
DNS=$dns | |
Address=$address_net | |
Gateway=$gateway | |
[Route] | |
Destination=169.254.0.0/16 | |
Scope=link | |
- name: format-ephemeral.service | |
command: start | |
content: | | |
[Unit] | |
Description=Formats the ephemeral drive | |
[Service] | |
Type=oneshot | |
RemainAfterExit=yes | |
ExecStart=/usr/sbin/wipefs -f /dev/vdb | |
ExecStart=/usr/sbin/mkfs.btrfs -f /dev/vdb | |
- name: var-lib-docker.mount | |
command: start | |
content: | | |
[Unit] | |
Description=Mount ephemeral to /var/lib/docker | |
Requires=format-ephemeral.service | |
After=format-ephemeral.service | |
Before=docker.service | |
[Mount] | |
What=/dev/vdb | |
Where=/var/lib/docker | |
Type=btrfs | |
hostname: $name |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Requires: | |
# - libguestfs-tools | |
CHANNEL=alpha | |
RAND_ID=$(openssl rand -hex 4) | |
MAC_ADDR=$(echo $RAND_ID| awk '{printf "52:54:%02s:%02s:%02s:%02s", substr($0,1,2), substr($0,3,2), substr($0,5,2), substr($0,7,2)}') | |
CONFIG_FILE="cloud-config.yml" | |
NAME="coreos-${RAND_ID}" | |
MEM="1024M" | |
SMP=2 | |
IMG=coreos_production_qemu_image.img | |
networking() { | |
case $1 in | |
allocate) | |
if [ ! -f ips.db ]; then | |
read -p "IP Pool Prefix: " prefix | |
read -p "IP Pool Start : " startVal | |
read -p "IP Pool End : " endVal | |
for (( i = $startVal ; i <= $endVal ; ++i )); do | |
echo "${prefix}${i}" >> ips.db | |
done | |
if [ -n "$SUDO_USER" ]; then | |
chown ${SUDO_USER}: ips.db | |
fi | |
fi | |
awk -f - ips.db > /tmp/ips.db.$$.selected 2> /tmp/ips.db.$$.remainder <<END | |
NR == 1 { print > "/dev/stdout" } | |
NR > 1 { print > "/dev/stderr" } | |
END | |
# Preserves ownership | |
cp /tmp/ips.db.$$.remainder ips.db | |
ip=$(cat /tmp/ips.db.$$.selected) | |
rm /tmp/ips.db.$$.* | |
export ADDRESS=$ip | |
export ADDRESS_NET=$ip/24 | |
export PUBLIC_IPV4=$ip | |
export DNS=209.18.47.61 | |
export GATEWAY=192.168.0.1 | |
;; | |
release) | |
echo $2 >> ips.db | |
;; | |
esac | |
} | |
storage() { | |
case $1 in | |
allocate) | |
lvcreate --size $2 --name $RAND_ID vg_qemu | |
STORAGE_LV=vg_qemu/$RAND_ID | |
#parted -s /dev/${STORAGE_LV} mklabel gpt | |
#parted -s /dev/${STORAGE_LV} mkpart primary 0 "100%" 2> /dev/null | |
;; | |
release) | |
lvremove -f $2 | |
;; | |
esac | |
} | |
teardown() { | |
config_drive=$1 | |
address_to_release=$2 | |
rm -rf $config_drive | |
networking release $address_to_release | |
} | |
while [ $# -gt 0 ]; do | |
case "$1" in | |
-storage) | |
if [ $# -lt 2 ]; then | |
echo "-storage requires ephemeral storage size" | |
exit 1 | |
fi | |
STORAGE_SIZE=$2 | |
shift 2 ;; | |
-channel) | |
if [ $# -lt 2 ]; then | |
echo "-channel requires channel name" | |
exit 1 | |
fi | |
CHANNEL=$2 | |
shift 2 ;; | |
-name) | |
if [ $# -lt 2 ]; then | |
echo "-name requires the VM name" | |
exit 1 | |
fi | |
NAME=$2 | |
shift 2 ;; | |
-extra-net) | |
EXTRA_NET=true | |
shift 1 ;; | |
-cloud-config) | |
if [ $# -lt 2 ]; then | |
echo "-cloud-config requires the cloud-config YML path" | |
exit 1 | |
fi | |
CONFIG_FILE=$2 | |
shift 2 ;; | |
--) | |
shift | |
break ;; | |
*) | |
break ;; | |
esac | |
done | |
set -e | |
if [ ! -f $IMG ]; then | |
wget http://${CHANNEL}.release.core-os.net/amd64-usr/current/${IMG}.bz2 -O - | bzcat > $IMG | |
if [ -n "$SUDO_USER" ]; then | |
chown ${SUDO_USER}: $IMG | |
fi | |
fi | |
if [ ! -f ${CONFIG_FILE} ]; then | |
echo "The user data file ${CONFIG_FILE} does not exist." | |
echo "Place there or pass path as first argument." | |
exit 1 | |
fi | |
networking allocate | |
TEARDOWN="$TEARDOWN networking release $ADDRESS ;" | |
if [ -n "$STORAGE_SIZE" ]; then | |
storage allocate $STORAGE_SIZE | |
TEARDOWN="$TEARDOWN storage release $STORAGE_LV ;" | |
fi | |
NODE_IMG="${NAME}-${IMG}" | |
cp $IMG $NODE_IMG | |
TEARDOWN="$TEARDOWN rm -f $NODE_IMG ;" | |
CONFIG_DRIVE=$(mktemp -t -d coreos-configdrive.XXXXXXXXXX) | |
TEARDOWN="$TEARDOWN rm -rf $CONFIG_DRIVE ;" | |
trap "$TEARDOWN" EXIT | |
mkdir -p "${CONFIG_DRIVE}/openstack/latest" | |
sed -f - ${CONFIG_FILE} > ${CONFIG_DRIVE}/openstack/latest/user_data <<END | |
s#\$address_net#$ADDRESS_NET#; | |
s/\$public_ipv4/$PUBLIC_IPV4/; | |
s/\$private_ipv4/$PUBLIC_IPV4/; | |
s/\$gateway/$GATEWAY/; | |
s/\$dns/$DNS/; | |
s/\$name/$NAME/; | |
END | |
#cat ${CONFIG_DRIVE}/openstack/latest/user_data | |
TAP_DEV=tap${RAND_ID} | |
QEMU=qemu-system-x86_64 | |
IMG_ARGS="-drive if=virtio,file=${NODE_IMG}" | |
CFG_ARGS="-fsdev local,id=conf,security_model=none,readonly,path=${CONFIG_DRIVE} -device virtio-9p-pci,fsdev=conf,mount_tag=config-2" | |
MACHINE_ARGS="-machine accel=kvm -cpu host -smp ${SMP}" | |
DISPLAY_ARGS="-nographic" | |
NET_ARGS="-device virtio-net,netdev=net0,mac=${MAC_ADDR} -netdev tap,id=net0,ifname=tap${RAND_ID}" | |
if [ "$EXTRA_NET" = true ]; then | |
RAND_ID2=$(openssl rand -hex 4) | |
MAC_ADDR2=$(echo $RAND_ID2| awk '{printf "52:54:%02s:%02s:%02s:%02s", substr($0,1,2), substr($0,3,2), substr($0,5,2), substr($0,7,2)}') | |
NET_ARGS="$NET_ARGS -device virtio-net,netdev=net1,mac=${MAC_ADDR2} -netdev tap,id=net1,ifname=tap${RAND_ID2}" | |
fi | |
if [ -n "$STORAGE_LV" ]; then | |
STORAGE_ARGS="-drive file=/dev/${STORAGE_LV},if=virtio,index=1" | |
fi | |
echo " | |
Launching $NAME with ID $RAND_ID... | |
" | |
set -x | |
$QEMU -name "$NAME" -m $MEM $IMG_ARGS $CFG_ARGS $NET_ARGS $STORAGE_ARGS $MACHINE_ARGS $DISPLAY_ARGS |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment