Class: Legion::Crypt::CertRotation

Inherits:
Object
  • Object
show all
Includes:
Logging::Helper
Defined in:
lib/legion/crypt/cert_rotation.rb

Constant Summary collapse

DEFAULT_CHECK_INTERVAL =

12 hours

43_200

Constants included from Logging::Helper

Logging::Helper::CompatLogger

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Logging::Helper

#handle_exception, #log

Constructor Details

#initialize(check_interval: DEFAULT_CHECK_INTERVAL) ⇒ CertRotation

Returns a new instance of CertRotation.



14
15
16
17
18
19
20
21
# File 'lib/legion/crypt/cert_rotation.rb', line 14

def initialize(check_interval: DEFAULT_CHECK_INTERVAL)
  @check_interval = check_interval
  @current_cert   = nil
  @issued_at      = nil
  @running        = false
  @thread         = nil
  @mutex          = Mutex.new
end

Instance Attribute Details

#check_intervalObject (readonly)

Returns the value of attribute check_interval.



12
13
14
# File 'lib/legion/crypt/cert_rotation.rb', line 12

def check_interval
  @check_interval
end

#current_certObject (readonly)

Returns the value of attribute current_cert.



12
13
14
# File 'lib/legion/crypt/cert_rotation.rb', line 12

def current_cert
  @current_cert
end

#issued_atObject (readonly)

Returns the value of attribute issued_at.



12
13
14
# File 'lib/legion/crypt/cert_rotation.rb', line 12

def issued_at
  @issued_at
end

Instance Method Details

#needs_renewal?Boolean

Returns:

  • (Boolean)


65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/legion/crypt/cert_rotation.rb', line 65

def needs_renewal?
  current_cert = nil
  issued_at = nil
  @mutex.synchronize do
    current_cert = @current_cert
    issued_at = @issued_at
  end
  return false if current_cert.nil? || issued_at.nil?

  expiry = current_cert[:expiry]
  total  = expiry - issued_at
  return true if total <= 0

  remaining = expiry - Time.now
  fraction  = remaining / total
  fraction < renewal_window
end

#rotate!Object



53
54
55
56
57
58
59
60
61
62
63
# File 'lib/legion/crypt/cert_rotation.rb', line 53

def rotate!
  node_name = node_common_name
  new_cert = Legion::Crypt::Mtls.issue_cert(common_name: node_name)
  @mutex.synchronize do
    @current_cert = new_cert
    @issued_at    = Time.now
  end
  log.info("[mTLS] Certificate rotated: serial=#{new_cert[:serial]} expiry=#{new_cert[:expiry]}")
  emit_rotated_event(new_cert)
  new_cert
end

#running?Boolean

Returns:

  • (Boolean)


49
50
51
# File 'lib/legion/crypt/cert_rotation.rb', line 49

def running?
  (@running && @thread&.alive?) || false
end

#startObject



23
24
25
26
27
28
29
30
# File 'lib/legion/crypt/cert_rotation.rb', line 23

def start
  return unless Legion::Crypt::Mtls.enabled?
  return if running?

  @running = true
  @thread  = Thread.new { rotation_loop }
  log.info('[mTLS] CertRotation started')
end

#stopObject



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/legion/crypt/cert_rotation.rb', line 32

def stop
  @running = false
  begin
    @thread&.wakeup
  rescue ThreadError => e
    handle_exception(e, level: :debug, operation: 'crypt.cert_rotation.stop')
    nil
  end
  @thread&.join(2)
  if @thread&.alive?
    log.warn '[mTLS] CertRotation thread did not stop within timeout'
  else
    @thread = nil
  end
  log.info('[mTLS] CertRotation stopped')
end