Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JENKINS-73460] add FIPS compliance checks to plugin when running in FIPS mode #1590

Merged
merged 14 commits into from
Aug 1, 2024

Conversation

PereBueno
Copy link
Contributor

@PereBueno PereBueno commented Jul 18, 2024

https://issues.jenkins.io/browse/JENKINS-73460
Added checks for FIPS compliance when running in FIPS mode, behaviour when not running in FIPS mode is the same as before this change.
Validations are done in KubernetesCloud:

  • Check that skip TLS verification is not active in FIPS mode
  • Verify Kubernetes server is using HTTPS
  • Verify certificate is valid (FIPS 140-2 accepted algorithm and size).

These validations are checked in the descriptor, showing an error message in case they don't pass.

Also, validations are performed in correspondent @DataBoundSetters and readResolve, so it will avoid creating non compliant cloud configurations.

Testing done

Added 3 unit tests.
Manually checked form behaviour and errror messages.

Submitter checklist

  • Make sure you are opening from a topic/feature/bugfix branch (right side) and not your main branch!
  • Ensure that the pull request title represents the desired changelog entry
  • Please describe what you did
  • Link to relevant issues in GitHub or Jira
  • Link to relevant pull requests, esp. upstream and downstream changes
  • Ensure you have provided tests - that demonstrates feature works or fixes the issue

@PereBueno PereBueno changed the title [DRAFT] Jenkins-73460 [JENKINS-73460] add FIPS compliance checks to plugin whem runnign in FIPS mode Jul 19, 2024
@PereBueno PereBueno marked this pull request as ready for review July 19, 2024 12:00
@PereBueno PereBueno requested a review from a team as a code owner July 19, 2024 12:00
Copy link
Member

@jtnord jtnord left a comment

Choose a reason for hiding this comment

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

Looking at the way this is using Expcetions to transport messages and report errors elsewhere seems to be a way to loose infomation. (some of the exceptions (e.g. CertificateException) would need a stack trace, others are self contained (the key is not big enough).

I would suggest maybe swapping this around. Have the main checking inside a function that returns a FormValidation, and have the other method throw an exception if this does returns a FormValidation.kind == Kind.ERROR

(You shouldn't be able to create a key that is not big enough with a FIPS provider, but not all providers are equal so this is an acceptable check, so please also check how this behaves with BouncyCastle FIPS)

pom.xml Outdated Show resolved Hide resolved
Copy link
Member

@aneveux aneveux left a comment

Choose a reason for hiding this comment

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

Thanks a lot for the PR, I left a bunch of comments, mainly questions =)

Feel free to close nitpicks that are not interesting to you.

Comment on lines 979 to 983
try {
checkSkipTlsVerify(skipTlsVerify);
} catch (IllegalArgumentException ex) {
return FormValidation.error(ex, ex.getLocalizedMessage());
}
Copy link
Member

Choose a reason for hiding this comment

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

question: I am guessing that your idea is to avoid code duplication, and that you require a method doing the actual check and returning an Exception for using in DataboundSetters and the like?

Because if feels quite weird in these doCheck methods to actually rely on these exceptions to do the validation, especially later in other validations where you use RuntimeException.

What's the rationale for that design instead of using some other approach not requiring to catch these exceptions?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch with the RuntimeException, they should be IllegalArgumentException (autocpmplete changed it for an IllegalStateException 🤦 ).Changing it now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mainly to avoid duplication.
We could return a FormValidation object with an ok or the exception + message instead of throwing a exception, but then we would be checking in a FormValidation object in all the databoundsetters to launch the exception, which doesn't sound right.
We could also add another layer, having

  • check* methods perform the logic and returns an error string | null
  • assert* methods invoke check* and if return !null raise an exception
  • doCheck* methods invoke check* and return a FormValidation with the contents.

The problem I see with this approach is that we might have other exceptions (like in this test).
In this test we're trying to check validity of something that is not a certificate (not an invalid certificate, directly not a certificate). This raises a DecoderException and we want to keep the stack trace (that points to the original class finding the problem in bouncy castle). If the check* methods were doing this check we would lose the original exception.

Comment on lines 979 to 983
try {
checkSkipTlsVerify(skipTlsVerify);
} catch (IllegalArgumentException ex) {
return FormValidation.error(ex, ex.getLocalizedMessage());
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch with the RuntimeException, they should be IllegalArgumentException (autocpmplete changed it for an IllegalStateException 🤦 ).Changing it now.

Comment on lines 979 to 983
try {
checkSkipTlsVerify(skipTlsVerify);
} catch (IllegalArgumentException ex) {
return FormValidation.error(ex, ex.getLocalizedMessage());
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mainly to avoid duplication.
We could return a FormValidation object with an ok or the exception + message instead of throwing a exception, but then we would be checking in a FormValidation object in all the databoundsetters to launch the exception, which doesn't sound right.
We could also add another layer, having

  • check* methods perform the logic and returns an error string | null
  • assert* methods invoke check* and if return !null raise an exception
  • doCheck* methods invoke check* and return a FormValidation with the contents.

The problem I see with this approach is that we might have other exceptions (like in this test).
In this test we're trying to check validity of something that is not a certificate (not an invalid certificate, directly not a certificate). This raises a DecoderException and we want to keep the stack trace (that points to the original class finding the problem in bouncy castle). If the check* methods were doing this check we would lose the original exception.

@PereBueno PereBueno requested a review from aneveux July 25, 2024 08:04
Copy link
Member

@aneveux aneveux left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@aneveux aneveux merged commit d919fa5 into jenkinsci:master Aug 1, 2024
8 checks passed
@jglick
Copy link
Member

jglick commented Aug 1, 2024

@aneveux please remember to apply a classification label before merging any PR. Or implement jenkins-infra/interesting-category-action#1

@aneveux
Copy link
Member

aneveux commented Aug 2, 2024

Oh 🤦 Sorry about that, my bad.

How can I fix the situation for this PR? Create a new dummy one with proper labels to trigger a release? Or is there some manual action I can do to fix things?

@jglick
Copy link
Member

jglick commented Aug 2, 2024

Just apply the label now, and then (assuming you did want this in a release—e.g. enhancement) you can go to the Actions tab and trigger the CD workflow manually. Or any other PR merged (e.g., @dependabot) will trigger a release.

@aneveux aneveux added the enhancement Improvements label Aug 2, 2024
@timja timja changed the title [JENKINS-73460] add FIPS compliance checks to plugin whem runnign in FIPS mode [JENKINS-73460] add FIPS compliance checks to plugin when running in FIPS mode Aug 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Improvements
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants