DevOps Digest 301: Fixing the Ugly Hack
In Issue 205, our Jenkins project built our sample project, the first major step on our DevOps journey. But plenty more remains to be done as we enter Chapter 3 and take a closer look at continuous integration to start reaping more significant benefits from our work.
It’s not worth getting into the many reasons we ended our last issue with an ugly hack, but it does allow us to explore a truth most developers are all too familiar with: you sometimes have to cut corners to meet deadlines. Especially true of DevOps, due to the plethora of conceptual models and implementation quirks at play, the challenge is twofold: (1) knowing when to use ugly workarounds to your advantage, and (2) ensuring they get fixed.
So let’s diagnose ours. We embedded a password in the plain text of a Jenkins pipeline script leaving us vulnerable because anyone who can get into Jenkins can look at our password. That’s not very secure as anyone who can get into Jenkins can look at our password.
Our attempts to sync the project workspace were failing with a password error. More important than the actual disease is this crucial point: Jenkins executes its jobs using a different account than the one you use to install it. So, a default Jenkins installation on Windows will configure itself to run as a service. The screenshot from our VM’s server administration utility shows exactly that:
To be more precise, the Jenkins service runs using the “Local System” account, a predefined account for use by the Windows Service Control Manager (SCM). The SCM offers predefined accounts to make it easy to install services, while limiting their permissions for sake of security. Most general users don’t need to know about such things, but Windows DevOps professionals don’t enjoy that luxury.
In a previous article, we saw how to list the environment variables with settings used by Perforce Helix where we had already set our password. We did that so we could use the command-line interface more easily. When we first tried to run our new Jenkins job, however, the Local System account had no such password set, which is why the attempt to sync failed.
Thus, the quick and dirty fix, adding those lines to the Jenkins pipeline script, to manually set our password. And for the record, it got set it for future invocations as well, because doing so made it part of the stored environment. We could remove such lines at any time and future builds would keep working, but only as long as the data stored in the environment remained valid.
We deliberately evinced the error and used that ugly hack to fix it because it illustrated a point. We’ve seen this kind of thing confuse many clear-eyed Jenkins administrators. It’s just too easy to be lulled into a false sense of security when things work from your command line but not elsewhere. Always remember that if it works under your account but fails under Jenkins, the odds are good you’ve got an environmental discrepancy to fix.
We’ll first fix it in a very simple, generic way, to illustrate how you can use simple Jenkins user name and password credentials in pipeline script. We can store a simple user name and password in Jenkins for use with any tool, in any job.
First, we need to add a new credential. Jenkins has powerful credentials management. It defines credentials by domains, allows plugins to define new types of credentials, and makes it easy to “load” the resulting values into the environment for use in pipeline script and the various processes it invokes.
From the top-level Jenkins dashboard, click the “Credentials” link, then the “(global)” domain, and then the link to “Add Credentials” on the left. Only provide details like the following to define our new, simple credential.
“Username with password” credentials are easily reused anywhere. We supplied the user ID and password and gave it a name “DevOps” to indicate its purpose. Pick a more useful name so you easily recognize it when editing pipeline script. After creating the credentials, update the script to reflect the following changes highlighted in the illustration below:
The “withCredentials” block of script “loads” the credential we created into the environment variables “USERNAME” and “PASSWORD”. This makes it easy to replace our previous hack with an environment variable reference instead of the password in plain text. There are other ways to do this (i.e., leveraging the Perforce Helix plugin), but we wanted to show you how to accomplish the task more generally for your other DevOps tasks.
In issue 302, we’ll start considering more sophisticated ways of automating the build process in Jenkins and develop a branching strategy. Stay tuned!
You Ask, We Answer
As previously mentioned, this is your roadmap to creating a successful DevOps pipeline. Don’t understand something? Just ask. Need to dive a little deeper? Send an email to [email protected] with your questions. Then, stay tuned for a live Q&A webinar at the end of this series. Get DevOps Digest Sent to your Inbox
You don’t need to remember to check back with us each week. Instead, get the digest delivered directly to your inbox. Subscribe to our 25-week DevOps Digest and we’ll get you where you need to go, one email at a time.
See Perforce Helix in Action!
Join us for a live demo every other Tuesday and see the best of Perforce Helix in 20 minutes. Save your spot!