Browse Source

handle certificates within hosts automatically

master
Georg Hopp 10 years ago
parent
commit
0b306511dc
  1. 29
      app/controllers/application_controller.rb
  2. 6
      app/controllers/dashboard_controller.rb
  3. 5
      app/controllers/hosts_controller.rb
  4. 41
      app/models/certificate.rb
  5. 41
      app/models/host.rb
  6. 8
      app/models/lxd/api.rb
  7. 13
      app/views/dashboard/index.html.erb

29
app/controllers/application_controller.rb

@ -3,34 +3,5 @@ class ApplicationController < ActionController::Base
# For APIs, you may want to use :null_session instead. # For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception protect_from_forgery with: :exception
def check_cert
@cert = Certificate.find_by active: true
unless @cert
@cert = Certificate.create
@cert.save
end
# update cert on all hosts if close to end.
# This will never fail as lxd is very lax with its certificates.
# It accepts certificates even behind the not_after date.
# As a result a password is only required when a new host is added
# or we remove the current cert completely.
if (@cert.cert.not_after - 1.day + 300) < Time.now
@new_cert = @cert.update
Host.all.each { |host|
host.cert = @cert
# add new certificate
cert = Lxd::Certificate.new(
api: host.api,
certificate: @new_cert.cert.to_pem.split("\n")[1...-1].join)
cert.add
# delete old certificate / we don't want this to be used
# any more.
Lxd::Certificate.new(
api: host.api, fingerprint: @cert.cert_fpr).delete
}
@cert = @new_cert
end
end
end end
# vim: set et ts=2 sw=2: # vim: set et ts=2 sw=2:

6
app/controllers/dashboard_controller.rb

@ -1,18 +1,14 @@
class DashboardController < ApplicationController class DashboardController < ApplicationController
def index def index
check_cert
@hosts = Host.all @hosts = Host.all
@hosts.map { |host| @hosts.map { |host|
host.cert = @cert
if host.config.auth == 'untrusted'
if host.lxd_config.auth == 'untrusted'
session[:return_to] = request.env["REQUEST_URI"] session[:return_to] = request.env["REQUEST_URI"]
redirect_to controller: 'hosts', action: 'auth', id: host.id redirect_to controller: 'hosts', action: 'auth', id: host.id
return return
end end
} }
@certificates = Lxd::Certificate.all @hosts.first.api
end end
end end
# vim: set et ts=2 sw=2: # vim: set et ts=2 sw=2:

5
app/controllers/hosts_controller.rb

@ -28,8 +28,7 @@ class HostsController < ApplicationController
# PATCH/PUT /hosts/1/add_key # PATCH/PUT /hosts/1/add_key
def add_key def add_key
cert = Lxd::Certificate.new api: @host.api
cert.add params[:hosts][:password]
@host.lxd_authenticate params[:hosts][:password]
redirect_to session.delete(:return_to) redirect_to session.delete(:return_to)
end end
@ -76,9 +75,7 @@ class HostsController < ApplicationController
private private
# Use callbacks to share common setup or constraints between actions. # Use callbacks to share common setup or constraints between actions.
def set_host def set_host
check_cert
@host = Host.find(params[:id]) @host = Host.find(params[:id])
@host.cert = @cert
end end
# Never trust parameters from the scary internet, only allow the white list through. # Never trust parameters from the scary internet, only allow the white list through.

41
app/models/certificate.rb

@ -2,28 +2,49 @@ require "openssl"
require 'digest/md5' require 'digest/md5'
class Certificate < ActiveRecord::Base class Certificate < ActiveRecord::Base
private_class_method :new
def self.get
@@cert ||= find_by active: true
@@cert ||= create
if @@cert.is_expired?
@@cert = @@cert.update
end
@@cert
end
def self.create(old=nil) def self.create(old=nil)
key = if old then old.key else OpenSSL::PKey::RSA.new 4096 end key = if old then old.key else OpenSSL::PKey::RSA.new 4096 end
cert = OpenSSL::X509::Certificate.new cert = OpenSSL::X509::Certificate.new
cert.version = if old then old.cert.version else 2 end cert.version = if old then old.cert.version else 2 end
cert.serial = if old then old.cert.serial+1 else 0 end cert.serial = if old then old.cert.serial+1 else 0 end
cert.not_before = Time.now cert.not_before = Time.now
#cert.not_after = Time.now + 1.year
cert.not_after = Time.now + 1.day
#cert.not_after = Time.now + 3.months
cert.not_after = Time.now + 1.day + 5.minutes
cert.public_key = key.public_key cert.public_key = key.public_key
cert.subject = cert.subject =
OpenSSL::X509::Name.parse( OpenSSL::X509::Name.parse(
'CN=lex-deeit/' + Rails.configuration.x.certificate['x509_base']) 'CN=lex-deeit/' + Rails.configuration.x.certificate['x509_base'])
cert.sign key, OpenSSL::Digest::SHA256.new cert.sign key, OpenSSL::Digest::SHA256.new
Certificate.new key: key.to_pem, cert: cert.to_pem, active: true
certificate = new(key: key.to_pem, cert: cert.to_pem, active: true)
certificate.save
certificate
end end
def update def update
self.active = false self.active = false
self.save self.save
cert = Certificate.create(self)
cert.save
cert
Certificate.create(self)
end
def is_expired?
# The cert is already expired
self.cert.not_after < Time.now
end
def expires_soon?
# The cert will expire within the next day or is alreay expired
(self.cert.not_after - 1.day) < Time.now
end end
def key def key
@ -43,5 +64,13 @@ class Certificate < ActiveRecord::Base
def cert_fpr def cert_fpr
Digest::SHA256.hexdigest(cert.to_der).upcase Digest::SHA256.hexdigest(cert.to_der).upcase
end end
def to_s
cert.to_pem.split("\n")[1...-1].join
end
def to_str
to_s
end
end end
# vim: set et ts=2 sw=2: # vim: set et ts=2 sw=2:

41
app/models/host.rb

@ -1,14 +1,43 @@
class Host < ActiveRecord::Base class Host < ActiveRecord::Base
def cert=(cert)
@cert = cert
end
belongs_to :certificate
def api
Lxd::API.get self, @cert
def certificate
# ensure that we always use a current, working non expired certificate.
case
when super.nil?
self.certificate_id = Certificate.get.id
self.save
super(true)
when super.expires_soon?
old = super
new = Certificate.get.update
Lxd::Certificate.new(api: api(old), certificate: new.to_s).add
self.certificate_id = new.id
self.save
@api = nil # enforce new api to get the new certificate used.
# finally remove the old certificate from lxd
Lxd::Certificate.new(api: api(new), fingerprint: old.cert_fpr).delete
super(true)
else
super
end
end end
def config
def lxd_config
Lxd::Config.get api Lxd::Config.get api
end end
def lxd_certificates
Lxd::Certificate.all api
end
def lxd_authenticate password
Lxd::Certificate.new(api: api).add password
end
private
def api certificate = nil
@api ||= Lxd::API.get self, certificate
end
end end
# vim: ts=2 sw=2: # vim: ts=2 sw=2:

8
app/models/lxd/api.rb

@ -1,9 +1,7 @@
module Lxd::API module Lxd::API
def self.get host, certificate
begin
uri = URI.parse host.uri
rescue
end
def self.get host, certificate = nil
certificate ||= host.certificate
uri = URI.parse host.uri
con = Net::HTTP.new uri.host, uri.port ? uri.port : 8443 con = Net::HTTP.new uri.host, uri.port ? uri.port : 8443
con.use_ssl = true con.use_ssl = true
con.cert = OpenSSL::X509::Certificate.new certificate.cert con.cert = OpenSSL::X509::Certificate.new certificate.cert

13
app/views/dashboard/index.html.erb

@ -1,9 +1,12 @@
<h1>Dashboard#index</h1> <h1>Dashboard#index</h1>
<p><%= @cert.cert_fpr %></p>
<p>Serial: <%= @cert.cert.serial %></p>
<% Certificate.all.each do |cert| -%>
<p>Fingerprint: <%= cert.cert_fpr %>&nbsp;
Serial: <%= cert.cert.serial %></p>
<% end -%>
<hr/>
<% @hosts.each do |host| -%> <% @hosts.each do |host| -%>
<p><%= host.config.inspect %></p>
<p><%= host.lxd_config.inspect %></p>
<% host.lxd_certificates.each do |certificate| -%>
<p><%= certificate.fingerprint %></p>
<% end -%> <% end -%>
<% @certificates.each do |cert| -%>
<p><%= cert.fingerprint %></p>
<% end -%> <% end -%>
Loading…
Cancel
Save