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

Add credential management to custom files #90

Merged
merged 1 commit into from
Apr 21, 2021

Conversation

tykeal
Copy link
Contributor

@tykeal tykeal commented Oct 15, 2020

With the advent of Jenkins Configuration As Code (JCasC) it has become
more needed to be able to provide a way to allow job owners to provide
new managed configuration files that also replace tokenized credentials.
While it is possible to attain this goal by utilizing the Credentials
Binding Plugin along with the 'Replace All' option when defining where
the file is put on disk during the job this has caused several problems
with well established methods of managing the jobs. In particular, jobs
being managed with Jenkins Job Builder which tend to be heavily
Freestyle in nature and also utilize a lot of templates and macros
suffer greatly when using this method of management.

Instead, allowing credentials to be defined and automatically replaced
when the file is rendered down to disk solves the problem of securely
storing the credentials in the credential store and also allowing less
privileged persons the ability to more easily work with the managed
files.

This change in particular modifies the 'custom' file type to support
defining credentials along with the tokens that are to be used and
having them properly rendered when being put down on disk. It will
continue to work fine with the previous method using the Credentials
Binding Plugin as well as it will only replace the tokens that it has a
full definition for and then would be passed through the full
environment token replacement as well as it did before this change.

Making this change allows for safe storage of configuration files in
JCasC format to be stored in a repository and in some fashion
manipulated into place for Jenkins to utilize (exercise for the admin)
which is a partial answer to JENKINS-17766. It also completely obviates
the requirement to encrypt the files as per JENKINS-18635 as the
sensitive data can now be securely separated from the non-sensitive
data.

Resolves: JENKINS-43204
Signed-off-by: Andrew Grimberg agrimberg@linuxfoundation.org

@tykeal
Copy link
Contributor Author

tykeal commented Oct 26, 2020

@imod any chance you could look this over especially since JENKINS-43204 is assigned to you?

Copy link
Member

@imod imod left a comment

Choose a reason for hiding this comment

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

I have not touched the code for quite a while so I'm not fully up to date anymore. But from the first look at it, it seems good. Just some one minor point...
I will try to get back to it once you have made the change, but to do a release, I need to reactivate my credentials first...


public CustomConfigProvider() {
load();
}

@Override
public ContentType getContentType() {
return null;
return ContentType.DefinedType.SHELL;
Copy link
Member

Choose a reason for hiding this comment

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

so per default new configs are shell-scripts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, it seems to make the most sense to make them "shell" type scripts. I'm leveraging the Token Macro plugin for replacing the variables and they're all shell type variables.

import java.util.logging.Level;
import java.util.logging.Logger;

public class CredentialsHelper {
Copy link
Member

Choose a reason for hiding this comment

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

please rename to clearly separate from the org.jenkinsci.plugins.configfiles.maven.security.CredentialsHelper (specially as they also have similar methods). Maybe even rename both:

  • org.jenkinsci.plugins.configfiles.maven.security.MavenConfigCredentialsHelper
  • org.jenkinsci.plugins.configfiles.custom.security.CustomConfigCredentialsHelper

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can definitely do that. I'll get a new version up later today.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I've updated to org.jenkinsci.plugins.configfiles.custom.security.CustomConfigCredentialsHelper. I'll likely work on a separate commit for the maven class change.

@tykeal
Copy link
Contributor Author

tykeal commented Nov 3, 2020

@imod can you take a look again? My team is hoping to see this merged / released sometime soonish so that we can roll out new support options for our customers using it an JCasC!

Copy link

@Aricg Aricg left a comment

Choose a reason for hiding this comment

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

lgtm, eager to implement this.

@Aricg
Copy link

Aricg commented Nov 26, 2020

Bumping again, cause I don't want to maintain a fork. 🙏

@imod
Copy link
Member

imod commented Nov 30, 2020

@Aricg @tykeal sorry, but I just can't find the time anymore - this plugin is looking for a new maintainer

https://groups.google.com/g/jenkinsci-dev/c/aCmm2MyydNA/m/_WogLPs7AgAJ

@tykeal
Copy link
Contributor Author

tykeal commented Dec 2, 2020

@imod if you're ok with it, I'll put my name forward for maintainership of this plugin. I'll send a response to the dev list on the mail thread with the info that's noted in https://www.jenkins.io/doc/developer/plugin-governance/adopt-a-plugin/

@daniel-beck
Copy link
Member

I'm fairly sure this PR introduces a security vulnerability. I strongly recommend it not be merged.

Copy link
Member

@daniel-beck daniel-beck left a comment

Choose a reason for hiding this comment

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

Per above (not a maintainer)

@tykeal
Copy link
Contributor Author

tykeal commented Dec 2, 2020

@daniel-beck I'll admit that this is my first time doing any sort of Java development in a very long time, but I'm failing to see where the security vulnerability is. In what way is it being introduced? I'm more than happy to work through any issues but I'm needing them pointed out.

If it's because of the old version of plain-credentials plugin being added, my intent was to find the newest version of the plugin that worked with the existing code base so as to not have to do upgrades all over the place of dependencies first.

Using the latest version of that plugin basically pushed me down a deep rabbit hole of updates all over the place in the plugin which was not the point of this PR

@jenkinsci jenkinsci deleted a comment from tykeal Dec 3, 2020
@imod
Copy link
Member

imod commented Dec 3, 2020

@tykeal thanks for taking the lead!

@daniel-beck
Copy link
Member

Hold on… moving the conversation to our private tracker.

public static class DescriptorImpl extends Descriptor<CustomizedCredentialMapping> {

public ListBoxModel doFillCredentialsIdItems(@AncestorInPath ItemGroup context, @QueryParameter String tokenKey) {
AccessControlled _context = (context instanceof AccessControlled ? (AccessControlled) context : Jenkins.get());
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jvz ah... ok. I lifted some of that code from elsewhere in the plugin.

The maven and properties credential mappings both do it that way as well. I was sort of feeling my way around trying to get this to work given my examples in the plugin only dealt with the StandardUsernameCredentials and I also need to add in the StringCredentials from plain-credentials plugin.

Copy link
Member

@jvz jvz Dec 4, 2020

Choose a reason for hiding this comment

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

Mentioning here as I said this in private: the code here isn't necessarily wrong, but it's overly restrictive in its permission checks. The checks for Item.CONFIGURE should be replaced by checks to CredentialsProvider.USE_ITEM when validating whether or not credentials should be allowed to be used. This will allow Authorize Project to work properly here (otherwise, users with the ability to use credentials from a build as well as the permission to build the job would not be able to access the credentials when the job is run; the UseItem permission addresses this authorization issue). Essentially, a user who can build the job shouldn't also need permission to configure it just for the credentials to work (without Authorize Project installed, you wouldn't notice this problem since builds are executed as the system user normally, and that has permission to access almost any credentials).

I will note, though, that the doFill... and doCheck... methods for credentials can safely use Item.CONFIGURE as the permission check as that makes sense, but the code that resolves credentials ids into IdCredentials instances should certainly be checking the CredentialsProvider.USE_ITEM permission instead.

@tykeal tykeal force-pushed the tokenized branch 2 times, most recently from aa11b93 to 6791cc4 Compare December 11, 2020 17:49
@tykeal
Copy link
Contributor Author

tykeal commented Dec 11, 2020

@daniel-beck @imod @jvz I believe I've fixed all of your requests.

Copy link
Member

@jvz jvz left a comment

Choose a reason for hiding this comment

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

That looks much better, thanks!

@tykeal
Copy link
Contributor Author

tykeal commented Dec 14, 2020

Great, just need @daniel-beck and @imod to weigh in then :D (or at least @daniel-beck since he's the one with a change request on the change!

@tykeal
Copy link
Contributor Author

tykeal commented Dec 29, 2020

Bumping. @daniel-beck and @imod but primarily @daniel-beck since his review is currently blocking any merge from what I can see.

@tykeal
Copy link
Contributor Author

tykeal commented Jan 27, 2021

bumping again. @daniel-beck @imod what do I need to do to get this merged and a new release out?

@tykeal
Copy link
Contributor Author

tykeal commented Mar 3, 2021

Bumping on this thread. I feel like a broken record here. Really trying to get this change merged since it's been nearly 5 months since I raised the initial PR and nearly 3 months since the last actual touch of code.

I and my team would really like to see this get merged and a release with it happen. We don't really like installing self-hosted plugins into the Jenkins systems we manage, it makes it a lot harder for our customers to replicate our open infra if they need to for some reason!

@daniel-beck daniel-beck self-requested a review March 9, 2021 15:44
@daniel-beck
Copy link
Member

Actual build failure:

[ERROR] Medium: Null passed for non-null parameter of com.cloudbees.plugins.credentials.common.AbstractIdCredentialsListBoxModel.includeMatchingAs(Authentication, Item, Class, List, CredentialsMatcher) in org.jenkinsci.plugins.configfiles.custom.security.CustomizedCredentialMapping$DescriptorImpl.doFillCredentialsIdItems(Item, String) [org.jenkinsci.plugins.configfiles.custom.security.CustomizedCredentialMapping$DescriptorImpl, org.jenkinsci.plugins.configfiles.custom.security.CustomizedCredentialMapping$DescriptorImpl, org.jenkinsci.plugins.configfiles.custom.security.CustomizedCredentialMapping$DescriptorImpl] Method invoked at CustomizedCredentialMapping.java:[line 96]Null value at CustomizedCredentialMapping.java:[line 84]Known null at CustomizedCredentialMapping.java:[line 85] NP_NULL_PARAM_DEREF

@daniel-beck
Copy link
Member

Looks like my ad-hoc suggestion was wrong, sorry about that. The correct behavior is to pass the same object that the permission is checked on.

Once this is resolved, I have no further concerns about this PR.

@tykeal
Copy link
Contributor Author

tykeal commented Mar 12, 2021

@daniel-beck ah, I wonder why it didn't blow up when I did my local build to make sure it still built. :-/ Ok, I'll revert back what I had.

@tykeal
Copy link
Contributor Author

tykeal commented Mar 12, 2021

@daniel-beck ok, I've reverted the change I had made that you had requested.

@daniel-beck
Copy link
Member

This original version is certainly wrong.

My suggestion fails because of an unexpectedly restrictive annotation in credentials-plugin: includeMatchingAs does not allow null item, while the CredentialsProvider#listCredentials it calls allows it.

Sadly we cannot pass item == null ? Jenkins.get() : item because Java 😞

@daniel-beck
Copy link
Member

https://gist.github.com/daniel-beck/4571f2849349c9bb16ad033b15c63016 should do it. It's not pretty, but should work as expected.

Pinging @jvz and @jeffret-b who are maintainers of Credentials Plugin and may have a better idea how this API is supposed to be used without code duplication.

@jvz
Copy link
Member

jvz commented Mar 12, 2021

That looks like it should work fine.

With the advent of Jenkins Configuration As Code (JCasC) it has become
more needed to be able to provide a way to allow job owners to provide
new managed configuration files that also replace tokenized credentials.
While it is possible to attain this goal by utilizing the Credentials
Binding Plugin along with the 'Replace All' option when defining where
the file is put on disk during the job this has caused several problems
with well established methods of managing the jobs. In particular, jobs
being managed with Jenkins Job Builder which tend to be heavily
Freestyle in nature and also utilize a lot of templates and macros
suffer greatly when using this method of management.

Instead, allowing credentials to be defined and automatically replaced
when the file is rendered down to disk solves the problem of securely
storing the credentials in the credential store and also allowing less
privileged persons the ability to more easily work with the managed
files.

This change in particular modifies the 'custom' file type to support
defining credentials along with the tokens that are to be used and
having them properly rendered when being put down on disk. It will
continue to work fine with the previous method using the Credentials
Binding Plugin as well as it will only replace the tokens that it has a
full definition for and then would be passed through the full
environment token replacement as well as it did before this change.

Making this change allows for safe storage of configuration files in
JCasC format to be stored in a repository and in some fashion
manipulated into place for Jenkins to utilize (exercise for the admin)
which is a partial answer to JENKINS-17766. It also completely obviates
the requirement to encrypt the files as per JENKINS-18635 as the
sensitive data can now be securely separated from the non-sensitive
data.

Resolves: JENKINS-43204
Signed-off-by: Andrew Grimberg <agrimberg@linuxfoundation.org>
@tykeal
Copy link
Contributor Author

tykeal commented Mar 15, 2021

@daniel-beck thanks for that. Yes, it works just fine and that code is definitely a lot better than what I had!

@tykeal
Copy link
Contributor Author

tykeal commented Apr 9, 2021

@daniel-beck @imod I'm crying here... what do I need to do to get this over the finish line??

@jvz
Copy link
Member

jvz commented Apr 9, 2021

Daniel isn't a maintainer of this plugin. Maintainers listed are: @olamy @jglick @rsandell @cyrille-leclerc @imod @alecharp @varyvol @MRamonLeon

@MRamonLeon
Copy link
Contributor

If @daniel-beck, who has been working actively, approve this I'm happy to merge. Not sure if I may consider his thumbs-up in a comment as PR approved from my side. Probably it may take a week or a bit more because we're actively working on some important stuff on this plugin.

@daniel-beck
Copy link
Member

Not sure if I may consider his thumbs-up in a comment as PR approved from my side

I have no objection to this PR from a security POV.

Besides that, I'm just not a maintainer of this plugin. Superficially, the change seems useful, and even looks like it improves feature parity between different config file types, but I don't know this plugin well enough to say whether it fits the overall design or direction. I have not reviewed the code other than checking it for security vulnerabilities.

@tykeal
Copy link
Contributor Author

tykeal commented Apr 21, 2021

@olamy thanks for the approval. Any reason to keep this from getting merged?

Would have been nice to see it go out with 3.7.1 which just released :(

@MRamonLeon
Copy link
Contributor

@olamy thanks for the approval. Any reason to keep this from getting merged?

Would have been nice to see it go out with 3.7.1 which just released :(

Indeed

@MRamonLeon MRamonLeon merged commit b09f3d4 into jenkinsci:master Apr 21, 2021
@MRamonLeon
Copy link
Contributor

Waiting for tests to pass on #118 before releasing

@tykeal
Copy link
Contributor Author

tykeal commented Apr 21, 2021

@MRamonLeon thanks! My team (and customers) are really looking forward to having this feature :)

@MRamonLeon
Copy link
Contributor

I still need to address a minor issue before merging. I hope to have it by Friday.

@MRamonLeon
Copy link
Contributor

@tykeal would you mind if I bump Jenkins core to 2.266?

@tykeal
Copy link
Contributor Author

tykeal commented Apr 22, 2021

@MRamonLeon I have no problem with that. I had considered bumping stuff when I wrote the change, but realized that I could get everything working on the versions that were in the pom.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants