class OpenvpnPlugin::Openvpn

Public Instance Methods

add_ca_extensions(ca_cert) click to toggle source
# File lib/chef/knife/openvpn.rb, line 85
def add_ca_extensions(ca_cert)
  ef = get_extensions_factory ca_cert, ca_cert
  ca_cert.add_extension(ef.create_extension('basicConstraints', 'CA:TRUE', true))
  ca_cert.add_extension(ef.create_extension('keyUsage', 'keyCertSign, cRLSign', true))
  ca_cert.add_extension(ef.create_extension('subjectKeyIdentifier', 'hash', false))
  ca_cert.add_extension(ef.create_extension('authorityKeyIdentifier', 'keyid:always', false))
end
add_endentity_extensions(entity_cert, ca_cert, is_user = false) click to toggle source
# File lib/chef/knife/openvpn.rb, line 93
def add_endentity_extensions(entity_cert, ca_cert, is_user = false)
  ef = get_extensions_factory entity_cert, ca_cert
  entity_cert.add_extension(ef.create_extension('keyUsage', 'digitalSignature', true))
  entity_cert.add_extension(ef.create_extension('subjectKeyIdentifier', 'hash', false))
  entity_cert.add_extension(ef.create_extension('nsCertType', 'server')) unless is_user
end
check_databag_secret() click to toggle source
# File lib/chef/knife/openvpn.rb, line 40
def check_databag_secret
  databag_secret_file = File.join(Dir.pwd, config[:databag_secret_file]) || Chef::Config[:knife][:secret_file]
  unless File.exist? databag_secret_file
    fail_with "Can't find encrypted databag secret file at #{databag_secret_file}."
  end
end
check_existing_databag(server_name, fail_if_exists = false) click to toggle source
# File lib/chef/knife/openvpn.rb, line 47
def check_existing_databag(server_name, fail_if_exists = false)
  databag_directory = File.join(Dir.pwd, "data_bags/openvpn-#{server_name}")
  if File.directory? databag_directory
    if fail_if_exists # databag exists and we want to create new
      fail_with "Data bag directory #{databag_directory} already exists."
    end
  else
    unless fail_if_exists # no such databag, but we want to use it
      fail_with "Data bag #{databag_directory} not exists."
    end
  end
end
fail_with(error_message) click to toggle source
# File lib/chef/knife/openvpn.rb, line 60
def fail_with(error_message)
  ui.error "Error: #{error_message}"
  exit 1
end
generate_cert_and_key(subject, cert_config, selfsigned = false, ca_cert = nil, ca_key = nil, is_user = false) click to toggle source
# File lib/chef/knife/openvpn.rb, line 100
def generate_cert_and_key(subject, cert_config, selfsigned = false, ca_cert = nil, ca_key = nil, is_user = false)
  key = OpenSSL::PKey::RSA.generate(cert_config['rsa_keysize'])
  cert = OpenSSL::X509::Certificate.new
  cert.version = 2
  cert.serial = Time.now.to_i
  cert.public_key = key.public_key

  cert.not_after = Time.now + (cert_config['years_to_expire'] * 365 * 24 * 60 * 60)
  cert.not_before = Time.now - (24 * 60 * 60)

  if selfsigned
    cert.subject = subject
    cert.issuer = subject
    add_ca_extensions(cert)
    cert.sign(key, OpenSSL::Digest::SHA256.new)
  else
    if ca_cert.nil? || ca_key.nil?
      fail_with "CA key or cert isn't specified"
    end
    cert.subject = subject
    cert.issuer = ca_cert.subject
    add_endentity_extensions(cert, ca_cert, is_user)
    cert.sign(ca_key, OpenSSL::Digest::SHA256.new)
  end

  if is_user
    require 'highline/import'
    passphrase = ask('Enter a passphrase [blank for passphraseless]: ') { |q| q.echo = false }
    unless passphrase == ''
      cipher = OpenSSL::Cipher.new('AES-256-CBC')
      key = key.export(cipher, passphrase)
    end
  end

  [cert, key]
end
get_databag_name(server_name) click to toggle source
# File lib/chef/knife/openvpn.rb, line 191
def get_databag_name(server_name)
  databag_name = "openvpn-#{server_name}"
  databag_name
end
get_databag_path(server_name) click to toggle source
# File lib/chef/knife/openvpn.rb, line 186
def get_databag_path(server_name)
  directory_path = File.join(Dir.pwd, "data_bags/openvpn-#{server_name}")
  directory_path
end
get_extensions_factory(subject_cert, issuer_cert) click to toggle source
# File lib/chef/knife/openvpn.rb, line 78
def get_extensions_factory(subject_cert, issuer_cert)
  factory = OpenSSL::X509::ExtensionFactory.new
  factory.subject_certificate = subject_cert
  factory.issuer_certificate = issuer_cert
  factory
end
issue_crl(revoke_info, serial, lastup, nextup, extensions, issuer, issuer_key, digest) click to toggle source
# File lib/chef/knife/openvpn.rb, line 137
def issue_crl(revoke_info, serial, lastup, nextup, extensions,
              issuer, issuer_key, digest)
  crl = OpenSSL::X509::CRL.new
  crl.issuer = issuer.subject
  crl.version = 1
  crl.last_update = lastup
  crl.next_update = nextup
  revoke_info.each do |rserial, time, reason_code|
    revoked = OpenSSL::X509::Revoked.new

    revoked.serial = if rserial.is_a? OpenSSL::BN
                       rserial
                     else
                       OpenSSL::BN.new(rserial)
                     end

    revoked.time = if time.is_a?
                     time
                   else
                     Time.parse(time)
                   end

    enum = OpenSSL::ASN1::Enumerated(reason_code)
    ext = OpenSSL::X509::Extension.new('CRLReason', enum)
    revoked.add_extension(ext)
    crl.add_revoked(revoked)
  end
  ef = OpenSSL::X509::ExtensionFactory.new
  ef.issuer_certificate = issuer
  ef.crl = crl
  crlnum = OpenSSL::ASN1::Integer(serial)
  crl.add_extension(OpenSSL::X509::Extension.new('crlNumber', crlnum))
  extensions.each do |oid, value, critical|
    crl.add_extension(ef.create_extension(oid, value, critical))
  end
  crl.sign(issuer_key, digest)
  crl
end
load_cert_and_key(cert_str, key_str, force = false) click to toggle source
# File lib/chef/knife/openvpn.rb, line 176
def load_cert_and_key(cert_str, key_str, force = false)
  cert = OpenSSL::X509::Certificate.new cert_str
  key = if force
          key_str
        else
          OpenSSL::PKey::RSA.new key_str
        end
  [cert, key]
end
load_databag_item(databag_name, item_id) click to toggle source
# File lib/chef/knife/openvpn.rb, line 209
def load_databag_item(databag_name, item_id)
  secret = load_databag_secret
  item = Chef::EncryptedDataBagItem.load(databag_name, item_id, secret)
  item
end
load_databag_secret() click to toggle source
# File lib/chef/knife/openvpn.rb, line 72
def load_databag_secret
  databag_secret_file = File.join(Dir.pwd, config[:databag_secret_file]) || Chef::Config[:knife][:secret_file]
  secret = Chef::EncryptedDataBagItem.load_secret(databag_secret_file)
  secret
end
make_name(cn, cert_config) click to toggle source
# File lib/chef/knife/openvpn.rb, line 65
def make_name(cn, cert_config)
  name = OpenSSL::X509::Name.new
  name.add_entry 'CN', cn
  %w(C L O OU ST mail).each { |entry| name.add_entry(entry, cert_config[entry]) }
  name
end
run() click to toggle source
# File lib/chef/knife/openvpn.rb, line 29
def run
  ui.info 'knife openvpn (user|server) action ARGS OPTS'
end
save_databag_item(id, server_name, item_hash, force = false) click to toggle source
# File lib/chef/knife/openvpn.rb, line 196
def save_databag_item(id, server_name, item_hash, force = false)
  databag_path = get_databag_path server_name
  item_hash['id'] = id
  item_path = File.join(databag_path, "#{id}.json")
  secret = load_databag_secret
  encrypted_data = Chef::EncryptedDataBagItem.encrypt_data_bag_item(item_hash, secret)
  if force || !File.exist?(item_path)
    File.write item_path, JSON.pretty_generate(encrypted_data)
  else
    fail_with "#{item_path} already exists"
  end
end