Skip to content

Commit 367dcad

Browse files
committed
Validate TLS certificate files contain valid PEM data at startup
RabbitMQ currently accepts invalid TLS certificate files at startup without validation, only failing silently when clients attempt to connect. This occurs because Erlang's TLS implementation lazily loads certificates on first connection rather than at configuration time. Users may not discover misconfigured certificates until production traffic fails. This change adds a `pem_file` validator to the cuttlefish schema that reads certificate files and validates they contain valid PEM data using `public_key:pem_decode/1`. The validator rejects empty files and files without valid PEM entries, causing RabbitMQ to fail at startup with a clear error message identifying the invalid file. The validator applies to all TLS certificate file mappings across 6 schema files: `cacertfile`, `certfile`, and `keyfile` for main listeners, definitions import, syslog, HTTP auth backend, LDAP auth backend, and peer discovery (Consul, etcd, Kubernetes). DH parameter files continue using the existing `file_accessible` validator since they are not PEM-encoded certificates. Fixes #15065
1 parent 506176e commit 367dcad

File tree

6 files changed

+32
-24
lines changed

6 files changed

+32
-24
lines changed

deps/rabbit/priv/schema/rabbit.schema

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,10 @@ end}.
175175
{datatype, {enum, [true, false]}}]}.
176176

177177
{mapping, "definitions.tls.cacertfile", "rabbit.definitions.ssl_options.cacertfile",
178-
[{datatype, string}, {validators, ["file_accessible"]}]}.
178+
[{datatype, string}, {validators, ["pem_file"]}]}.
179179

180180
{mapping, "definitions.tls.certfile", "rabbit.definitions.ssl_options.certfile",
181-
[{datatype, string}, {validators, ["file_accessible"]}]}.
181+
[{datatype, string}, {validators, ["pem_file"]}]}.
182182

183183
{mapping, "definitions.tls.cert", "rabbit.definitions.ssl_options.cert",
184184
[{datatype, string}]}.
@@ -214,7 +214,7 @@ fun(Conf) ->
214214
end}.
215215

216216
{mapping, "definitions.tls.keyfile", "rabbit.definitions.ssl_options.keyfile",
217-
[{datatype, string}, {validators, ["file_accessible"]}]}.
217+
[{datatype, string}, {validators, ["pem_file"]}]}.
218218

219219
{mapping, "definitions.tls.log_alert", "rabbit.definitions.ssl_options.log_alert",
220220
[{datatype, {enum, [true, false]}}]}.
@@ -316,10 +316,10 @@ end}.
316316
{datatype, {enum, [true, false]}}]}.
317317

318318
{mapping, "ssl_options.cacertfile", "rabbit.ssl_options.cacertfile",
319-
[{datatype, string}, {validators, ["file_accessible"]}]}.
319+
[{datatype, string}, {validators, ["pem_file"]}]}.
320320

321321
{mapping, "ssl_options.certfile", "rabbit.ssl_options.certfile",
322-
[{datatype, string}, {validators, ["file_accessible"]}]}.
322+
[{datatype, string}, {validators, ["pem_file"]}]}.
323323

324324
{mapping, "ssl_options.cert", "rabbit.ssl_options.cert",
325325
[{datatype, string}]}.
@@ -373,7 +373,7 @@ fun(Conf) ->
373373
end}.
374374

375375
{mapping, "ssl_options.keyfile", "rabbit.ssl_options.keyfile",
376-
[{datatype, string}, {validators, ["file_accessible"]}]}.
376+
[{datatype, string}, {validators, ["pem_file"]}]}.
377377

378378
{mapping, "ssl_options.log_level", "rabbit.ssl_options.log_level",
379379
[{datatype, {enum, [emergency, alert, critical, error, warning, notice, info, debug]}}]}.
@@ -1915,10 +1915,10 @@ end}.
19151915
{datatype, {enum, [true, false]}}]}.
19161916

19171917
{mapping, "log.syslog.ssl_options.cacertfile", "syslog.protocol",
1918-
[{datatype, string}, {validators, ["file_accessible"]}]}.
1918+
[{datatype, string}, {validators, ["pem_file"]}]}.
19191919

19201920
{mapping, "log.syslog.ssl_options.certfile", "syslog.protocol",
1921-
[{datatype, string}, {validators, ["file_accessible"]}]}.
1921+
[{datatype, string}, {validators, ["pem_file"]}]}.
19221922

19231923
{mapping, "log.syslog.ssl_options.cert", "syslog.protocol",
19241924
[{datatype, string}]}.
@@ -1954,7 +1954,7 @@ end}.
19541954
[{datatype, string}]}.
19551955

19561956
{mapping, "log.syslog.ssl_options.keyfile", "syslog.protocol",
1957-
[{datatype, string}, {validators, ["file_accessible"]}]}.
1957+
[{datatype, string}, {validators, ["pem_file"]}]}.
19581958

19591959
{mapping, "log.syslog.ssl_options.log_alert", "syslog.protocol",
19601960
[{datatype, {enum, [true, false]}}]}.
@@ -2889,6 +2889,14 @@ fun(File) ->
28892889
end
28902890
end}.
28912891

2892+
{validator, "pem_file", "PEM file does not exist, cannot be read, or does not contain valid X509 certificate data",
2893+
fun(File) ->
2894+
case file:read_file(File) of
2895+
{ok, Bin} -> public_key:pem_decode(Bin) =/= [];
2896+
_ -> false
2897+
end
2898+
end}.
2899+
28922900
{validator, "is_ip", "value should be a valid IP address",
28932901
fun(IpStr) ->
28942902
Res = inet:parse_address(IpStr),

deps/rabbitmq_auth_backend_http/priv/schema/rabbitmq_auth_backend_http.schema

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ end}.
4747
{datatype, {enum, [true, false]}}]}.
4848

4949
{mapping, "auth_http.ssl_options.cacertfile", "rabbitmq_auth_backend_http.ssl_options.cacertfile",
50-
[{datatype, string}, {validators, ["file_accessible"]}]}.
50+
[{datatype, string}, {validators, ["pem_file"]}]}.
5151

5252
{mapping, "auth_http.ssl_options.certfile", "rabbitmq_auth_backend_http.ssl_options.certfile",
53-
[{datatype, string}, {validators, ["file_accessible"]}]}.
53+
[{datatype, string}, {validators, ["pem_file"]}]}.
5454

5555
{mapping, "auth_http.ssl_options.cert", "rabbitmq_auth_backend_http.ssl_options.cert",
5656
[{datatype, string}]}.
@@ -104,7 +104,7 @@ fun(Conf) ->
104104
end}.
105105

106106
{mapping, "auth_http.ssl_options.keyfile", "rabbitmq_auth_backend_http.ssl_options.keyfile",
107-
[{datatype, string}, {validators, ["file_accessible"]}]}.
107+
[{datatype, string}, {validators, ["pem_file"]}]}.
108108

109109
{mapping, "auth_http.ssl_options.log_alert", "rabbitmq_auth_backend_http.ssl_options.log_alert",
110110
[{datatype, {enum, [true, false]}}]}.

deps/rabbitmq_auth_backend_ldap/priv/schema/rabbitmq_auth_backend_ldap.schema

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,10 @@ end}.
227227
{datatype, {enum, [true, false]}}]}.
228228

229229
{mapping, "auth_ldap.ssl_options.cacertfile", "rabbitmq_auth_backend_ldap.ssl_options.cacertfile",
230-
[{datatype, string}, {validators, ["file_accessible"]}]}.
230+
[{datatype, string}, {validators, ["pem_file"]}]}.
231231

232232
{mapping, "auth_ldap.ssl_options.certfile", "rabbitmq_auth_backend_ldap.ssl_options.certfile",
233-
[{datatype, string}, {validators, ["file_accessible"]}]}.
233+
[{datatype, string}, {validators, ["pem_file"]}]}.
234234

235235
{mapping, "auth_ldap.ssl_options.cert", "rabbitmq_auth_backend_ldap.ssl_options.cert",
236236
[{datatype, string}]}.
@@ -284,7 +284,7 @@ fun(Conf) ->
284284
end}.
285285

286286
{mapping, "auth_ldap.ssl_options.keyfile", "rabbitmq_auth_backend_ldap.ssl_options.keyfile",
287-
[{datatype, string}, {validators, ["file_accessible"]}]}.
287+
[{datatype, string}, {validators, ["pem_file"]}]}.
288288

289289
{mapping, "auth_ldap.ssl_options.log_alert", "rabbitmq_auth_backend_ldap.ssl_options.log_alert",
290290
[{datatype, {enum, [true, false]}}]}.

deps/rabbitmq_peer_discovery_consul/priv/schema/rabbitmq_peer_discovery_consul.schema

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -362,10 +362,10 @@ end}.
362362
{datatype, {enum, [true, false]}}]}.
363363

364364
{mapping, "cluster_formation.consul.ssl_options.cacertfile", "rabbit.cluster_formation.peer_discovery_consul.ssl_options.cacertfile",
365-
[{datatype, string}, {validators, ["file_accessible"]}]}.
365+
[{datatype, string}, {validators, ["pem_file"]}]}.
366366

367367
{mapping, "cluster_formation.consul.ssl_options.certfile", "rabbit.cluster_formation.peer_discovery_consul.ssl_options.certfile",
368-
[{datatype, string}, {validators, ["file_accessible"]}]}.
368+
[{datatype, string}, {validators, ["pem_file"]}]}.
369369

370370
{mapping, "cluster_formation.consul.ssl_options.cert", "rabbit.cluster_formation.peer_discovery_consul.ssl_options.cert",
371371
[{datatype, string}]}.
@@ -410,7 +410,7 @@ end
410410
end}.
411411

412412
{mapping, "cluster_formation.consul.ssl_options.keyfile", "rabbit.cluster_formation.peer_discovery_consul.ssl_options.keyfile",
413-
[{datatype, string}, {validators, ["file_accessible"]}]}.
413+
[{datatype, string}, {validators, ["pem_file"]}]}.
414414

415415
{mapping, "cluster_formation.consul.ssl_options.log_alert", "rabbit.cluster_formation.peer_discovery_consul.ssl_options.log_alert",
416416
[{datatype, {enum, [true, false]}}]}.

deps/rabbitmq_peer_discovery_etcd/priv/schema/rabbitmq_peer_discovery_etcd.schema

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,10 @@ end}.
183183
{datatype, {enum, [verify_peer, verify_none]}}]}.
184184

185185
{mapping, "cluster_formation.etcd.ssl_options.cacertfile", "rabbit.cluster_formation.peer_discovery_etcd.ssl_options.cacertfile",
186-
[{datatype, string}, {validators, ["file_accessible"]}]}.
186+
[{datatype, string}, {validators, ["pem_file"]}]}.
187187

188188
{mapping, "cluster_formation.etcd.ssl_options.certfile", "rabbit.cluster_formation.peer_discovery_etcd.ssl_options.certfile",
189-
[{datatype, string}, {validators, ["file_accessible"]}]}.
189+
[{datatype, string}, {validators, ["pem_file"]}]}.
190190

191191
{mapping, "cluster_formation.etcd.ssl_options.cert", "rabbit.cluster_formation.peer_discovery_etcd.ssl_options.cert",
192192
[{datatype, string}]}.
@@ -220,7 +220,7 @@ fun(Conf) ->
220220
end}.
221221

222222
{mapping, "cluster_formation.etcd.ssl_options.keyfile", "rabbit.cluster_formation.peer_discovery_etcd.ssl_options.keyfile",
223-
[{datatype, string}, {validators, ["file_accessible"]}]}.
223+
[{datatype, string}, {validators, ["pem_file"]}]}.
224224

225225
{mapping, "cluster_formation.etcd.ssl_options.log_alert", "rabbit.cluster_formation.peer_discovery_etcd.ssl_options.log_alert",
226226
[{datatype, {enum, [true, false]}}]}.

deps/rabbitmq_peer_discovery_k8s/priv/schema/rabbitmq_peer_discovery_k8s.schema

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ end}.
115115
%% modern keys
116116

117117
{mapping, "cluster_formation.k8s.tls.cacertfile", "rabbit.cluster_formation.peer_discovery_k8s.ssl_options.cacertfile",
118-
[{datatype, string}, {validators, ["file_accessible"]}
118+
[{datatype, string}, {validators, ["pem_file"]}
119119
]}.
120120

121121
{translation, "rabbit.cluster_formation.peer_discovery_k8s.ssl_options.cacertfile",
@@ -127,7 +127,7 @@ fun(Conf) ->
127127
end}.
128128

129129
{mapping, "cluster_formation.k8s.tls.certfile", "rabbit.cluster_formation.peer_discovery_k8s.ssl_options.certfile",
130-
[{datatype, string}, {validators, ["file_accessible"]}
130+
[{datatype, string}, {validators, ["pem_file"]}
131131
]}.
132132

133133
{translation, "rabbit.cluster_formation.peer_discovery_k8s.ssl_options.certfile",
@@ -139,7 +139,7 @@ fun(Conf) ->
139139
end}.
140140

141141
{mapping, "cluster_formation.k8s.tls.keyfile", "rabbit.cluster_formation.peer_discovery_k8s.ssl_options.keyfile",
142-
[{datatype, string}, {validators, ["file_accessible"]}
142+
[{datatype, string}, {validators, ["pem_file"]}
143143
]}.
144144

145145
{translation, "rabbit.cluster_formation.peer_discovery_k8s.ssl_options.keyfile",

0 commit comments

Comments
 (0)