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