@@ -50,9 +50,23 @@ def initialize(machine)
50
50
def next_state
51
51
Puppet . debug ( "Loading CA certs" )
52
52
53
+ force_crl_refresh = false
54
+
53
55
cacerts = @cert_provider . load_cacerts
54
56
if cacerts
55
57
next_ctx = @ssl_provider . create_root_context ( cacerts : cacerts , revocation : false )
58
+
59
+ now = Time . now
60
+ last_update = @cert_provider . ca_last_update
61
+ if needs_refresh? ( now , last_update )
62
+ # set last updated time first, then make a best effort to refresh
63
+ @cert_provider . ca_last_update = now
64
+
65
+ # If we refresh the CA, then we need to force the CRL to be refreshed too,
66
+ # since if there is a new CA in the chain, then we need its CRL to check
67
+ # the full chain for revocation status.
68
+ next_ctx , force_crl_refresh = refresh_ca ( next_ctx , last_update )
69
+ end
56
70
else
57
71
route = @machine . session . route_to ( :ca , ssl_context : @ssl_context )
58
72
_ , pem = route . get_certificate ( Puppet ::SSL ::CA_NAME , ssl_context : @ssl_context )
@@ -74,7 +88,7 @@ def next_state
74
88
@cert_provider . save_cacerts ( cacerts )
75
89
end
76
90
77
- NeedCRLs . new ( @machine , next_ctx )
91
+ NeedCRLs . new ( @machine , next_ctx , force_crl_refresh )
78
92
rescue OpenSSL ::X509 ::CertificateError => e
79
93
Error . new ( @machine , e . message , e )
80
94
rescue Puppet ::HTTP ::ResponseError => e
@@ -84,6 +98,49 @@ def next_state
84
98
to_error ( _ ( 'Could not download CA certificate: %{message}' ) % { message : e . message } , e )
85
99
end
86
100
end
101
+
102
+ private
103
+
104
+ def needs_refresh? ( now , last_update )
105
+ return true if last_update . nil?
106
+
107
+ ca_ttl = Puppet [ :ca_refresh_interval ]
108
+ return false unless ca_ttl
109
+
110
+ now . to_i > last_update . to_i + ca_ttl
111
+ end
112
+
113
+ def refresh_ca ( ssl_ctx , last_update )
114
+ Puppet . info ( _ ( "Refreshing CA certificate" ) )
115
+
116
+ # return the next_ctx containing the updated ca
117
+ [ download_ca ( ssl_ctx , last_update ) , true ]
118
+ rescue Puppet ::HTTP ::ResponseError => e
119
+ if e . response . code == 304
120
+ Puppet . info ( _ ( "CA certificate is unmodified, using existing CA certificate" ) )
121
+ else
122
+ Puppet . info ( _ ( "Failed to refresh CA certificate, using existing CA certificate: %{message}" ) % { message : e . message } )
123
+ end
124
+
125
+ # return the original ssl_ctx
126
+ [ ssl_ctx , false ]
127
+ rescue Puppet ::HTTP ::HTTPError => e
128
+ Puppet . warning ( _ ( "Failed to refresh CA certificate, using existing CA certificate: %{message}" ) % { message : e . message } )
129
+
130
+ # return the original ssl_ctx
131
+ [ ssl_ctx , false ]
132
+ end
133
+
134
+ def download_ca ( ssl_ctx , last_update )
135
+ route = @machine . session . route_to ( :ca , ssl_context : ssl_ctx )
136
+ _ , pem = route . get_certificate ( Puppet ::SSL ::CA_NAME , if_modified_since : last_update , ssl_context : ssl_ctx )
137
+ cacerts = @cert_provider . load_cacerts_from_pem ( pem )
138
+ # verify cacerts before saving
139
+ next_ctx = @ssl_provider . create_root_context ( cacerts : cacerts , revocation : false )
140
+ @cert_provider . save_cacerts ( cacerts )
141
+
142
+ next_ctx
143
+ end
87
144
end
88
145
89
146
# If revocation is enabled, load CRLs or download them, using the CA bundle
@@ -93,6 +150,13 @@ def next_state
93
150
# for which we don't have a CRL
94
151
#
95
152
class NeedCRLs < SSLState
153
+ attr_reader :force_crl_refresh
154
+
155
+ def initialize ( machine , ssl_context , force_crl_refresh = false )
156
+ super ( machine , ssl_context )
157
+ @force_crl_refresh = force_crl_refresh
158
+ end
159
+
96
160
def next_state
97
161
Puppet . debug ( "Loading CRLs" )
98
162
@@ -102,15 +166,12 @@ def next_state
102
166
if crls
103
167
next_ctx = @ssl_provider . create_root_context ( cacerts : ssl_context [ :cacerts ] , crls : crls )
104
168
105
- crl_ttl = Puppet [ :crl_refresh_interval ]
106
- if crl_ttl
107
- last_update = @cert_provider . crl_last_update
108
- now = Time . now
109
- if last_update . nil? || now . to_i > last_update . to_i + crl_ttl
110
- # set last updated time first, then make a best effort to refresh
111
- @cert_provider . crl_last_update = now
112
- next_ctx = refresh_crl ( next_ctx , last_update )
113
- end
169
+ now = Time . now
170
+ last_update = @cert_provider . crl_last_update
171
+ if needs_refresh? ( now , last_update )
172
+ # set last updated time first, then make a best effort to refresh
173
+ @cert_provider . crl_last_update = now
174
+ next_ctx = refresh_crl ( next_ctx , last_update )
114
175
end
115
176
else
116
177
next_ctx = download_crl ( @ssl_context , nil )
@@ -133,6 +194,15 @@ def next_state
133
194
134
195
private
135
196
197
+ def needs_refresh? ( now , last_update )
198
+ return true if @force_crl_refresh || last_update . nil?
199
+
200
+ crl_ttl = Puppet [ :crl_refresh_interval ]
201
+ return false unless crl_ttl
202
+
203
+ now . to_i > last_update . to_i + crl_ttl
204
+ end
205
+
136
206
def refresh_crl ( ssl_ctx , last_update )
137
207
Puppet . info ( _ ( "Refreshing CRL" ) )
138
208
0 commit comments