Description
Describe the bug:
When a certificate resource contains both cert sign
and another non-CA usage (such as server auth
), the x509 certificate produced by cert-manager splits the usage between X509v3 Key Usage
and X509v3 Extended Key Usage
fields. Per RFC5280 4.2.1.12,
If a certificate contains both a key usage extension and an extended
key usage extension, then both extensions MUST be processed
independently and the certificate MUST only be used for a purpose
consistent with both extensions. If there is no purpose consistent
with both extensions, then the certificate MUST NOT be used for any
purpose.
Because the usages are split between the key usage and extended key usage fields, the produced certificates are not valid for any of the usages.
Expected behaviour:
There key usage and extended key usage fields should have the same values set, or one of them should have no values set at all.
Steps to reproduce the bug:
-
Deploy a certificate with
cert sign
andserver auth
usage:--- # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/cert-manager.io/certificate_v1.json apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: example-cert spec: isCA: true # Self-signed cert must be a CA commonName: Self signed cert dnsNames: &domain_names - some-domain.com usages: - server auth # Self-signed cert must be able to sign itself - cert sign - crl sign # Allow only signing for the license domain name nameConstraints: critical: true permitted: dnsDomains: *domain_names issuerRef: name: self-signed-issuer kind: ClusterIssuer group: cert-manager.io secretName: example-cert
-
Get the signed cert and check the key usage via openssl:
$ kubectl get secrets -n monitoring example-cert -o json | jq -r '.data["tls.crt"]' | base64 -d | openssl x509 -noout -text | grep -A4 'X509v3 extensions' X509v3 extensions: X509v3 Key Usage: critical Certificate Sign, CRL Sign X509v3 Extended Key Usage: TLS Web Server Authentication
If deployed to a basic webserver (i.e. nginx with bare minimum config), openssl reject this certificate due to 26 (unsupported certificate purpose)
$ echo | openssl s_client -connect some-domain.com:443
... # Unrelated lines omitted
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1567 bytes and written 443 bytes
Verification error: unsupported certificate purpose
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 26 (unsupported certificate purpose)
---
DONE
Anything else we need to know?:
Environment details:
- Kubernetes version: N/A
- Cloud-provider/provisioner: N/A
- cert-manager version: 1.17.1
- Install method: e.g. helm/static manifests Helm
/kind bug