From 8d9666e63a8876fa5e85964fe5c1de8d849a9fe3 Mon Sep 17 00:00:00 2001 From: Peter Palfrader Date: Thu, 28 Jul 2016 21:29:58 +0000 Subject: [PATCH] and onionbalance module --- modules/onion/files/tor-onion-name | 137 ++++++++++++++++++ modules/onion/manifests/balance.pp | 32 ++++ modules/onion/manifests/balance_service.pp | 21 +++ modules/onion/manifests/service.pp | 7 +- .../parser/functions/onionbalance_hostname.rb | 14 ++ modules/roles/manifests/init.pp | 3 + 6 files changed, 211 insertions(+), 3 deletions(-) create mode 100644 modules/onion/files/tor-onion-name create mode 100644 modules/onion/manifests/balance.pp create mode 100644 modules/onion/manifests/balance_service.pp create mode 100644 modules/puppetmaster/lib/puppet/parser/functions/onionbalance_hostname.rb diff --git a/modules/onion/files/tor-onion-name b/modules/onion/files/tor-onion-name new file mode 100644 index 000000000..8803e0ede --- /dev/null +++ b/modules/onion/files/tor-onion-name @@ -0,0 +1,137 @@ +#!/bin/bash + +# Obtain the hidden service name from a tor hidden service RSA key + +# Copyright (c) 2016 Peter Palfrader +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +set -e +set -u +set -o pipefail + +usage() { + echo "$0 [-p] [hidden service RSA key]" + echo " Computes the Tor onion hostname from a given RSA public or private key." + echo " Use -p to indicate you are passing a public key. If none is given as an" + echo " argument, one is read from stdin." +} + +umask 077 +export LC_ALL=C + +if ! command -v openssl >/dev/null 2>&1 ; then + echo >&2 "This program needs the openssl command line tool". + exit 1 +fi + +tempdir="" +cleanup() { + cd / + if [ -n "$tempdir" ]; then + rm -rf "$tempdir" + fi +} +trap 'cleanup' EXIT +tempdir="$(mktemp -d)" + +PUBIN="" + +while getopts "ph" OPTION +do + case $OPTION in + h) + usage + exit + ;; + p) + PUBIN=1 + ;; + *) + usage >&2 + exit 1 + ;; + esac +done +shift $(($OPTIND - 1)) + +if [ "$#" = 0 ]; then + KEY="$tempdir/key" + cat > "$KEY" +elif [ "$#" = 1 ]; then + KEY="$1" + shift +else + usage >&2 + exit 1 +fi + +if [ -z "$PUBIN" ]; then + PKEY="$tempdir/pkey" + if ! openssl rsa -pubout < "$KEY" 2>&1 > "$PKEY" | (grep -Fxv 'writing RSA key' >&2 || true); then + echo >&2 "Maybe you need to use -p for using a public key?" + exit 1 + fi + KEY="$PKEY" +fi + +mod="$(openssl rsa -pubin < "$KEY" -modulus -noout | cut -d= -f 2)" +exp="$(openssl rsa -pubin < "$KEY" -text -noout | awk '$1=="Exponent:" {print $2}')" +cat > "$tempdir/asn" << EOF +asn1=SEQUENCE:seq_sect +[seq_sect] +field1=INTEGER:0x$mod +field2=INTEGER:$exp +EOF + +openssl asn1parse -genconf "$tempdir/asn" -noout -out "$tempdir/blob" + +python -c 'import base64, hashlib, sys; \ + d = hashlib.sha1(sys.stdin.read()).digest()[0:10]; \ + print "%s.onion"%(base64.b32encode(d).lower(),) + ' < "$tempdir/blob" +#if command -v base32 >/dev/null 2>&1 ; then +# echo $( +# perl -MDigest::SHA -e ' +# $/=undef; +# $d=Digest::SHA::sha1(<>); +# $d=substr($d,0,10); +# print $d; +# ' < "$tempdir/blob" | base32 | tr A-Z a-z +# ).onion +#else +# perl -MDigest::SHA -e ' +# eval("use MIME::Base32 qw( RFC )"); +# if ($@) { +# print STDERR "This program needs either the base32 command line tool or the MIME::Base32 perl module.\n"; +# exit 1; +# } +# $/=undef; +# $d=Digest::SHA::sha1(<>); +# $d=substr($d,0,10); +# print lc(MIME::Base32::encode($d)), ".onion\n" +# ' < "$tempdir/blob" +#fi + +# vim:set et: +# vim:set ts=4: +# vim:set shiftwidth=4: diff --git a/modules/onion/manifests/balance.pp b/modules/onion/manifests/balance.pp new file mode 100644 index 000000000..1c0f9d3f3 --- /dev/null +++ b/modules/onion/manifests/balance.pp @@ -0,0 +1,32 @@ +class onion::balance { + include onion + + package { 'onionbalance': + ensure => installed, + } + service { 'onionbalance': + ensure => running, + require => Package['onionbalance'], + } + + file { '/usr/local/bin/tor-onion-name': + mode => '0555', + source => 'puppet:///modules/onion/tor-onion-name', + } + + concat::fragment { 'onion::torrc_control_header': + target => "/etc/tor/torrc", + order => 10, + content => "ControlPort 9051\n\n", + } + + concat { '/etc/onionbalance/config': + notify => Service['onionbalance'], + require => Package['onionbalance'], + } + concat::fragment { 'onion::balance::config_header': + target => "/etc/onionbalance/config", + order => 05, + content => "service:\n", + } +} diff --git a/modules/onion/manifests/balance_service.pp b/modules/onion/manifests/balance_service.pp new file mode 100644 index 000000000..9348692fa --- /dev/null +++ b/modules/onion/manifests/balance_service.pp @@ -0,0 +1,21 @@ +define onion::balance_service ( +) { + include onion::balance + + $onion_hn = onionbalance_hostname($name) + if ! $onion_hn { + exec { "create-onionbalance-key-${name}": + command => "/bin/true && umask 0027 && openssl genrsa -out /etc/onionbalance/private_keys/${name}.key 1024 && chgrp onionbalance /etc/onionbalance/private_keys/${name}.key", + onlyif => "/bin/true && ! [ -e /etc/onionbalance/private_keys/${name}.key ]", + require => Package['onionbalance'], + } + } + + concat::fragment { "onion::balance::service_header::${name}": + target => "/etc/onionbalance/config", + order => "50-${name}-10", + content => " - # ${name} via ${onion_hn}\n key: private_keys/${name}.key\n instances:\n", + } + + Concat::Fragment <<| tag == "onion::balance::${name}" |>> +} diff --git a/modules/onion/manifests/service.pp b/modules/onion/manifests/service.pp index 57e723f90..a619c1b34 100644 --- a/modules/onion/manifests/service.pp +++ b/modules/onion/manifests/service.pp @@ -7,7 +7,7 @@ define onion::service ( concat::fragment { "onion::torrc_onionservice::${name}": target => "/etc/tor/torrc", - order => 10, + order => 50, content => "HiddenServiceDir /var/lib/tor/onion/${name}\nHiddenServicePort ${port} ${target_address}:${target_port}\n\n", } @@ -15,8 +15,9 @@ define onion::service ( if $onion_hn { @@concat::fragment { "onion::balance::instance::$name::$hostname": target => "/etc/onionbalance/config", - content => " - address: ${onion_hn}\n name: ${hostname}-${name}", - tag => "onion::balance::$name", + content => " - address: ${onion_hn}\n name: ${hostname}-${name}\n", + order => "50-${name}-20", + tag => "onion::balance::$name", } } } diff --git a/modules/puppetmaster/lib/puppet/parser/functions/onionbalance_hostname.rb b/modules/puppetmaster/lib/puppet/parser/functions/onionbalance_hostname.rb new file mode 100644 index 000000000..b43b1d639 --- /dev/null +++ b/modules/puppetmaster/lib/puppet/parser/functions/onionbalance_hostname.rb @@ -0,0 +1,14 @@ +module Puppet::Parser::Functions + newfunction(:onionbalance_hostname, :type => :rvalue) do |args| + servicename = args.shift() + + onionbalance_hostname_fact = lookupvar('onionbalance_hostname') + + require 'json' + parsed = JSON.parse(onionbalance_hostname_fact) + return parsed[servicename] + end +end +# vim:set ts=2: +# vim:set et: +# vim:set shiftwidth=2: diff --git a/modules/roles/manifests/init.pp b/modules/roles/manifests/init.pp index 441e20ccd..5efac975e 100644 --- a/modules/roles/manifests/init.pp +++ b/modules/roles/manifests/init.pp @@ -359,4 +359,7 @@ class roles { target_port => 81, } } + if $::hostname in [olin] { + onion::balance_service { 'ftp.debian.org': } + } } -- 2.20.1