1
1
use clap:: Parser ;
2
2
use fs_err as fs;
3
3
use ra_tls:: {
4
- cert:: CertRequest ,
4
+ cert:: { CaCert , CertRequest } ,
5
5
rcgen:: { KeyPair , PKCS_ECDSA_P256_SHA256 } ,
6
6
} ;
7
7
8
8
#[ derive( Parser ) ]
9
9
#[ command( author, version, about) ]
10
10
struct Args {
11
- /// Domain name for the generated certificates
12
- #[ arg( short, long, default_value = "local" ) ]
13
- domain : String ,
11
+ #[ command( subcommand) ]
12
+ command : Commands ,
13
+ }
14
+
15
+ #[ derive( clap:: Subcommand ) ]
16
+ enum Commands {
17
+ /// Generate certificates for the KMS system
18
+ Generate {
19
+ /// Domain name for the generated certificates
20
+ #[ arg( short, long) ]
21
+ domain : String ,
22
+
23
+ /// Output directory for the generated certificates
24
+ #[ arg( short, long, default_value = "certs" ) ]
25
+ output_dir : String ,
26
+ } ,
27
+ /// Sign a certificate using an existing CA
28
+ Sign {
29
+ /// Domain name for the generated certificate
30
+ #[ arg( short, long) ]
31
+ domain : String ,
32
+
33
+ /// CA key file
34
+ #[ arg( short, long) ]
35
+ ca_key : String ,
14
36
15
- /// Output directory for the generated certificates
16
- #[ arg( short, long, default_value = "certs" ) ]
17
- output_dir : String ,
37
+ /// CA cert file
38
+ #[ arg( short, long) ]
39
+ ca_cert : String ,
40
+
41
+ /// Output cert file
42
+ #[ arg( short, long) ]
43
+ cert : String ,
44
+
45
+ /// Output key file
46
+ #[ arg( short, long) ]
47
+ key : String ,
48
+ } ,
18
49
}
19
50
20
51
fn main ( ) -> anyhow:: Result < ( ) > {
21
52
let args = Args :: parse ( ) ;
22
53
54
+ match args. command {
55
+ Commands :: Generate { domain, output_dir } => {
56
+ generate_and_store_certificates ( & domain, & output_dir) ?;
57
+ }
58
+ Commands :: Sign {
59
+ domain,
60
+ ca_key,
61
+ ca_cert,
62
+ cert,
63
+ key,
64
+ } => {
65
+ sign_certificate ( & domain, & ca_key, & ca_cert, & cert, & key) ?;
66
+ }
67
+ }
68
+ Ok ( ( ) )
69
+ }
70
+
71
+ fn generate_and_store_certificates ( domain : & str , output_dir : & str ) -> anyhow:: Result < ( ) > {
23
72
let tmp_ca_key = KeyPair :: generate_for ( & PKCS_ECDSA_P256_SHA256 ) ?;
24
73
let ca_key = KeyPair :: generate_for ( & PKCS_ECDSA_P256_SHA256 ) ?;
25
74
let kms_rpc_key = KeyPair :: generate_for ( & PKCS_ECDSA_P256_SHA256 ) ?;
@@ -42,7 +91,7 @@ fn main() -> anyhow::Result<()> {
42
91
. build ( )
43
92
. self_signed ( ) ?;
44
93
45
- let kms_domain = format ! ( "kms.{}" , args . domain ) ;
94
+ let kms_domain = format ! ( "kms.{domain}" ) ;
46
95
// Sign WWW server cert with KMS cert
47
96
let kms_rpc_cert = CertRequest :: builder ( )
48
97
. subject ( & kms_domain)
@@ -51,15 +100,14 @@ fn main() -> anyhow::Result<()> {
51
100
. build ( )
52
101
. signed_by ( & ca_cert, & ca_key) ?;
53
102
54
- let tproxy_domain = format ! ( "tproxy.{}" , args . domain ) ;
103
+ let tproxy_domain = format ! ( "tproxy.{domain}" ) ;
55
104
let tproxy_rpc_cert = CertRequest :: builder ( )
56
105
. subject ( & tproxy_domain)
57
106
. alt_names ( & [ tproxy_domain. clone ( ) ] )
58
107
. key ( & tproxy_rpc_key)
59
108
. build ( )
60
109
. signed_by ( & ca_cert, & ca_key) ?;
61
110
62
- let output_dir = & args. output_dir ;
63
111
store_cert (
64
112
output_dir,
65
113
"tmp-ca" ,
@@ -84,6 +132,7 @@ fn main() -> anyhow::Result<()> {
84
132
& tproxy_rpc_cert. pem ( ) ,
85
133
& tproxy_rpc_key. serialize_pem ( ) ,
86
134
) ?;
135
+
87
136
Ok ( ( ) )
88
137
}
89
138
@@ -94,3 +143,27 @@ fn store_cert(path: &str, name: &str, cert: &str, key: &str) -> anyhow::Result<(
94
143
fs:: write ( key_path, key) ?;
95
144
Ok ( ( ) )
96
145
}
146
+
147
+ fn sign_certificate (
148
+ domain : & str ,
149
+ ca_key_path : & str ,
150
+ ca_cert_path : & str ,
151
+ cert_path : & str ,
152
+ key_path : & str ,
153
+ ) -> anyhow:: Result < ( ) > {
154
+ let ca_key = fs:: read_to_string ( ca_key_path) ?;
155
+ let ca_cert = fs:: read_to_string ( ca_cert_path) ?;
156
+ let ca = CaCert :: new ( ca_cert, ca_key) ?;
157
+ let key = KeyPair :: generate_for ( & PKCS_ECDSA_P256_SHA256 ) ?;
158
+
159
+ let cert = CertRequest :: builder ( )
160
+ . subject ( domain)
161
+ . alt_names ( & [ domain. to_string ( ) ] )
162
+ . key ( & key)
163
+ . build ( )
164
+ . signed_by ( & ca. cert , & ca. key ) ?;
165
+
166
+ fs:: write ( cert_path, cert. pem ( ) ) ?;
167
+ fs:: write ( key_path, key. serialize_pem ( ) ) ?;
168
+ Ok ( ( ) )
169
+ }
0 commit comments