diff --git a/other/examples/remote/cconn/cconn b/other/examples/remote/cconn/cconn new file mode 100755 index 00000000..bc712a0d --- /dev/null +++ b/other/examples/remote/cconn/cconn @@ -0,0 +1,199 @@ +#!/bin/sh -ex + +# Copyright (c) 2021 Alexander Sieg + +# cconn is a transparent wrapper that allows seamless usage of sudo/rsync and +# FreeBSD jails, this makes it possible to configure a FreeBSD by just using +# the host system sshd. +# Configuration is done by throw the cdist invertory system. +# +# +# Installation: +# +# Simply set this script as remote_exec and remote_copy implementation in your +# cdist.cfg. You MUST always pass either copy or exec as the first parameter +# to this script +# +# remote_exec = path/to/cconn exec +# remote_copy = path/to/cconn copy +# +# As cconn uses the cdist inventory system for host specific configuration, it +# ether need to be executed from the directory the contains the inventory +# directory or be setting the INVENTORY environment variable to path were the +# inventory entries are kept. +# +# Usage: +# +# To setup a host to use some form of connection "bending" (e.g. sudo) you need +# to add a single __cconn_options tag to the host inventory file. Options are always a +# key value pair separated by a '='. All options are passed in a single tag and +# a separated by a space. +# +# __cconn_options options: +# +# NOTE: jail_host and iocage_jail can not be used at the same time and will +# lead to a error +# +# jail_host: +# hostname on which the FreeBSD jail resides on. +# +# iocage_host: +# Same as jail_host, but for jails managed by iocage(8) +# +# jail_name: +# By default cconn will use the __target_host as the FreeBSD jail name, set +# this option to override this name +# +# sudo_user: +# Username used to connect to the __target_host, all commands are then +# prefixed with sudo and copy operations are done with rsync +# +# For this work you need to be able to execute all command without password entry. +# sudoers(5) +# %wheel ALL=(ALL) NOPASSWD: ALL +# +#Examples: +# +# inventory/jail.example.com: +# some_other_tag +# __cconn_options jail_host=example.com sudo_user=ada +# + + +#TODO: add sudo_pass and sudo_passfile option to support use without NOPASSWD +#TODO: support SSH connection multiplexing. This requieres a patch to cdist, as +# we need path to the tmp dir. + +log() { + # Uncomment this for debugging + echo "$@" | logger -t "cdist-cconn-$COMMAND" + : +} + +COMMAND="$1"; shift + +if [ -z "$INVENTORY" ]; then + INVENTORY="inventory" +fi + +# shellcheck disable=SC2154 +options="$(sed -n 's/^__cconn_options\(.*\)$/\1/p' "$INVENTORY/$__target_host" | cut -d' ' -f2-)" +tmpcmd=$* +for option in $options; do + # shellcheck disable=SC2046 + set -- $(echo "$option" | tr '=' ' ') + key="$1" + value="$2" + case "$1" in + "jail_host") + JAIL_HOST="$value" + ;; + "iocage_host") + IOCAGE_HOST="$value" + ;; + "jail_name") + JAIL_NAME="$value" + ;; + "sudo_user") + SUDO_USER="$value" + ;; + *) + log "unknown option $key=$value found" + ;; + esac +done +# shellcheck disable=SC2086 +set -- $tmpcmd + +if [ -n "$IOCAGE_HOST" ] && [ -n "$JAIL_HOST" ]; then + echo "WARING: jail_host and iocage_host can't be used at the same time" + log "WARING: jail_host and iocage_host can't be used at the same time" + exit 1 +fi + +TARGET_HOST="$__target_host" +SSH_USER="root" + +if [ -n "$IOCAGE_HOST" ]; then + JAIL_HOST="$IOCAGE_HOST" + + if [ -z "$JAIL_NAME" ]; then + JAIL_NAME="ioc-$(echo "$__target_host" | tr '.' '_')" + else + JAIL_NAME="ioc-$(echo "$JAIL_NAME" | tr '.' '_')" + fi +else + if [ -z "$JAIL_NAME" ]; then + JAIL_NAME="$TARGET_HOST" + fi +fi + +if [ -n "$JAIL_HOST" ]; then + log "INSIDE_JAIL: TRUE" + TARGET_HOST="$JAIL_HOST" + WRAPPER="jexec $JAIL_NAME" +fi + +if [ -n "$SUDO_USER" ]; then + log "SUDO_USER: $SUDO_USER" + WRAPPER="sudo -- $WRAPPER" + SSH_USER="$SUDO_USER" +fi + +log "TARGET_HOST: $TARGET_HOST" +log "@:" "$@" +if [ -n "$JAIL_HOST" ]; then + log "IOCAGE_HOST: $IOCAGE_HOST" + log "JAIL_HOST: $JAIL_HOST" + log "JAIL_NAME: $JAIL_NAME" + log "WRAPPER: $WRAPPER" +fi + +case "$COMMAND" in + "exec") + shift; # remove the jail host name from $@ + ssh -o User="$SSH_USER" -q "$TARGET_HOST" "$WRAPPER $*" + ;; + "copy") + if [ -n "$JAIL_HOST" ]; then + # jls(8) dosen't need root to print this information + jail_root=$(ssh -q "$TARGET_HOST" -- jls -j "$JAIL_NAME" path) + log "JAIL_ROOT: $jail_root" + fi + + if [ -n "$JAIL_HOST" ]; then + set -- "$(echo "$@" | sed "s|$__target_host:|$JAIL_HOST:$jail_root|g")" + fi + + if [ -n "$SUDO_USER" ]; then + # For rsync to do the right thing, the source has to end with "/" if it is + # a directory. The below preprocessor loop takes care of that. + + # second last argument is the source + source_index=$(($#-1)) + index=0 + for arg in "$@"; do + if [ $index -eq 0 ]; then + # reset $@ + set -- + fi + index=$((index+=1)) + if [ $index -eq $source_index ] && [ -d "$arg" ]; then + arg="${arg%/}/" + fi + set -- "$@" "$arg" + done + + rsync --copy-links -e "ssh -o User=$SSH_USER" --rsync-path='sudo rsync' "$@" + else + #shellcheck disable=SC2068 + scp -o "User=$SSH_USER" -q $@ + fi + ;; + *) + echo "unkown command - $COMMAND" + exit 1 + ;; +esac + +log "----"