Skip to content

Commit 9a23e70

Browse files
maltesandersbernauerTechassi
authored
Make RSA key length configurable (#506)
* make key length configurable * adapted changelog * rename key length enum variants * cargo fmt * fix unit tests * fmt * improve crd schema * add comments * yaml lint * add documentation * improvements * fixes * Apply suggestions from code review Co-authored-by: Sebastian Bernauer <[email protected]> * set default key length to 2048 * adapt key length default and values * use constants for key length * trailing whitespace * Apply suggestions from code review Co-authored-by: Sebastian Bernauer <[email protected]> * explicitly use serde default * improve docs * fix clippy /test * improve docs * fmt * fix test * Update rust/operator-binary/src/crd.rs Co-authored-by: Sebastian Bernauer <[email protected]> * regenerate charts * bump tonic due to cargo deny * rename struct * improve doc header * Update deploy/helm/secret-operator/crds/crds.yaml Co-authored-by: Techassi <[email protected]> * consistently switched to key pair instead of keypair * improve docs * regenerate charts * fix * fix --------- Co-authored-by: Sebastian Bernauer <[email protected]> Co-authored-by: Techassi <[email protected]>
1 parent 09c36f1 commit 9a23e70

File tree

12 files changed

+181
-33
lines changed

12 files changed

+181
-33
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
88

99
- Active Directory's `samAccountName` generation can now be customized ([#454]).
1010
- Added experimental cert-manager backend ([#482]).
11+
- Make RSA key length configurable ([#506]).
1112

1213
### Fixed
1314

@@ -25,6 +26,7 @@ All notable changes to this project will be documented in this file.
2526
[#495]: https://github.com/stackabletech/secret-operator/pull/495
2627
[#497]: https://github.com/stackabletech/secret-operator/pull/497
2728
[#505]: https://github.com/stackabletech/secret-operator/pull/505
29+
[#506]: https://github.com/stackabletech/secret-operator/pull/506
2830

2931
## [24.7.0] - 2024-07-24
3032

Cargo.lock

+11-19
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deploy/helm/secret-operator/crds/crds.yaml

+23-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ spec:
4040
description: |-
4141
The [`autoTls` backend](https://docs.stackable.tech/home/nightly/secret-operator/secretclass#backend-autotls) issues a TLS certificate signed by the Secret Operator. The certificate authority can be provided by the administrator, or managed automatically by the Secret Operator.
4242
43-
A new certificate and keypair will be generated and signed for each Pod, keys or certificates are never reused.
43+
A new certificate and key pair will be generated and signed for each Pod, keys or certificates are never reused.
4444
properties:
4545
ca:
4646
description: Configures the certificate authority used to issue Pod certificates.
@@ -58,6 +58,28 @@ spec:
5858
5959
If `autoGenerate: true` then the Secret Operator will prepare a new CA certificate the old CA approaches expiration. If `autoGenerate: false` then the Secret Operator will log a warning instead.
6060
type: string
61+
keyGeneration:
62+
default:
63+
rsa:
64+
length: 2048
65+
description: The algorithm used to generate a key pair and required configuration settings. Currently only RSA and a key length of 2048, 3072 or 4096 bits can be configured.
66+
oneOf:
67+
- required:
68+
- rsa
69+
properties:
70+
rsa:
71+
properties:
72+
length:
73+
description: The amount of bits used for generating the RSA keypair. Currently, `2048`, `3072` and `4096` are supported. Defaults to `2048` bits.
74+
enum:
75+
- 2048
76+
- 3072
77+
- 4096
78+
type: integer
79+
required:
80+
- length
81+
type: object
82+
type: object
6183
secret:
6284
description: Reference (name and namespace) to a Kubernetes Secret object where the CA certificate and key is stored in the keys `ca.crt` and `ca.key` respectively.
6385
properties:

deploy/helm/secret-operator/templates/secret_migration_job.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
# Migrates the TLS CA keypair from the hard-coded default namespace to the operator namespace
2+
# Migrates the TLS CA key pair from the hard-coded default namespace to the operator namespace
33
# See https://github.com/stackabletech/secret-operator/issues/453
44
apiVersion: batch/v1
55
kind: Job
@@ -52,4 +52,4 @@ spec:
5252
echo "$source_ca_secret" | jq 'del(.metadata["namespace","creationTimestamp","resourceVersion","selfLink","uid"])' | kubectl apply -n $TARGET_NAMESPACE -f -
5353
fi
5454
fi
55-
restartPolicy: Never
55+
restartPolicy: Never
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
apiVersion: secrets.stackable.tech/v1alpha1
3+
kind: SecretClass
4+
metadata:
5+
name: tls
6+
spec:
7+
backend:
8+
autoTls:
9+
ca:
10+
secret:
11+
name: secret-provisioner-tls-ca
12+
namespace: default
13+
keyGeneration: # <1>
14+
rsa: # <2>
15+
length: 4096 # <3>

docs/modules/secret-operator/pages/secretclass.adoc

+22-2
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,33 @@ Each SecretClass is a associated with a single backend, which dictates the mecha
3131
Issues a TLS certificate signed by the Secret Operator.
3232
The certificate authority can be provided by the administrator, or managed automatically by the Secret Operator.
3333

34-
A new certificate and keypair will be generated and signed for each Pod, keys or certificates are never reused.
34+
A new certificate and key pair will be generated and signed for each Pod, keys or certificates are never reused.
3535

3636
CAUTION: Attributes of the certificate (such as the expiration date, fingerprint, or serial number) will be regenerated for each
3737
Pod, and should not be expected to be stable.
3838

3939
xref:scope.adoc[Scopes] are used to populate the claims (such as `subjectAlternateName`) of the provisioned certificates.
4040

41+
[#backend-tls-certificate-key-pair-generation]
42+
=== `TLS certificate key pair generation`
43+
44+
Currently, only RSA is supported in the `autoTls` backend.
45+
You can however configure the key length for generated private keys. If not specified it will default to `2048` bits.
46+
47+
----
48+
include::example$secretclass-tls-key-length.yaml[]
49+
----
50+
<1> `autoTls.ca.keyGeneration` specifies which algorithm and additional parameters are used
51+
<2> `autoTls.ca.keyGeneration.rsa` specifies the RSA key pair algorithm (RSA currently is the only one supported)
52+
<3> `autoTls.ca.keyGeneration.rsa.length` specifies the amount of bits used for generating the RSA key pair. Currently, `2048`, `3072` and `4096` are supported. Defaults to `2048` bits.
53+
54+
CAUTION: Using more than `2048` bits will significantly increase the computation time to create new key pairs.
55+
The SSL Labs https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices[SSL and TLS Deployment Best Practices] as of 2024-10-01 recommend
56+
57+
> For most websites, using RSA keys stronger than 2,048 bits and ECDSA keys stronger than 256 bits is a waste of CPU power and might impair user experience
58+
59+
If options higher than `2048` are chosen, the CPU resources for the secret operator should be increased in order to avoid Pods being stuck in `Pending` waiting for the computation of their key pair.
60+
4161
==== Certificate lifetime
4262

4363
By default the Secret Operator will generally aim to use as short-lived certificates as possible.
@@ -375,7 +395,7 @@ The secret contains the following files:
375395
Both stores are encrypted, with an empty string as the passphrase.
376396

377397
NOTE: When using the xref:#backend-k8ssearch[] backend, it is _strongly_ recommended to store secrets in the use the xref:#format-tls-pem[] format instead.
378-
The secret operator supports converting PEM keypairs into PKCS#12, but not the other way around.
398+
The secret operator supports converting PEM key pairs into PKCS#12, but not the other way around.
379399

380400
[#format-kerberos]
381401
=== Kerberos

rust/operator-binary/build.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ fn main() {
66
let out_dir = PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR is required"));
77
tonic_build::configure()
88
.file_descriptor_set_path(out_dir.join("file_descriptor_set.bin"))
9-
.compile(&["vendor/csi/csi.proto"], &["vendor/csi"])
9+
.compile_protos(&["vendor/csi/csi.proto"], &["vendor/csi"])
1010
.unwrap();
1111
built::write_built_file().unwrap();
1212
}

rust/operator-binary/src/backend/tls/ca.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use tracing::{info, info_span, warn};
3434

3535
use crate::{
3636
backend::SecretBackendError,
37+
crd::CertificateKeyGeneration,
3738
utils::{asn1time_to_offsetdatetime, Asn1TimeParseError, Unloggable},
3839
};
3940

@@ -153,6 +154,9 @@ pub struct Config {
153154
/// Hence, this value _should_ be larger than the PKI's maximum certificate lifetime,
154155
/// and smaller than [`Self::ca_certificate_lifetime`].
155156
pub rotate_if_ca_expires_before: Option<Duration>,
157+
158+
/// Configuration how TLS private keys should be created.
159+
pub key_generation: CertificateKeyGeneration,
156160
}
157161

158162
/// A single certificate authority certificate.
@@ -188,7 +192,12 @@ impl CertificateAuthority {
188192
let not_before = now - Duration::from_minutes_unchecked(5);
189193
let not_after = now + config.ca_certificate_lifetime;
190194
let conf = Conf::new(ConfMethod::default()).unwrap();
191-
let private_key = Rsa::generate(2048)
195+
196+
let private_key_length = match config.key_generation {
197+
CertificateKeyGeneration::Rsa { length } => length,
198+
};
199+
200+
let private_key = Rsa::generate(private_key_length)
192201
.and_then(PKey::try_from)
193202
.context(GenerateKeySnafu)?;
194203
let certificate = X509Builder::new()

rust/operator-binary/src/backend/tls/mod.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use stackable_operator::{
2828
use time::OffsetDateTime;
2929

3030
use crate::{
31-
crd,
31+
crd::{self, CertificateKeyGeneration},
3232
format::{well_known, SecretData, WellKnownSecretData},
3333
utils::iterator_try_concat_bytes,
3434
};
@@ -132,12 +132,13 @@ impl SecretBackendError for Error {
132132
pub struct TlsGenerate {
133133
ca_manager: ca::Manager,
134134
max_cert_lifetime: Duration,
135+
key_generation: CertificateKeyGeneration,
135136
}
136137

137138
impl TlsGenerate {
138139
/// Check if a signing CA has already been instantiated in a specified Kubernetes secret - if
139140
/// one is found the key is loaded and used for signing certs.
140-
/// If no current authority can be found, a new keypair and self signed certificate is created
141+
/// If no current authority can be found, a new key pair and self signed certificate is created
141142
/// and stored for future use.
142143
/// This allows users to provide their own CA files, but also enables secret-operator to generate
143144
/// an independent self-signed CA.
@@ -147,6 +148,7 @@ impl TlsGenerate {
147148
secret: ca_secret,
148149
auto_generate: auto_generate_ca,
149150
ca_certificate_lifetime,
151+
key_generation,
150152
}: &crd::AutoTlsCa,
151153
max_cert_lifetime: Duration,
152154
) -> Result<Self> {
@@ -158,11 +160,13 @@ impl TlsGenerate {
158160
manage_ca: *auto_generate_ca,
159161
ca_certificate_lifetime: *ca_certificate_lifetime,
160162
rotate_if_ca_expires_before: Some(*ca_certificate_lifetime / 2),
163+
key_generation: key_generation.clone(),
161164
},
162165
)
163166
.await
164167
.context(LoadCaSnafu)?,
165168
max_cert_lifetime,
169+
key_generation: key_generation.clone(),
166170
})
167171
}
168172
}
@@ -171,7 +175,7 @@ impl TlsGenerate {
171175
impl SecretBackend for TlsGenerate {
172176
type Error = Error;
173177

174-
/// Generate a keypair and sign it with the CA key.
178+
/// Generate a key pair and sign it with the CA key.
175179
/// Then add the ca certificate and return these files for provisioning to the volume.
176180
async fn get_secret_data(
177181
&self,
@@ -233,7 +237,12 @@ impl SecretBackend for TlsGenerate {
233237
}
234238

235239
let conf = Conf::new(ConfMethod::default()).unwrap();
236-
let pod_key = Rsa::generate(2048)
240+
241+
let pod_key_length = match self.key_generation {
242+
CertificateKeyGeneration::Rsa { length } => length,
243+
};
244+
245+
let pod_key = Rsa::generate(pod_key_length)
237246
.and_then(PKey::try_from)
238247
.context(GenerateKeySnafu)?;
239248
let mut addresses = Vec::new();

0 commit comments

Comments
 (0)