Conjur Setup

Hey Folks,

Trying to setup a Conjur plugin for jenkins as stated in the following link:

But at the stage Prepare the certificate
Use the openssl client tool to retrieve the certificate from Conjur. The following command retrieves the certificate from an identified Conjur instance and stores the cert on your local machine in a file named conjur.pem . The identified Conjur instance may be a Conjur Follower. (Jenkins administrators do not need access to the Conjur Master.)

openssl s_client -showcerts -connect <CONJUR_DNS_NAME>:443 < /dev/null 2> /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > <file-name>

what should be my CONJUR_DNS_NAME??? Btw, i am using the conjur server that i have installed in my VM using the instructions from https://www.conjur.org/get-started/quick-start/oss-environment/.

For the CONJUR_DNS_NAME, tried to use the hostname of the conjur server container but no luck thus far.

Running out of ideas. Would really appreciate your help. Thanks!

Hey @davidbeckham -

I have a quick start Conjur running in my local environment right now, and was able to retrieve the cert by running:

openssl s_client -showcerts \
  -connect localhost:8443 < /dev/null 2> /dev/null \
  | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' \
  > conjur.pem

You may also note that when you stand up the quick start docker-compose environment, the Conjur certificate is also available at conf/tls/nginx.crt.

Moved this to #conjur. #conjur:conjur-guides is for tutorials/how-to guides.

hi @izgerij, thanks for looking into this. i’m trying to setup a jenkins to fetch a AWS secret key everytime there is a build. however, i notice that it can be done via a plugin as stated in the docs: https://docs.conjur.org/latest/en/Content/Integrations/jenkins-configure.htm?tocpath=Integrations|Jenkins|_____2 or through the tutorials at: https://www.conjur.org/get-started/tutorials/jenkins-security. May I know whats the difference between these 2 links? To achieve my goal, which documentation should I be following?

i’m trying out the tutorial on: https://www.conjur.org/get-started/tutorials/jenkins-security/

with regards to the summon part, do i need to install summon-aws-secrets on the jenkins container in order to retrieve the secrets from conjur? and i would need to incorporate the summon API calls in my Jenkins build file in order to retrieve the secrets?

thanks.

Hey @davidbeckham -

The two guides (in the docs and the tutorial) cover two different approaches for ensuring your Jenkins pipelines have access to secrets in Conjur. Which one you choose depends a bit on how you prefer to work.

Using Summon in Jenkins Pipelines

In many of our own development pipelines, we choose to use Summon to inject secrets from Conjur into our Jenkins pipelines. You can see an example here: https://github.com/cyberark/conjur/blob/75dfb728f2008a50423b27523c217c7325946e55/Jenkinsfile#L95.

We use this approach because we want to be able to run the test suite from our local machines the same way that Jenkins will run it, and using Summon allows us to do that. For example, with Summon we’re able to set up our secrets.yml configuration file with separate environments that retrieves different secrets depending on whether we’re running in our local dev environment vs the CI environment (see this blog for more info). If you want to use Summon in your pipeline too, you’ll need to make sure your Summon executors are set up with a Conjur configuration and that you have Summon and Summon-Conjur installed on your executors. The tutorial walks you through this flow.

When you use Summon, you:

  • Ensure your Jenkins executor is configured to access Conjur and has Summon & Summon-Conjur installed
  • Write your scripts to look for secret values in specific environment variables
  • Write a secrets.yml file that maps the environment variables to the credential path in your secret provider, e.g. to map DB_PASSWORD to /path/to/db/password in Conjur, your secrets.yml would contain:
    DB_PASSWORD: !var /path/to/db/password
    
  • Wrap the invocation of your pipeline scripts that need secrets in the Jenkinsfile with Summon. For example:
    stage('Run tests') {
      steps {
        sh 'summon -f /secrets.yml ./test.sh'
      }
    }
    

Just as a sidenote, Summon AWS Secrets is the Summon secret provider that retrieves secrets from AWS Secrets Manager with Summon - so you wouldn’t use that provider to retrieve secrets from Conjur.

Using the Jenkins-Native Conjur Credentials Plugin in Pipelines

We also have a Jenkins-native plugin that you can install to retrieve secrets from Conjur - the docs page highlights the use of this plugin, which is in the process of being ported to the jenkinsci GitHub org, and you can find it here: https://github.com/jenkinsci/conjur-credentials-plugin. To use the plugin, you:

  • Ensure your Jenkins executor is configured to access Conjur and has the Conjur Credentials Plugin installed
  • Write your scripts to look for secret values in specific environment variables
  • Wrap the invocation of your pipeline scripts that need secrets in the Jenkinsfile in a withCredentials block that invokes the conjurSecretCredential method. For example:
    stage('Run tests') {
      steps {
        withCredentials(
          [
            conjurSecretCredential(credentialsId: 'test-db-password', variable: 'DB_PASSWORD')
          ]
        ) {
           sh './test.sh'
        }
      }
    }
    

I hope this helps, but if you run into more questions as you go please feel free to post here with more questions.

hi @izgerij

thanks for your patience and the comprehensive reply! i am trying out the plugin method you shared on: https://github.com/jenkinsci/conjur-credentials-plugin.

Under Global Configuration, may I know what should I be keying in for the appliance URL field? I have setup my conjur by following the tutorials at: https://www.conjur.org/get-started/quick-start/oss-environment/. And for the SSL certificate field, can i use conjur-quickstart/conf/tls/nginx.crt and how do I configure it such that nginx.crt can be used by the plugin?

thanks!

Can you share more about how you have this deployed? It sounds like you have Conjur running using the quick start docker-compose on a VM (in AWS?). Where is your Jenkins server running? Thanks!

i have my host machine installed with vm workstation. on my vm workstation, i have a centos VM installed with docker. and this where i run my conjur OSS environment.

my jenkins and conjur server are running in the conjur-quickstart_default network spun up in the conjur OSS environment.

With regards to the following notes on the input to the Conjur SSL Certificate field:
Requests to Conjur will fail unless:

  • An SSL certificate is specified in the SSL certificate field. Note : The SSL Certificate can be linked to a certificate already stored in Jenkins (defined as credentials).
  • There is a certificate locally defined in the cacerts of the JVM sending the requests - how can i define this cert?
  • Conjur is not set up to use SSL. - do you have the instructions on setting up the SSL on conjur?

Could you advise what should i be putting into the Conjur SSL Certificate field?

with regards to the appliance URL field:
Entered https://localhost:8443 in the appliance URL field but no luck:
java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:607)
at okhttp3.internal.platform.Platform.connectSocket(Platform.java:129)
at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:245)
Caused: java.net.ConnectException: Failed to connect to localhost/127.0.0.1:8443

if i put the ngnix’s IP: 172.19.0.4, i will get the connection time out error:
java.net.SocketTimeoutException: connect timed out
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:607)

my conjur server is running fine when accessed from my host machine.

I don’t have a Jenkins env handy at the moment to test this out, but I tested with the Conjur CLI Docker image. I ran the following command from the quick start project root directory:

docker run \
  --network conjur-quickstart_default \
  --rm -it \
  -e CONJUR_AUTHN_API_KEY="[my admin API key]" \
  -e CONJUR_AUTHN_LOGIN="admin" \
  -e CONJUR_ACCOUNT="myConjurAccount" \
  -e CONJUR_APPLIANCE_URL="https://proxy" \
  -e CONJUR_SSL_CERTIFICATE="$(cat conf/tls/nginx.crt)" \
  cyberark/conjur-cli:5

I believe this means:

  • You should be able to set the appliance URL to https://proxy in the Jenkins config (again, this works if the Jenkins container is also running on the conjur-quickstart_default network)
  • You should copy the contents of the SSL certificate at conf/tls/nginx.crt in the Conjur SSL Certificate field.

@enunez may be able to advise on how to define the certificate in the cacerts of the JVM. Regarding the 3rd option (“Conjur is not set up to use SSL”), we do not recommend this as it would mean your secrets would be sent in plaintext between your client and the server.

Please let me know if this helps or not. I’ll also look for ways to clear up the documentation so this is easier for others who try this use case, too.

thank you @izgerij, worked like a charm! able to get db/password echo out.

i’m trying to get to my next step, which is to connect to a AWS API using the AWSAccessKeyId & AWSSecretKey stored in conjur. got 2 questions:

  1. when i loaded awsaccesskeyid and awssecretkey into db/awsaccesskeyid and db/awssecretkey respectively. did a conjur list, confirmed they are there:

however, when i edited the jenkins pipeline file and tried the build again, i got the following error:

java.io.IOException: Error fetching secret from Conjur [404 - Not Found
{“error”:{“code”:“not_found”,“message”:“Variable ‘db/awsaccesskeyid’ not found in account ‘myConjurAccount’”,“target”:“variable”,“details”:{“code”:“not_found”,“target”:“id”,“message”:“myConjurAccount:variable:db/awsaccesskeyid”}}}
at org.conjur.jenkins.api.ConjurAPI.getSecret(ConjurAPI.java:226)
at org.conjur.jenkins.conjursecrets.ConjurSecretCredentialsImpl.getSecret(ConjurSecretCredentialsImpl.java:130)
Caused: org.conjur.jenkins.exceptions.InvalidConjurSecretException: Error fetching secret from Conjur [404 - Not Found
{“error”:{“code”:“not_found”,“message”:“Variable ‘db/awsaccesskeyid’ not found in account ‘myConjurAccount’”,“target”:“variable”,“details”:{“code”:“not_found”,“target”:“id”,“message”:“myConjurAccount:variable:db/awsaccesskeyid”}}}
at org.conjur.jenkins.conjursecrets.ConjurSecretCredentialsImpl.getSecret(ConjurSecretCredentialsImpl.java:134)
at org.conjur.jenkins.conjursecrets.ConjurSecretCredentialsBinding.bind(ConjurSecretCredentialsBinding.java:59)
at org.jenkinsci.plugins.credentialsbinding.impl.BindingStep$Execution2.doStart(BindingStep.java:135)
at org.jenkinsci.plugins.workflow.steps.GeneralNonBlockingStepExecution.lambda$run$0(GeneralNonBlockingStepExecution.java:77)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Finished: FAILURE

i’m scratching my head; my conjur list says db/awsaccesskeyid but the build keeps failing. is there any step that i missed out?

  1. do you have any guides on using the awssecretkey and awsaccesskeyid to do a simple API call?

  2. with regards to withCredentials and the symbol conjurSecretCredential, it seems to be able to retrieve only secret. is there anyway to retrieve 2 secrets at the same time since i have awssecretkey and awsaccesskeyid?

thanks!

Hello again :slight_smile:

I am glad to see you are making progress! It may be that the Conjur identity your Jenkins server is using does not have privileges on the secrets it needs. When I need to check this, I always run the following commands in a Conjur CLI container:

conjur resource permitted_roles variable:[variable id] read
conjur resource permitted_roles variable:[variable id] execute

If your policy is configured correctly, you should see the Conjur identity you’ve given to your Jenkins server returned with both commands - that is, the identity must have read and execute privileges on any secret it needs to access.

If your identity does not have the right permissions on those variables, you’ll have to review and update your policy. We usually recommend that when you define variables in a branch, you also create a secrets-users group at the same time that has read and execute privileges on the secrets, so that you can add any identities that will need access to the secrets on that branch to the group in order to grant access. So your policy branch might look like:

- !policy
  id: users-app
  body:
    - &variables
      - !variable db-username
      - !variable db-password

    - !group secrets-users

    # secrets-users can read and execute
    - !permit
      resource: *variables
      privileges: [ read, execute ]
      role: !group secrets-users

and you will have an entitlement that grants your jenkins-host identity membership in the users-app/secrets-users group:

- !grant
  role: !group users-app/secrets-users
  member: !host jenkins-host

Regarding using multiple credentials in your pipeline, the syntax in the example I shared above would change as follows:

stage('Run tests') {
  steps {
    withCredentials([
        conjurSecretCredential(credentialsId: 'test-db-username', variable: 'DB_USERNAME'),
        conjurSecretCredential(credentialsId: 'test-db-password', variable: 'DB_PASSWORD')
	])
    {
       sh './test.sh'
    }
  }
}

You would of course need to first define credentials of ConjurSecret type in your Jenkins configuration for test-db-password and test-db-username.

hey @izgerij

thanks so much for your kind guidance! it’s working fine now! :smile:

please bear with me as i have one last part to clarify, i am following this blog: https://www.conjur.org/blog/ci-cd-servers-know-all-your-plumbing-secrets/ and would like to use the AWSSecretKey and AWSAccessKeyId to do a API to my AWS account to download a file from my S3 bucket.

But after doing some reading, i realised most of the interactions with AWS requires a AWS plugin. For example: AWS Step: https://plugins.jenkins.io/pipeline-aws/#s3download. To connect to AWS, it requires us to key in the AWSSecretKey and AWSAccessKeyId via the AWSCredential below:

therefore, i am wondering, how can i make use of the stored AWSSecretKey and AWSAccessKeyId in conjur to do a API call to AWS to upload a file to my S3 bucket without using the hardcoded AWSCredential, but rather like to use the AWSSecretKey and AWSAccessKeyId checked out from conjur? :slightly_smiling_face:

Hi David, I think the withAWS step could help:

withAWS(credentials:'IDofSystemCredentials') {
// do something eg s3 upload
}

withAWS allows you to specify an existing username/password credential provided by any credentials provider including the conjur credentials jenkins plugin. My understanding is that the the conjur credentials plugin creates username/password credentials by storing the username in Jenkins and pulling the password from a conjur variable specified by you when the credential is created. In this case the username is the AKID and the password is the SAK.

You could pull both AKID & SAK from conjur if you used summon and aws cli/sdk rather than using aws pipeline steps.