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,34 +3,5 @@ class ApplicationController < ActionController::Base | ||
| 3 | # For APIs, you may want to use :null_session instead. | 3 | # For APIs, you may want to use :null_session instead. |
| 4 | protect_from_forgery with: :exception | 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 | end | 6 | end |
| 36 | # vim: set et ts=2 sw=2: | 7 | # vim: set et ts=2 sw=2: |
| 1 | class DashboardController < ApplicationController | 1 | class DashboardController < ApplicationController |
| 2 | def index | 2 | def index |
| 3 | - check_cert | ||
| 4 | @hosts = Host.all | 3 | @hosts = Host.all |
| 5 | 4 | ||
| 6 | @hosts.map { |host| | 5 | @hosts.map { |host| |
| 7 | - host.cert = @cert | ||
| 8 | - if host.config.auth == 'untrusted' | 6 | + if host.lxd_config.auth == 'untrusted' |
| 9 | session[:return_to] = request.env["REQUEST_URI"] | 7 | session[:return_to] = request.env["REQUEST_URI"] |
| 10 | redirect_to controller: 'hosts', action: 'auth', id: host.id | 8 | redirect_to controller: 'hosts', action: 'auth', id: host.id |
| 11 | return | 9 | return |
| 12 | end | 10 | end |
| 13 | } | 11 | } |
| 14 | - | ||
| 15 | - @certificates = Lxd::Certificate.all @hosts.first.api | ||
| 16 | end | 12 | end |
| 17 | end | 13 | end |
| 18 | # vim: set et ts=2 sw=2: | 14 | # vim: set et ts=2 sw=2: |
| @@ -28,8 +28,7 @@ class HostsController < ApplicationController | @@ -28,8 +28,7 @@ class HostsController < ApplicationController | ||
| 28 | 28 | ||
| 29 | # PATCH/PUT /hosts/1/add_key | 29 | # PATCH/PUT /hosts/1/add_key |
| 30 | def add_key | 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 | redirect_to session.delete(:return_to) | 32 | redirect_to session.delete(:return_to) |
| 34 | end | 33 | end |
| 35 | 34 | ||
| @@ -76,9 +75,7 @@ class HostsController < ApplicationController | @@ -76,9 +75,7 @@ class HostsController < ApplicationController | ||
| 76 | private | 75 | private |
| 77 | # Use callbacks to share common setup or constraints between actions. | 76 | # Use callbacks to share common setup or constraints between actions. |
| 78 | def set_host | 77 | def set_host |
| 79 | - check_cert | ||
| 80 | @host = Host.find(params[:id]) | 78 | @host = Host.find(params[:id]) |
| 81 | - @host.cert = @cert | ||
| 82 | end | 79 | end |
| 83 | 80 | ||
| 84 | # Never trust parameters from the scary internet, only allow the white list through. | 81 | # Never trust parameters from the scary internet, only allow the white list through. |
| @@ -2,28 +2,49 @@ require "openssl" | @@ -2,28 +2,49 @@ require "openssl" | ||
| 2 | require 'digest/md5' | 2 | require 'digest/md5' |
| 3 | 3 | ||
| 4 | class Certificate < ActiveRecord::Base | 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 | def self.create(old=nil) | 16 | def self.create(old=nil) |
| 6 | key = if old then old.key else OpenSSL::PKey::RSA.new 4096 end | 17 | key = if old then old.key else OpenSSL::PKey::RSA.new 4096 end |
| 7 | cert = OpenSSL::X509::Certificate.new | 18 | cert = OpenSSL::X509::Certificate.new |
| 8 | cert.version = if old then old.cert.version else 2 end | 19 | cert.version = if old then old.cert.version else 2 end |
| 9 | cert.serial = if old then old.cert.serial+1 else 0 end | 20 | cert.serial = if old then old.cert.serial+1 else 0 end |
| 10 | cert.not_before = Time.now | 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 | cert.public_key = key.public_key | 24 | cert.public_key = key.public_key |
| 14 | cert.subject = | 25 | cert.subject = |
| 15 | OpenSSL::X509::Name.parse( | 26 | OpenSSL::X509::Name.parse( |
| 16 | 'CN=lex-deeit/' + Rails.configuration.x.certificate['x509_base']) | 27 | 'CN=lex-deeit/' + Rails.configuration.x.certificate['x509_base']) |
| 17 | cert.sign key, OpenSSL::Digest::SHA256.new | 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 | end | 32 | end |
| 20 | 33 | ||
| 21 | def update | 34 | def update |
| 22 | self.active = false | 35 | self.active = false |
| 23 | self.save | 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 | end | 48 | end |
| 28 | 49 | ||
| 29 | def key | 50 | def key |
| @@ -43,5 +64,13 @@ class Certificate < ActiveRecord::Base | @@ -43,5 +64,13 @@ class Certificate < ActiveRecord::Base | ||
| 43 | def cert_fpr | 64 | def cert_fpr |
| 44 | Digest::SHA256.hexdigest(cert.to_der).upcase | 65 | Digest::SHA256.hexdigest(cert.to_der).upcase |
| 45 | end | 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 | end | 75 | end |
| 47 | # vim: set et ts=2 sw=2: | 76 | # vim: set et ts=2 sw=2: |
| 1 | class Host < ActiveRecord::Base | 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 | end | 24 | end |
| 9 | 25 | ||
| 10 | - def config | 26 | + def lxd_config |
| 11 | Lxd::Config.get api | 27 | Lxd::Config.get api |
| 12 | end | 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 | end | 42 | end |
| 14 | # vim: ts=2 sw=2: | 43 | # vim: ts=2 sw=2: |
| 1 | module Lxd::API | 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 | con = Net::HTTP.new uri.host, uri.port ? uri.port : 8443 | 5 | con = Net::HTTP.new uri.host, uri.port ? uri.port : 8443 |
| 8 | con.use_ssl = true | 6 | con.use_ssl = true |
| 9 | con.cert = OpenSSL::X509::Certificate.new certificate.cert | 7 | con.cert = OpenSSL::X509::Certificate.new certificate.cert |
| 1 | <h1>Dashboard#index</h1> | 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 | <% @hosts.each do |host| -%> | 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 | <% end -%> | 11 | <% end -%> |
| 7 | -<% @certificates.each do |cert| -%> | ||
| 8 | -<p><%= cert.fingerprint %></p> | ||
| 9 | <% end -%> | 12 | <% end -%> |
Please
register
or
login
to post a comment