Configuration-as-code-plugin: Folder credentials and its chicken-and-egg problem

Created on 21 Mar 2019  路  12Comments  路  Source: jenkinsci/configuration-as-code-plugin

Hi CasC team, thanks for making this wonderful plugin! I am evaluating it to use it for my team.

I meet one blocking point:
We want to use folder to group credentials (so we can separate CI and CD for security purpose), but:

  1. I don't know how to configure credentials for folder
  2. I suspect that there is an chicken-and-egg problem that is not resolvable

Detail for point 1:

  • I have tried to export CasC, but it contains no folder credentials.
  • I have tried to look up the JSON schema, found no relating property

Detail for point 2:

  • I use job-dsl to configure all jobs and folders. AFAIK, DSL's depends on credentials (for git checkout) and folder credentials depends on DSL (to spin up the folder).

So this looks like a chicken-and-egg problem.

So my questions are:

  • Has anyone in this community done this kind of setup before? If yes, would you please share a bit of examples?
  • Is this doable in current version?

Context:

  • Jenkins version: 2.164.1
  • Plugin version: 1.7
  • OS: Linux (official Jenkins image)

Most helpful comment

@twz123: Here is my example of a Job DSL that creates such a folder. CasC only creates a seed job in my case which checksout the Job DSL here.

folder("test") {
    description 'The folder contains all jobs for regular tests'
    properties {
        folderCredentialsProperty {
            domainCredentials {
                domainCredentials {
                    domain {
                        name("test")
                        description("Credentials necessary for our tests")
                    }
                    credentials {
                        usernamePasswordCredentialsImpl {
                            scope("GLOBAL")
                            id("test_user_id")
                            description("User for deployments on test environment")
                            username("test_user_dev")
                            password("password")
                        }
                    }
                }
            }
        }
    }
}

A bit strange why you need the "domainCredentials" encapsulated twice but this is the only way it is working for me.
I figured it out this way by installing the plugins on my jenkins instance and then opening the documentation of the dynamic DSL. See https://github.com/jenkinsci/job-dsl-plugin/wiki/Dynamic-DSL how you can view it in your jenkins.

All 12 comments

Check gitter we had a discussion about how to go about job-dsl and folder credentials not too long ago (within the last two days)

https://jenkinsci.github.io/job-dsl-plugin/

This is really more of a job dsl issue than it is JCasC, yes JCasC can provide Job DSL with secret context when running your seed job but besides that folder creation is all Job DSL

Not in the context of folder credentials. Folders are a job/project inside Jenkins that can hold configuration and credentials plugin can add credentials to folders; hence it is a Job DSL issue.

JCasC is already providing Job DSL with credentials context when JCasC configures Job DSL. So any environment variables, docker secrets, vault secrets are accessible to Job DSL

right, now I get it.
So just to make sure that I have the right understanding:
To use credentials in Job DSL, we can either:

  • use Job DSL to query credentials provided by CasC (checkoutCredentialsId('bluh-bluh'))
  • provision folder credential by Job DSL directly (folderCredentialsProperty under folder)

And in order to make sure some credentials only accessible within the folder: we can only use the second option.

Is my understanding correct?

Yes on both accounts :smile:

We use Vault instead, yes Jenkins can see everything in Vault under /secret/jenkins.
Though only specific users can see certain secret paths /secret/jenkins/oursecretproject/(staging/testing/production) and only fewer can edit those.
We then expect users in their pipeline to request these secrets when needed for deploying/producing and they could potentially request secrets they do not own.
But we have plans to modify secrets so they are encrypted and only Jenkins has the key to unencrypt them.

That way we avoid the Jenkins credential store as much as possible.

This a more an issue with the core not providing JCasC compatible databinding for jobs,
Currently the workaround is to delegate to job-dsl, can't do much more than that for now though...

@casz thanks for the hint 馃憤 . I think Vault is a good candidate for a slightly more complex environment. But what we are looking for is a fully automated pipeline for small team, with Pull Request (Branch) being our only safe guard.

Ideal setup in Jenkins land:

ci-pipeline-job.yml -> access to non-sensitive variable & triggered by all branches
cd-folder/
    cd-pipeline-job.yml -> access to sensitive secrets & only triggered by limited branches (master)

In this case, folder credential is the only solution in the land of Jenkins. (Or in Gitlab CI using protected variable)


@timja 馃憤 馃憤 thanks, now I get the full picture. I wish Jenkins can be battery-included in the future.

Hi folks,

I'm currently trying to accomplish the same thing. Do you have a more complete example of how to put credentials into folders using CasC and Job DSL? Seems to be a pretty common thing to do, but I'm kinda stuck. :-/

@twz123: Here is my example of a Job DSL that creates such a folder. CasC only creates a seed job in my case which checksout the Job DSL here.

folder("test") {
    description 'The folder contains all jobs for regular tests'
    properties {
        folderCredentialsProperty {
            domainCredentials {
                domainCredentials {
                    domain {
                        name("test")
                        description("Credentials necessary for our tests")
                    }
                    credentials {
                        usernamePasswordCredentialsImpl {
                            scope("GLOBAL")
                            id("test_user_id")
                            description("User for deployments on test environment")
                            username("test_user_dev")
                            password("password")
                        }
                    }
                }
            }
        }
    }
}

A bit strange why you need the "domainCredentials" encapsulated twice but this is the only way it is working for me.
I figured it out this way by installing the plugins on my jenkins instance and then opening the documentation of the dynamic DSL. See https://github.com/jenkinsci/job-dsl-plugin/wiki/Dynamic-DSL how you can view it in your jenkins.

Following the above comment from @zhming0 , does anyone have example job-dsl code "to query credentials provided by CasC"?

Many thanks.

@holmesb: In our setup we use job-dsl only create a job which points to a Jenkinsfile
Job-DSL:

pipelineJob("myJob") {
    description("Job description")
    definition {
        cpsScm {
            lightweight(true)
            scriptPath("Jenkinsfile")
            scm {
                git {
                    remote {
                        url("https://github.com/myaccount/myrepo")
                        credentials("my_github_credential")
                    }
                    branch("master")
                }
            }
        }
    }
}

An example Jenkinsfile to reference a password looks like:

pipeline {
    agent {
        docker {
            image 'ubuntu:18.04'
            reuseNode true
        }
    }
    stages {
        stage('Run Tests') {
            steps {
                withCredentials([usernamePassword(credentialsId: test_user_id, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
                     sh("./build.py $USERNAME $PASSWORD")
                }
            }
        }
    }
}

Only make sure to use the credentialsID you defined in the Jenkins credential store (via JCasC or manually).

Sorry if my comment wasn't clear @linkeal , we're trying to create a folder credential using job-dsl (by querying credentials provided by CasC - as suggested by @zhming0), not attach a credential to a job.

Our credentials are currently created by CasC and exist globally (not at folder level). The reason we are using both CasC and JobDSL is CasC mounts our kubernetes secret. This means in our code we can create a credential referring to a secret using ${OUR_SECRET} notation. But CasC offers no way to create folder credentials (@casz says this is a bad idea), so we must use job-dsl for this.

Was this page helpful?
0 / 5 - 0 ratings