From 1ae25a097223251c7d32bbb514b36779fed81edb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Felix=20D=C3=B6rre?= Date: Sun, 16 Jul 2017 22:34:55 +0200 Subject: [PATCH] add: script for an admin to manage certificates Change-Id: Ie85f6686f1e04314aafc0726704d5406968cc1e7 --- commands | 6 +- manager/.gitignore | 3 + manager/admin-manage-certificates | 131 ++++++++++++++++++++++++++++++ manager/config | 22 +++++ 4 files changed, 159 insertions(+), 3 deletions(-) create mode 100755 manager/admin-manage-certificates diff --git a/commands b/commands index 6f6d00d..ef9ba7c 100755 --- a/commands +++ b/commands @@ -57,9 +57,9 @@ if [[ $com == "update certs" || $com == "force update certs" ]]; then rmdir $folder elif [[ $com == "reload certs" ]]; then sudo puppet apply /etc/puppet/code/environments/production/manifests --verbose - sudo lxc-attach -n front-nginx -- puppet agent --verbose --test - sudo lxc-attach -n quiz -- puppet agent --verbose --test - sudo lxc-attach -n gigi -- puppet agent --verbose --test + sudo lxc-attach -n front-nginx -- puppet agent --verbose --onetime + sudo lxc-attach -n quiz -- puppet agent --verbose --onetime + sudo lxc-attach -n gigi -- puppet agent --verbose --onetime elif [[ $com == "update crls" ]]; then if ! tar xv -C /data/crl; then echo "requiring tar" diff --git a/manager/.gitignore b/manager/.gitignore index 4b5bdb3..f19bffc 100644 --- a/manager/.gitignore +++ b/manager/.gitignore @@ -6,3 +6,6 @@ /vm-key /vm-key.pub /root.crt +/admin-key +/admin-key.pub +/.tmpdata diff --git a/manager/admin-manage-certificates b/manager/admin-manage-certificates new file mode 100755 index 0000000..2a6c4c0 --- /dev/null +++ b/manager/admin-manage-certificates @@ -0,0 +1,131 @@ +#!/bin/bash +targetHost=$1 +targetHost=${targetHost%/} +source config +source "$targetHost/config" + +if [[ ! -f admin-key ]]; then + ssh-keygen -t ed25519 -N "" -f admin-key + printf >&2 'Warning: generated admin-key without passphrase\n' +fi + +if [[ "$2" == "install" ]]; then + ssh_target "cat >> modules/hop/files/authorized_keys <<< 'command=\"/home/admin/commands\",restrict,pty $(cat admin-key.pub)'" + ssh_target -t 'sudo lxc-attach -n hop -- bash -c "ssh-keyscan -H 10.0.3.1 > /home/admin/.ssh/known_hosts"' + ssh_target -t 'sudo lxc-attach -n hop -- puppet agent --test --verbose' + exit 0; +fi + + +read_admin_email +read_admin_password + +echo -n "cat >> modules/hop/files/authorized_keys <<< 'command=\"/home/admin/commands\",restrict,pty $(cat admin-key.pub)' && " +echo -n 'sudo lxc-attach -n hop -- bash -c "ssh-keyscan -H 10.0.3.1 > /home/admin/.ssh/known_hosts" && ' +echo 'sudo lxc-attach -n hop -- puppet agent --test --verbose' +read -p "Keys installed? " _ +folder=.tmpdata +mkdir -p $folder +function csrf { + grep csrf | ${1:-cat} | ${2:-cat} | sed "s/.*value='\([^']*\)'.*/\\1/" +} + +[[ -f root.crt ]] || curl -s "http://www.$domain/roots?pem" > root.crt +echo "Opening Gigi connection" +rm -f $folder/cookie-jar +csrf=$(mcurl login -c $folder/cookie-jar|csrf) +if ! [[ -f $folder/cookie-jar ]]; then + echo "Need cookies." >&2 + exit 1; +fi +mcurl login --data-urlencode "username=$admin_email" --data-urlencode "password=$admin_password" --data-urlencode "csrf=$csrf" -c $folder/cookie-jar > /dev/null + +csrf=$(mcurl account/details | csrf "tail -n 1") +mcurl account/details --data "orgaForm=orga&org%3A3=yes&csrf=$csrf" +echo "Gigi is ready" +function issue0 { + options=$1 + csr=$2 + csrf=$(mcurl "account/certs/new" | csrf "head -n 1") + + encoded=$(cat "$csr" | tr '\n' '?' | sed "s/=/%3D/g;s/+/%2B/g;s/\?/%0A/g") + + mcurl account/certs/new -d "CSR=$encoded&process=Next&csrf=$csrf" > /dev/null + + serial=$(mcurl account/certs/new -d "$options&OU=&hash_alg=SHA256&validFrom=now&validity=2y&login=1&description=&process=Issue+Certificate&csrf=$csrf" -v 2>&1 | tee $folder/certlog | grep "< Location: " | sed "s_.*/\([a-f0-9]*\)[^0-9]*_\1_") + echo "Certificate: $serial" + if [[ $serial != "" ]]; then + mcurl "account/certs/$serial.crt?chain&noAnchor" > $folder/cert.crt + return 0; + else + return 1; + fi +} +force="" +if [[ "$2" == "force" ]]; then + force="force " +fi +coproc { + admin_ssh "${force}update certs" + read -r end +} +updated="false" +while true; do + read -r line <&${COPROC[0]} || break; + echo "Command: $line" + if [[ "$line" = "SKIP "* ]]; then + echo "Skipping: $line" + elif [[ "$line" = "ISSUE "* ]]; then + openssl req -out $folder/web.req <&${COPROC[0]} + echo "CSR received, contacting Gigi" + options="profile=server-orga&CN=&SANs=quiz.$domain" + case ${line#ISSUE } in + "modules/gigi/files/gigi") + options="profile=server-orga&CN=&SANs=www.$domain%0Asecure.$domain%0Astatic.$domain%0Aapi.$domain%0A" + ;; + "modules/pootle/files/web") + options="profile=server-orga&CN=&SANs=pootle.$domain" + ;; + "modules/gigi/files/client") + options="profile=mail-orga&CN=&SANs=gigi@$domain" + ;; + "modules/quiz/files/web") + options="profile=server-orga&CN=&SANs=quiz.$domain" + ;; + "modules/gitweb/files/web") + options="profile=server-orga&CN=&SANs=code.$domain" + ;; + "modules/quiz/files/client") + options="profile=client-orga&CN=Quiz+Api+User&SANs=quiz@$domain" + ;; + *) + echo "Unknown certificate in $line, rejecting" + echo "FAIL" >&${COPROC[1]} + continue; + ;; + esac + if issue0 "$options" $folder/web.req; then + echo "gigi issued successfully" + echo "SUCCESS" >&${COPROC[1]} + updated="true" + cnt=$(grep "BEGIN CERTIFICATE" $folder/cert.crt | wc -l) + echo "chain of length $cnt" + echo "$cnt" >&${COPROC[1]} + cat $folder/cert.crt >&${COPROC[1]} + read -r reply <&${COPROC[0]}; + echo $reply + else + echo "FAIL" >&${COPROC[1]} + fi + elif [[ "$line" = "DONE" ]]; then + sleep 1 + break; + fi +done +echo "end process" >&${COPROC[1]} +cat <&${COPROC[0]} +mcurl logout > /dev/null + +if [[ "$updated" == "true" ]]; then + admin_ssh -t "reload certs" +fi diff --git a/manager/config b/manager/config index 6625d0d..e0e6753 100755 --- a/manager/config +++ b/manager/config @@ -64,3 +64,25 @@ function read_activation_link { read -rp "Link: " link printf '%s\n' "$link" } + +# Assign to the variable "admin_email" the email address of the gigi user account that should issue certificates for the system. +function read_admin_email { + read -rp "Gigi user account email for certificates: " admin_email +} + +# Assign to the variable "admin_password" the password of the gigi user account that should issue certificates for the system. +function read_admin_password { + read -rsp "Gigi password: " admin_password +} + +# Connect to gigi using $1 as local url part, the remaining args as additional curl arguments, "root.crt" as root certificate, "$folder/cookie-jar" as cookie-jar. +function mcurl { + local url="$1" + shift + curl -s --cacert root.crt -b $folder/cookie-jar "https://www.$domain/$url" "$@" +} + +# Connect via ssh into the "hop" container. +function admin_ssh { + ssh -i admin-key -p 2222 "admin@$to" "$@" +} -- 2.39.5