]> WPIA git - infra.git/commitdiff
add: script and instructions for automated setup
authorFelix Dörre <felix@dogcraft.de>
Tue, 21 Mar 2017 09:41:48 +0000 (10:41 +0100)
committerFelix Dörre <felix@dogcraft.de>
Wed, 22 Mar 2017 21:06:22 +0000 (22:06 +0100)
Change-Id: I0757795270b97d00dd7cf1f1f5414e0b3b796939

bootstrap-user [changed mode: 0644->0755]
manager/.gitignore [new file with mode: 0644]
manager/README.md [new file with mode: 0644]
manager/fetch [new file with mode: 0644]
manager/installNRE [new file with mode: 0755]
manager/setup [new file with mode: 0755]

old mode 100644 (file)
new mode 100755 (executable)
diff --git a/manager/.gitignore b/manager/.gitignore
new file mode 100644 (file)
index 0000000..e2d7f3b
--- /dev/null
@@ -0,0 +1,5 @@
+/nre-results/
+/tricks
+*/config
+*~
+\#*\#
diff --git a/manager/README.md b/manager/README.md
new file mode 100644 (file)
index 0000000..03730d1
--- /dev/null
@@ -0,0 +1,128 @@
+VM-Setup (for CI)
+=================
+
+In the following instruction "this directory" refers to the directory (outside of the VM) where this README.md resides.
+
+1. create a VM with network adapter
+   - recommended more than 16GB HD and 1GB RAM
+2. install debian (stretch) into this VM
+   - with SSHD
+   - recommended: default user, one partition, mostly default settings
+3. create configuration for connecting to this vm
+   - create an ssh-key (may have a passphrase) named "vm-key" in this directory
+   - install the public key into the VMs authorized_keys-file (e.g. with `ssh-copy-id`)
+   - create a file named `<myconfname>/config` containing `to=user@vm-connection-info`
+   (steps 4 and 5 can be executed by script init-vm)
+4. connect to this VM and install CI-SSH-Key (generate one named vm-key in this directory)
+   - (optional) disable SSH-Password Auth (in the VM)
+   - (optional; required for CI) disable sudo requiring a password. (in the VM)
+5. (optional) install some packages for CI speedup (in the VM)
+6. (optional) Now may be a good time to poweroff the VM, take a snapshot and power it back on.
+7. run `./setup <myconfname> [fresh]`
+   - `fresh` instructs the script to reset the VM before installing
+
+
+Creating a tricks script
+------
+
+You may create a script named `tricks` in this directory. This script will be executed after initial bootstrap is completed but before bootstrap-user is invoked. This script may therefore apply some site-local patches to the system to get everything ready for initializing gigi's database. Things to do here would be:
+- setting up additional tunnels
+- patching gigi's public suffix list to accept your domain
+- other stuff your site requires
+
+Here are some useful snippets that you might want to include in your tricks file:
+
+
+### Adding your own domain as public suffix
+
+The bootstrap procedure requires Gigi’s domain to be exactly one level below a *public suffix*,
+for example `someca.de` or `someca.co.uk`.
+If you do not have many such domains to spare,
+you can edit Gigi’s public suffix list to add a domain controlled by you to it (for example `gigi.yourname.com`),
+and then run Gigi instances under `test1.gigi.yourname.com`, `test2.gigi.yourname.com` etc.
+In this example, `YOUR.PUBLIC.SUFFIX` below would be `gigi.yourname.com`.
+
+```
+if ! sudo lxc-attach -n gigi -- unzip -c /usr/share/java/gigi.jar club/wpia/gigi/util/effective_tld_names.dat | grep "YOUR.PUBLIC.SUFFIX" > /dev/null; then
+    echo "patching public suffixes"
+    sudo lxc-attach -n gigi -- apt-get update
+    sudo lxc-attach -n gigi -- apt-get install --no-install-recommends -y unzip zip
+    sudo lxc-attach -n gigi bash <<EOF
+cd /tmp
+rm -fR club
+unzip /usr/share/java/gigi.jar club/wpia/gigi/util/effective_tld_names.dat
+printf 'YOUR.PUBLIC.SUFFIX\n' >> club/wpia/gigi/util/effective_tld_names.dat
+zip /usr/share/java/gigi.jar club/wpia/gigi/util/effective_tld_names.dat
+rm -fR club
+EOF
+fi
+```
+
+### Forwarding IPv6 traffic to nginx
+
+All containers inside the VM have an IP address in the private 10.0.0.0/8 block,
+and we set up iptables rules to NAT IPv4 traffic from the VM to the nginx container
+(which then proxies to Gigi).
+This doesn't work if your VM only has a public IPv6 address, for example because its host system is on a residential connection.
+In this case, you can set up another server (with an IPv4 address) to proxy to your system via IPv6,
+and then run services in the VM that forward that IPv6 traffic back to nginx' IPv4 address.
+(You will have to use that server's domain name in your configuration,
+and possibly adjust the public suffix list as described elsewhere in this document.)
+
+```
+if ! [[ -f /etc/systemd/system/forward-to-nginx@.socket ]]; then
+    sudo tee /etc/systemd/system/forward-to-nginx@.socket > /dev/null << 'EOF'
+[Unit]
+Description=Listen on port %i and forward it to the nginx container
+
+[Socket]
+ListenStream=%i
+
+[Install]
+WantedBy=sockets.target
+EOF
+    sudo systemctl daemon-reload
+fi
+if ! [[ -f /etc/systemd/system/forward-to-nginx@.service ]]; then
+    sudo tee /etc/systemd/system/forward-to-nginx@.service > /dev/null << 'EOF'
+[Unit]
+Description=Forward port %i to the nginx container
+Documentation=man:systemd-socket-proxyd(8)
+
+[Service]
+ExecStart=/lib/systemd/systemd-socket-proxyd 10.0.3.13:%i
+
+DynamicUser=yes
+PrivateUsers=yes
+PrivateTmp=yes
+PrivateDevices=yes
+ProtectSystem=strict
+ProtectHome=yes
+NoNewPrivileges=yes
+SystemCallArchitectures=native
+RestrictAddressFamilies=AF_INET
+ProtectKernelModules=yes
+MemoryDenyWriteExecute=yes
+RestrictRealtime=yes
+EOF
+    sudo systemctl daemon-reload
+fi
+sudo systemctl enable forward-to-nginx@{80,443}.socket
+sudo systemctl start forward-to-nginx@{80,443}.socket
+```
+
+
+Other snippets
+--------------
+
+### Restarting the user-bootstrap procedure
+
+If you entered wrong bootstrap users or something went wrong during the final phase of bootstrapping
+(the actual initialization of Gigi’s database with the first administrative accounts)
+you can kill the script and then wipe the database with the following one-liner (run in the VM):
+
+```bash
+sudo lxc-attach -n gigi -- systemctl stop gigi-proxy.{service,socket} cassiopeia-client && sudo lxc-attach -n postgres-primary -- su -c "psql" postgres <<< "DROP DATABASE gigi; CREATE DATABASE gigi;"
+```
+
+Afterwards, you can run `./bootstrap-user` in the VM again.
diff --git a/manager/fetch b/manager/fetch
new file mode 100644 (file)
index 0000000..809b1bf
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+function ssh_target {
+    ssh -i vm-key "$to" "$@"
+}
+source "$1/config"
+
+echo "To: $to"
+echo "Agent: $SSH_AGENT_PID"
+oldpid=$SSH_AGENT_PID
+if [[ $oldpid == "" ]]; then
+    eval $(ssh-agent)
+    ssh-add vm-key
+fi
+
+git fetch "$to:" "HEAD:refs/remotes/$1"
+
+if [[ $oldpid == "" ]]; then
+    eval $(ssh-agent -k)
+fi
+
diff --git a/manager/installNRE b/manager/installNRE
new file mode 100755 (executable)
index 0000000..2116eaf
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+signerLocation=self
+function ssh_target {
+    ssh -i vm-key "$to" "$@"
+}
+
+source "$1/config"
+
+function extract {
+    pattern=$1
+    folder=$2
+    echo "On $to"
+    echo $folder
+    for i in $pattern; do
+        cat $i | ssh_target "mkdir -p $folder && tar xzv -C $folder"
+    done
+}
+shopt -s nullglob
+extract "nre-results/signer-server-*.tar.gz" modules/cassiopeia_signer/files
+extract "nre-results/gigi-*.tar.gz" modules/nre/files
+extract "nre-results/signer-client-*.tar.gz" modules/cassiopeia_client/files
+
+#if [[ "$1" == "signer" ]]; then
+#    extract "generated/signer-server-*.tar.gz" modules/cassiopeia_signer/files
+#elif [[ "$1" == "both" ]]; then
+#else
+#    echo "installing on $target"
+#    extract "generated/gigi-*.tar.gz" modules/nre/files
+#    extract "generated/signer-client-*.tar.gz" modules/cassiopeia_client/files
+#    #todo generate this with mkcassiopeia
+#    extract "generated/signer.tar.gz" modules/cassiopeia/files
+#fi
diff --git a/manager/setup b/manager/setup
new file mode 100755 (executable)
index 0000000..9481c85
--- /dev/null
@@ -0,0 +1,180 @@
+#!/bin/bash
+signerLocation=self
+devPkgs=""
+targetHost="$1"
+
+function ssh_target {
+    ssh -i vm-key "$to" "$@"
+}
+
+function install_nre {
+    ./installNRE "$targetHost"
+}
+function read_activation_link {
+    read -rp "Link: " link
+    printf '%s\n' "$link"
+}
+function configure {
+    ssh_target -t 'bash conf-puppet --force'
+    ssh_target 'sed -i "s%\$signerLocation = '".*'"'%\$signerLocation = '"'$signerLocation'"'%" environments/production/manifests/ip.pp'
+}
+function do_reset_vm {
+    read -rp "Please reset your VM and confirm by pressing enter." _
+}
+function execute-bootstrap-user {
+    ssh_target -t 'bash bootstrap-user'
+}
+
+source "$targetHost/config"
+
+eval $(ssh-agent)
+trap "eval \$(ssh-agent -k)" EXIT
+ssh-add vm-key
+function title {
+    printf '\e]0;%s\007' "$1"
+}
+
+function reset_vm {
+    if ! [[ -f reset-vm-key ]]; then
+        ssh-keygen -f reset-vm-key -t ed25519 -N ""
+    fi
+    title 'S0: VM-reset'
+    printf "command=\"bash reset1\" "
+    cat reset-vm-key.pub
+
+    echo "Powering off"
+    ssh_target -t 'ip a show dev enp0s3; sudo poweroff'
+
+    echo "Resetting VM"
+    do_reset_vm
+    echo "Waiting for VM to respond: "
+    while ! ping -c 1 -W 1 "${to#*@}" > /dev/null; do
+        printf "."
+    done
+    printf "\n"
+    while ! ssh_target 'echo Got into VM'; do
+        sleep 5
+        echo "Please open the VM for my key"
+    done
+}
+function update {
+    title 'S1: apt-get; clone'
+    ssh_target -t "sudo apt-get update && DEBIAN_FRONTEND=noninteractive sudo -E apt-get upgrade -o Dpkg::Options::=\"--force-confold\" -y && sudo apt-get install -y git curl $devPkgs"
+    echo "Git init"
+    ssh_target -t '[[ -d .git ]] || git init;'
+    echo "Git push"
+    git bundle create .fullBundle HEAD
+    cat .fullBundle | ssh_target 'cat > .fullBundle'
+    ssh_target 'git fetch .fullBundle HEAD:refs/remotes/origin/master; rm .fullBundle'
+    rm .fullBundle
+    echo "Git update"
+    ssh_target -t 'if ! git rev-parse --verify master &> /dev/null; then git checkout origin/master; else git merge --ff-only origin/master; fi'
+}
+
+function ensure_nre {
+    first=true
+    while true; do
+        if [[ $first == "true" ]]; then
+            first=false
+        else
+            echo "Please provide the NRE archives in 'nre-results/*.tar.gz' or install them manually into the target."
+            read -p "press enter to continue" tmp
+        fi
+        install_nre
+        if ssh_target '[ -d modules/cassiopeia_client/files/profiles ] && [ -d modules/nre/files/config/profiles ]'; then
+            echo cassiopeia-client and nre-conf files found
+        else
+            echo cassiopeia-client or nre-conf files not found
+            continue
+        fi
+        if [[ "$signerLocation" == "self" ]]; then
+            if ssh_target '[ -d modules/cassiopeia_signer/files/profiles ]'; then
+                echo cassiopeia-signer files found
+            else
+                echo cassiopeia-signer files not found
+                continue
+            fi
+            if ssh_target '[ -d modules/cassiopeia/files ]'; then
+                echo external keys with self-signer?? wrong!
+                #continue
+                #TODO make more intelligent... only allow if key-pair exists
+            fi
+        else
+            if ssh_target '[ -d modules/cassiopeia/files ]'; then
+                echo external keys with self-signer found
+            else
+                echo external keys with self-signer not found
+                continue
+            fi
+        fi
+        break
+    done
+}
+function execute-bootstrap-user-auto {
+
+    coproc {
+        ssh_target -t -t 'bash bootstrap-user'
+    }
+    echo "waiting for bootstrap-user..."
+    if [[ $need_sudo == "true" ]]; then
+        read -sp "sudo: " sudo
+        if [[ $sudo != "" ]]; then
+            printf '%s\n' "$sudo" >&${COPROC[1]}
+        fi
+    fi
+    line=""
+    while [[ $line != "We need a first "* ]]; do
+        if ! read -r line <&${COPROC[0]}; then
+            echo "Error, bootstrap terminated early"
+            exit -1
+        fi
+        echo "Line: $line"
+    done
+    bootstrapper_details >&${COPROC[1]}
+
+    while [[ $line != "You should now have been sent an activation link to the email"* ]]; do
+        if ! read -r line <&${COPROC[0]}; then
+            echo "Error, bootstrap terminated early"
+            exit -1
+        fi
+        printf '%s\n' "$line"
+    done
+    read_activation_link >&${COPROC[1]}
+    cat <&${COPROC[0]}
+}
+
+if [[ "$2" == "fresh" ]]; then
+    reset_vm
+fi
+need_sudo=true
+if ssh_target "sudo -n whoami" > /dev/null; then
+    echo "Sudo does not need a password, great!"
+    need_sudo=false
+fi
+
+update
+if [[ "$2" == "update" ]]; then
+    exit 0;
+fi
+configure
+ensure_nre
+title 'S3: puppet-1'
+ssh_target -t 'sudo ./bootstrap'
+title 'S3: puppet-2'
+ssh_target -t 'sudo ./bootstrap'
+
+[[ -f ../../migrate ]] && ( cd ../.. && bash migrate "$targetHost")
+if [[ -f tricks ]]; then
+    cat tricks | ssh_target 'cat > tricks && chmod +x tricks'
+    ssh_target -t 'bash tricks'
+fi
+
+if [[ $signerLocation == "self" ]] && [[ $(ssh_target 'ps -ef | grep tcpseria[l] | wc -l') != "2" ]]; then
+    echo "Error some services weren't started"
+    exit 1
+fi
+
+execute-bootstrap-user
+
+title 'bash'
+eval $(ssh-agent -k)