and onionbalance module
authorPeter Palfrader <peter@palfrader.org>
Thu, 28 Jul 2016 21:29:58 +0000 (21:29 +0000)
committerPeter Palfrader <peter@palfrader.org>
Thu, 28 Jul 2016 21:29:58 +0000 (21:29 +0000)
modules/onion/files/tor-onion-name [new file with mode: 0644]
modules/onion/manifests/balance.pp [new file with mode: 0644]
modules/onion/manifests/balance_service.pp [new file with mode: 0644]
modules/onion/manifests/service.pp
modules/puppetmaster/lib/puppet/parser/functions/onionbalance_hostname.rb [new file with mode: 0644]
modules/roles/manifests/init.pp

diff --git a/modules/onion/files/tor-onion-name b/modules/onion/files/tor-onion-name
new file mode 100644 (file)
index 0000000..8803e0e
--- /dev/null
@@ -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 (file)
index 0000000..1c0f9d3
--- /dev/null
@@ -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 (file)
index 0000000..9348692
--- /dev/null
@@ -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}" |>>
+}
index 57e723f..a619c1b 100644 (file)
@@ -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 (file)
index 0000000..b43b1d6
--- /dev/null
@@ -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:
index 441e20c..5efac97 100644 (file)
@@ -359,4 +359,7 @@ class roles {
                        target_port => 81,
                }
        }
+       if $::hostname in [olin] {
+               onion::balance_service { 'ftp.debian.org': }
+       }
 }