Skip to content

selfsigned: warn when certs are issued with empty issuer DNs #3760

Merged
jetstack-bot merged 4 commits intocert-manager:masterfrom
SgtCoDFish:selfsigned-validity-3634
Mar 26, 2021
Merged

selfsigned: warn when certs are issued with empty issuer DNs #3760
jetstack-bot merged 4 commits intocert-manager:masterfrom
SgtCoDFish:selfsigned-validity-3634

Conversation

@SgtCoDFish
Copy link
Copy Markdown
Member

@SgtCoDFish SgtCoDFish commented Mar 10, 2021

What this PR does / why we need it: RFC 5280 states that the issuer field cannot be empty, but this is effectively the default for selfsigned certs where the user doesn't specify any part of the subject DN (and with selfsigned certs, the subject becomes the issuer).

There are also some smaller tweaks to comments I discovered as part of this work.

/kind bug

Which issue this PR fixes: fixes #3634 (sort of)

Release note:

selfsigned issuer: warn when certs have empty issuer DNs, in violation of TLS RFC 5280

@jetstack-bot jetstack-bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. kind/bug Categorizes issue or PR as related to a bug. dco-signoff: yes Indicates that all commits in the pull request have the valid DCO sign-off message. labels Mar 10, 2021
@jetstack-bot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: SgtCoDFish

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@jetstack-bot jetstack-bot requested a review from wallrj March 10, 2021 17:52
@jetstack-bot jetstack-bot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Mar 10, 2021
@SgtCoDFish
Copy link
Copy Markdown
Member Author

there are clearly some missing pieces here based on the tests! I'd missed the e2es

@SgtCoDFish SgtCoDFish force-pushed the selfsigned-validity-3634 branch from d47321e to 5577570 Compare March 10, 2021 19:53
@SgtCoDFish
Copy link
Copy Markdown
Member Author

/retest

@JoshVanL
Copy link
Copy Markdown
Contributor

/assign

Copy link
Copy Markdown
Contributor

@JoshVanL JoshVanL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the code itself looks good, but am curious as to why this is needed in the first place. In the case of selfsigned issuers, I am strongly in favour of users being able to request exactly what they asked for. If a DN is required for whatever application the user is using, then it makes sense that the user request it.

It also doesn't make sense to me that the subject would default to cert-manager, when the application using is probably not cert-manager.

/unassign
/assign @SgtCoDFish

@jetstack-bot jetstack-bot assigned SgtCoDFish and unassigned JoshVanL Mar 12, 2021
@SgtCoDFish
Copy link
Copy Markdown
Member Author

I think the code itself looks good, but am curious as to why this is needed in the first place. In the case of selfsigned issuers, I am strongly in favour of users being able to request exactly what they asked for.

I understand the desire to allow maximum control and I generally agree; I think my caveat would be that users should be able to request exactly what they ask for as long as it's in spec. Otherwise, inevitably, you end up getting bitten by the cert being invalid somewhere down the road, as happened in #3634

My concern is the following:

  1. foobar v1 loads an invalid selfsigned cert with no issuer DN and everything works
  2. foobar v2's TLS library strengthens its existing checks - entirely within spec - and refuses to start because it can't load the cert - even if it's the exact same cert that worked perfectly with foobar v1. This causes an outage.
  3. The engineer responsible angrily raises a ticket against cert-manager

This is similar to what can happen with non-critical x509 extensions, which I've seen cause pretty significant outages in the past as newer versions of Chrome started to understand and enforce those non-critical extensions. It's a ticking time-bomb.

More generally, I think my position is that cert-manager should not, by default, allow the issuance of a cert for TLS which violates the spec, and to treat anywhere that it's possible to generate an invalid cert as a bug. Maybe cert-manager could have a flag like --allow-issuing-invalid-certs which defaults to false, to maintain the ability to generate an invalid cert in instances like this, but I don't really know why anyone would want that outside of maybe testing

@SgtCoDFish
Copy link
Copy Markdown
Member Author

SgtCoDFish commented Mar 12, 2021

It also doesn't make sense to me that the subject would default to cert-manager, when the application using is probably not cert-manager.

Yeah I understand this - we could just pull a DNS name out of the SAN extension. My thought process was:

if they were going to issue a cert with a blank subject they probably don't care what's in there, so default to something inoffensive to the tune of 'issued by cert-manager'

@maelvls
Copy link
Copy Markdown
Member

maelvls commented Mar 15, 2021

Will take a look today!

/assign

@maelvls
Copy link
Copy Markdown
Member

maelvls commented Mar 16, 2021

I think we would also need to update https://cert-manager.io/docs/configuration/selfsigned with the change made to the self signed issuer API behavior, and explain that if a certificate is created without a commonName, then a default DN OU=cert-manager self-signed cert will be used.

Regarding the release-note: since we changed the API, I think we also need to be more specific with regards to the message.

Suggestion in cert-manager.io:

The SelfSigned Issuer now makes sure to generate certificates that contain a non-empty issuer DN (distinguished name). We made this change in accordance with RFC 5280 which states that "the issuer field MUST contain a non-empty distinguished name (DN)". The SelfSigned Issuer will fill the certificate's issuer DN field with whatever is in the certificate's template subject DN. If the certificate's subject DN hasn't been set in some way (e.g. through an annotation or using the spec.commonName field), the issuer DN defaults to the first DNS name available in the certificate; if no DNS name is available, the issuer DN OU=cert-manager self-signed cert is used. (#3634)

Suggestion for the release-notes:

```release-note
The SelfSigned Issuer now makes sure to generate certificates that contain a non-empty issuer DN (distinguished name). We made this change in accordance with [RFC 5280](https://tools.ietf.org/html/rfc5280#section-4.1.2.4) which states that "the issuer field MUST contain a non-empty distinguished name (DN)". The SelfSigned Issuer will fill the certificate's issuer DN field with whatever is in the certificate's template subject DN. If the certificate's subject DN hasn't been set in some way (e.g. through an annotation or using the spec.commonName field), the issuer DN defaults to the first DNS name available in the certificate; if no DNS name is available, the issuer DN `OU=cert-manager self-signed cert` is used. (#3634)
```

@maelvls
Copy link
Copy Markdown
Member

maelvls commented Mar 16, 2021

Done with my review!
/unassign

it's conceivable that in the future we could have Ed25519 certs,
which would also have a key size of 256 but would be a new named entry
here

Signed-off-by: Ashley Davis <ashley.davis@jetstack.io>
this behaviour seems to be handled by translateIngressAnnotations

Signed-off-by: Ashley Davis <ashley.davis@jetstack.io>
Signed-off-by: Ashley Davis <ashley.davis@jetstack.io>
@SgtCoDFish SgtCoDFish force-pushed the selfsigned-validity-3634 branch 2 times, most recently from ddd6f3a to a8d98da Compare March 19, 2021 15:08
@SgtCoDFish
Copy link
Copy Markdown
Member Author

/retest

@munnerz
Copy link
Copy Markdown
Member

munnerz commented Mar 24, 2021

I think the code itself looks good, but am curious as to why this is needed in the first place. In the case of selfsigned issuers, I am strongly in favour of users being able to request exactly what they asked for. If a DN is required for whatever application the user is using, then it makes sense that the user request it.

I'd strongly lean in favor of Josh's comment here - we previously used to default other fields (like 'Organization') in a similar way, and ended out having to remove it. There are many ways you can violate RFCs with x509, and whilst I think we should help guide users to create valid certificates, we shouldn't do so by affixing things like this IMO.

Could we instead add some clear guidance into the documentation, and potentially also fire an Event in the selfsigned certificaterequest controller to note that it has signed a certificate that does not specify a DN and may be incompatible with some clients (and link to the relevant part of the RFC?)

@SgtCoDFish
Copy link
Copy Markdown
Member Author

Could we instead add some clear guidance into the documentation, and potentially also fire an Event in the selfsigned certificaterequest controller to note that it has signed a certificate that does not specify a DN and may be incompatible with some clients (and link to the relevant part of the RFC?)

This does seem reasonable, and I'd be happy to be outvoted and take that approach. That said, I still view outputting a warning Event as being inferior to just preventing the issue entirely; I think what's missing for me is the reasoning:

we previously used to default other fields (like 'Organization') in a similar way, and ended out having to remove it.

why did it have to be removed? was it being added to address a similar issue to what we have here?

whilst I think we should help guide users to create valid certificates, we shouldn't do so by affixing things like this IMO.

again, I'd be really interested to know why you hold this belief.

For context, I'm in a situation ATM which I'm sure we've all been in at some point: this change seemed super clear and obvious to me and I was really surprised to see any pushback on it at all. (That of course doesn't mean I'm right or that my approach in this PR is right!)

The fact that I was so surprised hints to me that I'm maybe missing some part of the bigger picture - maybe I'm over-focusing on the scenario I described here (which is a situation I've seen cause huge problems before) and I'm missing something as a result.

@maelvls
Copy link
Copy Markdown
Member

maelvls commented Mar 25, 2021

we previously used to default other fields (like 'Organization') in a similar way, and ended out having to remove it.

I guess my lack of X.509 knowledge prevents me from understanding the full implications of the "defaulting" that I thought I a good idea in this PR.

Could we have more information about the removal of Organization? Why did we have to remove it?

@SgtCoDFish SgtCoDFish force-pushed the selfsigned-validity-3634 branch from a8d98da to 86e46e8 Compare March 25, 2021 19:31
@SgtCoDFish SgtCoDFish changed the title selfsigned: prevent certs with empty issuer DNs selfsigned: warn when certs are issued with empty issuer DNs Mar 26, 2021
@SgtCoDFish SgtCoDFish force-pushed the selfsigned-validity-3634 branch from 86e46e8 to 1298973 Compare March 26, 2021 09:55
Copy link
Copy Markdown
Contributor

@JoshVanL JoshVanL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple things from me

/assign @SgtCoDFish


func runTest(t *testing.T, test testT) {
test.builder.T = t
//test.builder.Recorder = new(testpkg.FakeRecorder)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still needs to be removed 😅

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm an expert at finding ways to shoot myself in the foot with git 👍

@SgtCoDFish SgtCoDFish force-pushed the selfsigned-validity-3634 branch from 1298973 to 87e71eb Compare March 26, 2021 11:13
@SgtCoDFish
Copy link
Copy Markdown
Member Author

The latest comments should now be addressed 👍


func runTest(t *testing.T, test testT) {
test.builder.T = t
//test.builder.Recorder = new(testpkg.FakeRecorder)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still needs to be removed 😅

@SgtCoDFish SgtCoDFish force-pushed the selfsigned-validity-3634 branch from 87e71eb to 5e31fa3 Compare March 26, 2021 11:51
as raised in#3634 - RFC 5280 states that the issuer field cannot be
empty, but this could easily happen with selfsigned certs which had
an empty subject (as the issuer matches the subject when the cert is
self signed)

this commit detects when a cert would be issued selfsigned with an
empty subject DN and emits a warning event, allowing cluster operators
to detect the warning and potentially either re-issue to generate a
compliant cert, or else accept the risk.

Signed-off-by: Ashley Davis <ashley.davis@jetstack.io>
@JoshVanL
Copy link
Copy Markdown
Contributor

/lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. dco-signoff: yes Indicates that all commits in the pull request have the valid DCO sign-off message. kind/bug Categorizes issue or PR as related to a bug. lgtm Indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Empty issuer DN when using selfSigned

5 participants