@@ -11,6 +11,7 @@ use postgres_native_tls::MakeTlsConnector;
11
11
use std:: str:: FromStr ;
12
12
use std:: sync:: Arc ;
13
13
use std:: time:: Duration ;
14
+ use tokio:: sync:: Mutex ;
14
15
use tokio_postgres:: GenericClient ;
15
16
use tokio_postgres:: Statement ;
16
17
@@ -24,21 +25,10 @@ impl Postgres {
24
25
25
26
const CERT_URL : & str = "https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem" ;
26
27
27
- lazy_static:: lazy_static! {
28
- static ref CERTIFICATE_PEMS : Vec <u8 > = {
29
- let client = reqwest:: blocking:: Client :: new( ) ;
30
- let resp = client
31
- . get( CERT_URL )
32
- . send( )
33
- . expect( "failed to get RDS cert" ) ;
34
- resp. bytes( ) . expect( "failed to get RDS cert body" ) . to_vec( )
35
- } ;
36
- }
37
-
38
28
async fn make_client ( db_url : & str ) -> anyhow:: Result < tokio_postgres:: Client > {
39
29
if db_url. contains ( "rds.amazonaws.com" ) {
40
30
let mut builder = TlsConnector :: builder ( ) ;
41
- for cert in make_certificates ( ) {
31
+ for cert in make_certificates ( ) . await {
42
32
builder. add_root_certificate ( cert) ;
43
33
}
44
34
let connector = builder. build ( ) . context ( "built TlsConnector" ) ?;
@@ -75,11 +65,28 @@ async fn make_client(db_url: &str) -> anyhow::Result<tokio_postgres::Client> {
75
65
Ok ( db_client)
76
66
}
77
67
}
78
- fn make_certificates ( ) -> Vec < Certificate > {
68
+ async fn make_certificates ( ) -> Vec < Certificate > {
79
69
use x509_cert:: der:: pem:: LineEnding ;
80
70
use x509_cert:: der:: EncodePem ;
81
71
82
- let certs = x509_cert:: Certificate :: load_pem_chain ( & CERTIFICATE_PEMS [ ..] ) . unwrap ( ) ;
72
+ static CERTIFICATE_PEMS : Mutex < Option < Vec < u8 > > > = Mutex :: const_new ( None ) ;
73
+
74
+ let mut guard = CERTIFICATE_PEMS . lock ( ) . await ;
75
+ if guard. is_none ( ) {
76
+ let client = reqwest:: Client :: new ( ) ;
77
+ let resp = client
78
+ . get ( CERT_URL )
79
+ . send ( )
80
+ . await
81
+ . expect ( "failed to get RDS cert" ) ;
82
+ let certificate_pems = resp
83
+ . bytes ( )
84
+ . await
85
+ . expect ( "failed to get RDS cert body" )
86
+ . to_vec ( ) ;
87
+ * guard = Some ( certificate_pems. clone ( ) ) ;
88
+ }
89
+ let certs = x509_cert:: Certificate :: load_pem_chain ( & guard. as_ref ( ) . unwrap ( ) [ ..] ) . unwrap ( ) ;
83
90
certs
84
91
. into_iter ( )
85
92
. map ( |cert| Certificate :: from_pem ( cert. to_pem ( LineEnding :: LF ) . unwrap ( ) . as_bytes ( ) ) . unwrap ( ) )
@@ -1365,9 +1372,9 @@ mod tests {
1365
1372
1366
1373
// Makes sure we successfully parse the RDS certificates and load them into native-tls compatible
1367
1374
// format.
1368
- #[ test]
1369
- fn can_make_certificates ( ) {
1370
- let certs = make_certificates ( ) ;
1375
+ #[ tokio :: test]
1376
+ async fn can_make_certificates ( ) {
1377
+ let certs = make_certificates ( ) . await ;
1371
1378
assert ! ( !certs. is_empty( ) ) ;
1372
1379
}
1373
1380
}
0 commit comments