diff options
| -rw-r--r-- | platform.rb | 12 | ||||
| -rw-r--r-- | provider_base/lib/macros.rb | 1 | ||||
| -rw-r--r-- | provider_base/lib/macros/files.rb | 14 | ||||
| -rw-r--r-- | provider_base/lib/macros/keys.rb | 78 | ||||
| -rw-r--r-- | provider_base/services/tor.json | 9 | 
5 files changed, 106 insertions, 8 deletions
| diff --git a/platform.rb b/platform.rb index 06a49b7e..c37b6d29 100644 --- a/platform.rb +++ b/platform.rb @@ -5,7 +5,7 @@  Leap::Platform.define do    self.version = "0.6" -  self.compatible_cli = "1.6.0".."1.99" +  self.compatible_cli = "1.6.1".."1.99"    #    # the facter facts that should be gathered @@ -77,10 +77,12 @@ Leap::Platform.define do      :vagrantfile      => 'test/Vagrantfile',      # node output files -    :hiera            => 'hiera/#{arg}.yaml', -    :node_ssh_pub_key => 'files/nodes/#{arg}/#{arg}_ssh.pub', -    :node_x509_key    => 'files/nodes/#{arg}/#{arg}.key', -    :node_x509_cert   => 'files/nodes/#{arg}/#{arg}.crt', +    :hiera             => 'hiera/#{arg}.yaml', +    :node_ssh_pub_key  => 'files/nodes/#{arg}/#{arg}_ssh.pub', +    :node_x509_key     => 'files/nodes/#{arg}/#{arg}.key', +    :node_x509_cert    => 'files/nodes/#{arg}/#{arg}.crt', +    :node_tor_priv_key => 'files/nodes/#{arg}/tor.key', +    :node_tor_pub_key  => 'files/nodes/#{arg}/tor.pub',      # testing files      :test_client_key     => 'test/cert/client.key', diff --git a/provider_base/lib/macros.rb b/provider_base/lib/macros.rb index 854b92b5..ecc3e6ba 100644 --- a/provider_base/lib/macros.rb +++ b/provider_base/lib/macros.rb @@ -9,6 +9,7 @@ require_relative 'macros/core'  require_relative 'macros/files'  require_relative 'macros/haproxy'  require_relative 'macros/hosts' +require_relative 'macros/keys'  require_relative 'macros/nodes'  require_relative 'macros/secrets'  require_relative 'macros/stunnel' diff --git a/provider_base/lib/macros/files.rb b/provider_base/lib/macros/files.rb index b3ba4a06..958958bc 100644 --- a/provider_base/lib/macros/files.rb +++ b/provider_base/lib/macros/files.rb @@ -48,13 +48,22 @@ module LeapCli      # * if the path does not exist locally, but exists in provider_base, then the default file from      #   provider_base is copied locally. this is required for rsync to work correctly.      # -    def file_path(path) +    def file_path(path, options={})        if path.is_a? Symbol          path = [path, @node.name] +      elsif path.is_a? String +        # ensure it prefixed with files/ +        unless path =~ /^files\// +          path = "files/" + path +        end        end        actual_path = Path.find_file(path)        if actual_path.nil? -        Util::log 2, :skipping, "file_path(\"#{path}\") because there is no such file." +        if options[:missing] +          raise FileMissing.new(Path.named_path(path), options) +        else +          Util::log 2, :skipping, "file_path(\"#{path}\") because there is no such file." +        end          nil        else          if actual_path =~ /^#{Regexp.escape(Path.provider_base)}/ @@ -70,6 +79,7 @@ module LeapCli            actual_path += '/' # ensure directories end with /, important for building rsync command          end          relative_path = Path.relative_path(actual_path) +        relative_path.sub!(/^files\//, '') # remove "files/" prefix          @node.file_paths << relative_path          File.join(Leap::Platform.files_dir, relative_path)        end diff --git a/provider_base/lib/macros/keys.rb b/provider_base/lib/macros/keys.rb new file mode 100644 index 00000000..0d46acb5 --- /dev/null +++ b/provider_base/lib/macros/keys.rb @@ -0,0 +1,78 @@ +# encoding: utf-8 + +# +# Macro for dealing with cryptographic keys +# + +module LeapCli +  module Macro + +    # +    # return the path to the tor public key +    # generating key if it is missing +    # +    def tor_public_key_path(path_name, key_type) +      path = file_path(path_name) +      if path.nil? +        generate_tor_key(key_type) +      end +      return path +    end + +    # +    # return the path to the tor private key +    # generating key if it is missing +    # +    def tor_private_key_path(path_name, key_type) +      path = file_path(path_name) +      if path.nil? +        generate_tor_key(key_type) +      end +      return path +    end + +    # +    # on the command line an onion address can be created +    # from an rsa public key using this: +    # +    #   base64 -d < ./pubkey | sha1sum | awk '{print $1}' | +    #     perl -e '$l=<>; chomp $l; print pack("H*", $l)' | +    #     python -c 'import base64, sys; t=sys.stdin.read(); print base64.b32encode(t[:10]).lower()' +    # +    # path_name is the named path of the tor public key. +    # +    def onion_address(path_name) +      require 'base32' +      require 'base64' +      require 'openssl' +      path = Path.find_file([path_name, self.name]) +      if path && File.exists?(path) +        public_key_str = File.readlines(path).grep(/^[^-]/).join +        public_key     = Base64.decode64(public_key_str) +        sha1sum_string = Digest::SHA1.new.hexdigest(public_key) +        sha1sum_binary = [sha1sum_string].pack('H*') +        Base32.encode(sha1sum_binary.slice(0,10)).downcase +      else +        LeapCli.log :warning, 'Tor public key file "%s" does not exist' % tor_public_key_path +      end +    end + +    private + +    def generate_tor_key(key_type) +      if key_type == 'RSA' +        require 'certificate_authority' +        keypair = CertificateAuthority::MemoryKeyMaterial.new +        bit_size = 1024 +        LeapCli.log :generating, "%s bit RSA Tor key" % bit_size do +          keypair.generate_key(bit_size) +          LeapCli::Util.write_file! [:node_tor_priv_key, self.name], keypair.private_key.to_pem +          LeapCli::Util.write_file! [:node_tor_pub_key, self.name], keypair.public_key.to_pem +        end +      else +        LeapCli.bail! 'tor.key.type of %s is not yet supported' % key_type +      end +    end + +  end +end diff --git a/provider_base/services/tor.json b/provider_base/services/tor.json index fc365a19..87fb9682 100644 --- a/provider_base/services/tor.json +++ b/provider_base/services/tor.json @@ -3,6 +3,13 @@      "bandwidth_rate": 6550,      "contacts": "= [provider.contacts['tor'] || provider.contacts.default].flatten",      "nickname": "= (self.name + secret(:tor_family)).sub('_','')[0..18]", -    "family": "= nodes[:services => 'tor'][:environment => '!local'].field('tor.nickname').join(',')" +    "family": "= nodes[:services => 'tor'][:environment => '!local'].field('tor.nickname').join(',')", +    "hidden_service": null, +    "key": { +      "type": "RSA", +      "public": "= tor_public_key_path(:node_tor_pub_key, tor.key.type) if tor.hidden_service", +      "private": "= tor_private_key_path(:node_tor_priv_key, tor.key.type) if tor.hidden_service", +      "address": "= onion_address(:node_tor_pub_key) if tor.hidden_service" +    }    }  } | 
