Commit 0b306511dc3b71aa93a7a265c61bb91694459f4e
1 parent
862ee9fa
handle certificates within hosts automatically
Showing
7 changed files
with
83 additions
and
60 deletions
| ... | ... | @@ -3,34 +3,5 @@ class ApplicationController < ActionController::Base |
| 3 | 3 | # For APIs, you may want to use :null_session instead. |
| 4 | 4 | protect_from_forgery with: :exception |
| 5 | 5 | |
| 6 | - def check_cert | |
| 7 | - @cert = Certificate.find_by active: true | |
| 8 | - unless @cert | |
| 9 | - @cert = Certificate.create | |
| 10 | - @cert.save | |
| 11 | - end | |
| 12 | - | |
| 13 | - # update cert on all hosts if close to end. | |
| 14 | - # This will never fail as lxd is very lax with its certificates. | |
| 15 | - # It accepts certificates even behind the not_after date. | |
| 16 | - # As a result a password is only required when a new host is added | |
| 17 | - # or we remove the current cert completely. | |
| 18 | - if (@cert.cert.not_after - 1.day + 300) < Time.now | |
| 19 | - @new_cert = @cert.update | |
| 20 | - Host.all.each { |host| | |
| 21 | - host.cert = @cert | |
| 22 | - # add new certificate | |
| 23 | - cert = Lxd::Certificate.new( | |
| 24 | - api: host.api, | |
| 25 | - certificate: @new_cert.cert.to_pem.split("\n")[1...-1].join) | |
| 26 | - cert.add | |
| 27 | - # delete old certificate / we don't want this to be used | |
| 28 | - # any more. | |
| 29 | - Lxd::Certificate.new( | |
| 30 | - api: host.api, fingerprint: @cert.cert_fpr).delete | |
| 31 | - } | |
| 32 | - @cert = @new_cert | |
| 33 | - end | |
| 34 | - end | |
| 35 | 6 | end |
| 36 | 7 | # vim: set et ts=2 sw=2: | ... | ... |
| 1 | 1 | class DashboardController < ApplicationController |
| 2 | 2 | def index |
| 3 | - check_cert | |
| 4 | 3 | @hosts = Host.all |
| 5 | 4 | |
| 6 | 5 | @hosts.map { |host| |
| 7 | - host.cert = @cert | |
| 8 | - if host.config.auth == 'untrusted' | |
| 6 | + if host.lxd_config.auth == 'untrusted' | |
| 9 | 7 | session[:return_to] = request.env["REQUEST_URI"] |
| 10 | 8 | redirect_to controller: 'hosts', action: 'auth', id: host.id |
| 11 | 9 | return |
| 12 | 10 | end |
| 13 | 11 | } |
| 14 | - | |
| 15 | - @certificates = Lxd::Certificate.all @hosts.first.api | |
| 16 | 12 | end |
| 17 | 13 | end |
| 18 | 14 | # vim: set et ts=2 sw=2: | ... | ... |
| ... | ... | @@ -28,8 +28,7 @@ class HostsController < ApplicationController |
| 28 | 28 | |
| 29 | 29 | # PATCH/PUT /hosts/1/add_key |
| 30 | 30 | def add_key |
| 31 | - cert = Lxd::Certificate.new api: @host.api | |
| 32 | - cert.add params[:hosts][:password] | |
| 31 | + @host.lxd_authenticate params[:hosts][:password] | |
| 33 | 32 | redirect_to session.delete(:return_to) |
| 34 | 33 | end |
| 35 | 34 | |
| ... | ... | @@ -76,9 +75,7 @@ class HostsController < ApplicationController |
| 76 | 75 | private |
| 77 | 76 | # Use callbacks to share common setup or constraints between actions. |
| 78 | 77 | def set_host |
| 79 | - check_cert | |
| 80 | 78 | @host = Host.find(params[:id]) |
| 81 | - @host.cert = @cert | |
| 82 | 79 | end |
| 83 | 80 | |
| 84 | 81 | # Never trust parameters from the scary internet, only allow the white list through. | ... | ... |
| ... | ... | @@ -2,28 +2,49 @@ require "openssl" |
| 2 | 2 | require 'digest/md5' |
| 3 | 3 | |
| 4 | 4 | class Certificate < ActiveRecord::Base |
| 5 | + private_class_method :new | |
| 6 | + | |
| 7 | + def self.get | |
| 8 | + @@cert ||= find_by active: true | |
| 9 | + @@cert ||= create | |
| 10 | + if @@cert.is_expired? | |
| 11 | + @@cert = @@cert.update | |
| 12 | + end | |
| 13 | + @@cert | |
| 14 | + end | |
| 15 | + | |
| 5 | 16 | def self.create(old=nil) |
| 6 | 17 | key = if old then old.key else OpenSSL::PKey::RSA.new 4096 end |
| 7 | 18 | cert = OpenSSL::X509::Certificate.new |
| 8 | 19 | cert.version = if old then old.cert.version else 2 end |
| 9 | 20 | cert.serial = if old then old.cert.serial+1 else 0 end |
| 10 | 21 | cert.not_before = Time.now |
| 11 | - #cert.not_after = Time.now + 1.year | |
| 12 | - cert.not_after = Time.now + 1.day | |
| 22 | + #cert.not_after = Time.now + 3.months | |
| 23 | + cert.not_after = Time.now + 1.day + 5.minutes | |
| 13 | 24 | cert.public_key = key.public_key |
| 14 | 25 | cert.subject = |
| 15 | 26 | OpenSSL::X509::Name.parse( |
| 16 | 27 | 'CN=lex-deeit/' + Rails.configuration.x.certificate['x509_base']) |
| 17 | 28 | cert.sign key, OpenSSL::Digest::SHA256.new |
| 18 | - Certificate.new key: key.to_pem, cert: cert.to_pem, active: true | |
| 29 | + certificate = new(key: key.to_pem, cert: cert.to_pem, active: true) | |
| 30 | + certificate.save | |
| 31 | + certificate | |
| 19 | 32 | end |
| 20 | 33 | |
| 21 | 34 | def update |
| 22 | 35 | self.active = false |
| 23 | 36 | self.save |
| 24 | - cert = Certificate.create(self) | |
| 25 | - cert.save | |
| 26 | - cert | |
| 37 | + Certificate.create(self) | |
| 38 | + end | |
| 39 | + | |
| 40 | + def is_expired? | |
| 41 | + # The cert is already expired | |
| 42 | + self.cert.not_after < Time.now | |
| 43 | + end | |
| 44 | + | |
| 45 | + def expires_soon? | |
| 46 | + # The cert will expire within the next day or is alreay expired | |
| 47 | + (self.cert.not_after - 1.day) < Time.now | |
| 27 | 48 | end |
| 28 | 49 | |
| 29 | 50 | def key |
| ... | ... | @@ -43,5 +64,13 @@ class Certificate < ActiveRecord::Base |
| 43 | 64 | def cert_fpr |
| 44 | 65 | Digest::SHA256.hexdigest(cert.to_der).upcase |
| 45 | 66 | end |
| 67 | + | |
| 68 | + def to_s | |
| 69 | + cert.to_pem.split("\n")[1...-1].join | |
| 70 | + end | |
| 71 | + | |
| 72 | + def to_str | |
| 73 | + to_s | |
| 74 | + end | |
| 46 | 75 | end |
| 47 | 76 | # vim: set et ts=2 sw=2: | ... | ... |
| 1 | 1 | class Host < ActiveRecord::Base |
| 2 | - def cert=(cert) | |
| 3 | - @cert = cert | |
| 4 | - end | |
| 2 | + belongs_to :certificate | |
| 5 | 3 | |
| 6 | - def api | |
| 7 | - Lxd::API.get self, @cert | |
| 4 | + def certificate | |
| 5 | + # ensure that we always use a current, working non expired certificate. | |
| 6 | + case | |
| 7 | + when super.nil? | |
| 8 | + self.certificate_id = Certificate.get.id | |
| 9 | + self.save | |
| 10 | + super(true) | |
| 11 | + when super.expires_soon? | |
| 12 | + old = super | |
| 13 | + new = Certificate.get.update | |
| 14 | + Lxd::Certificate.new(api: api(old), certificate: new.to_s).add | |
| 15 | + self.certificate_id = new.id | |
| 16 | + self.save | |
| 17 | + @api = nil # enforce new api to get the new certificate used. | |
| 18 | + # finally remove the old certificate from lxd | |
| 19 | + Lxd::Certificate.new(api: api(new), fingerprint: old.cert_fpr).delete | |
| 20 | + super(true) | |
| 21 | + else | |
| 22 | + super | |
| 23 | + end | |
| 8 | 24 | end |
| 9 | 25 | |
| 10 | - def config | |
| 26 | + def lxd_config | |
| 11 | 27 | Lxd::Config.get api |
| 12 | 28 | end |
| 29 | + | |
| 30 | + def lxd_certificates | |
| 31 | + Lxd::Certificate.all api | |
| 32 | + end | |
| 33 | + | |
| 34 | + def lxd_authenticate password | |
| 35 | + Lxd::Certificate.new(api: api).add password | |
| 36 | + end | |
| 37 | + | |
| 38 | + private | |
| 39 | + def api certificate = nil | |
| 40 | + @api ||= Lxd::API.get self, certificate | |
| 41 | + end | |
| 13 | 42 | end |
| 14 | 43 | # vim: ts=2 sw=2: | ... | ... |
| 1 | 1 | module Lxd::API |
| 2 | - def self.get host, certificate | |
| 3 | - begin | |
| 4 | - uri = URI.parse host.uri | |
| 5 | - rescue | |
| 6 | - end | |
| 2 | + def self.get host, certificate = nil | |
| 3 | + certificate ||= host.certificate | |
| 4 | + uri = URI.parse host.uri | |
| 7 | 5 | con = Net::HTTP.new uri.host, uri.port ? uri.port : 8443 |
| 8 | 6 | con.use_ssl = true |
| 9 | 7 | con.cert = OpenSSL::X509::Certificate.new certificate.cert | ... | ... |
| 1 | 1 | <h1>Dashboard#index</h1> |
| 2 | -<p><%= @cert.cert_fpr %></p> | |
| 3 | -<p>Serial: <%= @cert.cert.serial %></p> | |
| 2 | +<% Certificate.all.each do |cert| -%> | |
| 3 | +<p>Fingerprint: <%= cert.cert_fpr %> | |
| 4 | +Serial: <%= cert.cert.serial %></p> | |
| 5 | +<% end -%> | |
| 6 | +<hr/> | |
| 4 | 7 | <% @hosts.each do |host| -%> |
| 5 | -<p><%= host.config.inspect %></p> | |
| 8 | +<p><%= host.lxd_config.inspect %></p> | |
| 9 | +<% host.lxd_certificates.each do |certificate| -%> | |
| 10 | +<p><%= certificate.fingerprint %></p> | |
| 6 | 11 | <% end -%> |
| 7 | -<% @certificates.each do |cert| -%> | |
| 8 | -<p><%= cert.fingerprint %></p> | |
| 9 | 12 | <% end -%> | ... | ... |
Please
register
or
login
to post a comment