{"id":3408,"date":"2018-09-26T08:17:11","date_gmt":"2018-09-26T13:17:11","guid":{"rendered":"http:\/\/lisa.rushworth.us\/?p=3408"},"modified":"2018-09-26T08:45:06","modified_gmt":"2018-09-26T13:45:06","slug":"3408","status":"publish","type":"post","link":"https:\/\/www.rushworth.us\/lisa\/?p=3408","title":{"rendered":"Building A Jenkins Sandbox"},"content":{"rendered":"<p>You can use a pre-built docker container (the \u201clong term support\u201d iteration is published as jenkins\/jenkins:lts) or perform a local installation from <a class=\"jive-link-external-small\" href=\"https:\/\/jenkins.io\/download\/\" target=\"_blank\" rel=\"nofollow noopener\">https:\/\/jenkins.io\/download\/<\/a>, add a package repo to your package manager config (<a class=\"jive-link-external-small\" href=\"http:\/\/pkg.jenkins-ci.org\/redhat-stable\/jenkins.repo\" target=\"_blank\" rel=\"nofollow noopener\">http:\/\/pkg.jenkins-ci.org\/redhat-stable\/jenkins.repo<\/a> for RedHat-based systems), or build it from the <a href=\"https:\/\/github.com\/jenkinsci\/jenkins\" target=\"_blank\" rel=\"noopener\">source repo<\/a>. In this sandbox example, I will be using a Docker container.<\/p>\n<p>Map the \/var\/Jenkins_home value to something. This allows you to store user-specific data on your local drive, <em>not<\/em> within the Docker image. In my case, c: is shared in Docker and I\u2019m using c:\\docker\\jenkins\\jenkins_home to store the data.<\/p>\n<p><a href=\"http:\/\/lisa.rushworth.us\/?attachment_id=3409\" rel=\"attachment wp-att-3409\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3409\" src=\"http:\/\/lisa.rushworth.us\/wp-content\/uploads\/2018\/09\/Jenkins01.png\" alt=\"\" width=\"624\" height=\"429\" srcset=\"https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins01.png 624w, https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins01-300x206.png 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/a><\/p>\n<p>I have a java cacerts file mounted to the container as well \u2013 <em>my<\/em> CA chain has been imported into this file, and the default password, changeit, is used. This will allow Java to trust internally signed certificates. The keystore password appears as part of the process (i.e. anyone who can run commands like \u201cps aux\u201d or \u201cps -efww\u201d will see this value, so while security best practices dictate the default password should be changed \u2026 don\u2019t change it to something like your root password!).<\/p>\n<p><a href=\"http:\/\/lisa.rushworth.us\/?attachment_id=3410\" rel=\"attachment wp-att-3410\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3410\" src=\"http:\/\/lisa.rushworth.us\/wp-content\/uploads\/2018\/09\/Jenkins02.png\" alt=\"\" width=\"624\" height=\"498\" srcset=\"https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins02.png 624w, https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins02-300x239.png 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/a><\/p>\n<p>We can now start the Docker container:<\/p>\n<pre>docker run -p 8080:8080 -p 50000:50000 -v \/c\/docker\/jenkins\/jenkins_home:\/var\/jenkins_home -v \/c\/docker\/jenkins\/cacerts:\/usr\/lib\/jvm\/java-8-openjdk-amd64\/jre\/lib\/security\/cacerts jenkins\/jenkins:lts<\/pre>\n<p>Once the container is running, you can visit the management web site (<a class=\"jive-link-external-small\" href=\"http:\/\/localhost:8080\" target=\"_blank\" rel=\"nofollow noopener\">http:\/\/localhost:8080<\/a>) and install the modules you want \u2013 or just take the defaults (you\u2019ll end up with \u2018stuff\u2019 you don\u2019t need \u2026 I don\u2019t use subversion, for instance, and don\u2019t really need a plugin for it). For a sandbox, I accept the defaults and then use Jenkins =&gt; Manage Jenkins =&gt; Manage Plug-ins to remove obviously unnecessary ones. And add any that may be needed (e.g. if you are using Visual Studio solution files, add in the MSBuild plugin).<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Configuring Authentication (LDAP)<\/strong><\/p>\n<p>First install the appropriate plug-in \u2013 referrals cause authentication problems when using AD as the LDAP authentication source, if you are using AD for authentication \u2026 use the Active Directory plugin).<\/p>\n<p>Manage Jenkins =&gt; Configure Global Security. Under access control, select the radio button for \u201cLDAP\u201d or \u201cActive Directory\u201d. Configuration is implementation specific.<\/p>\n<p><strong><em>AD:<\/em><\/strong><\/p>\n<p>Click the button to expand the advanced configuration. You should not need to specify a domain controller if service records for the domain are present in DNS. The \u201cSite\u201d should be \u201cUserAuth\u201d. For the Bind DN, you <em>can<\/em> use your userid (user@domain.ccTLD or domain\\uid format) with your password. Or you can create a dedicated service account \u2013 for a \u201creal world\u201d implementation, you would want a dedicated service account (using *your* account means you\u2019ll need to update your Jenkins config whenever you change your password \u2026 and when you forget this update, auth fails).<\/p>\n<p><a href=\"http:\/\/lisa.rushworth.us\/?attachment_id=3411\" rel=\"attachment wp-att-3411\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3411\" src=\"http:\/\/lisa.rushworth.us\/wp-content\/uploads\/2018\/09\/Jenkins03.png\" alt=\"\" width=\"624\" height=\"364\" srcset=\"https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins03.png 624w, https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins03-300x175.png 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/a><\/p>\n<p><em>A note about the group membership lookup strategy:<\/em><\/p>\n<p>For some reason, Jenkins assumes recursive group memberships will be used (e.g. there is a \u201cApp XYZ DevOps Team\u201d that is placed into the \u201cJenkins Users\u201d group, and \u201cJenkins Users\u201d is assigned authorizations within the system). Bit of a shame that \u201cnone\u201d isn\u2019t an option for cases where there <em>isn\u2019t<\/em> hierarchical group membership being built out.<\/p>\n<p>There are three lookup strategies available: recursive group queries, LDAP_MATCHING_RULE_IN_CHAIN, and Toke-Groups user attribute. There have been bugs in the &#8220;Automatic&#8221; strategy that caused timeout failures. Additionally, the group list returned by the three strategies is <em>not<\/em> identical &#8230; so it is <em>possible<\/em> to have inconsistent authorization results as different strategies are used. To ensure consistent behaviour, I select a specific strategy.<\/p>\n<p><a href=\"http:\/\/lisa.rushworth.us\/?attachment_id=3415\" rel=\"attachment wp-att-3415\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-3415\" src=\"http:\/\/lisa.rushworth.us\/wp-content\/uploads\/2018\/09\/Jenkins07-1024x287.png\" alt=\"\" width=\"960\" height=\"269\" srcset=\"https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins07-1024x287.png 1024w, https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins07-300x84.png 300w, https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins07-768x215.png 768w, https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins07.png 1213w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/p>\n<p><em><strong>Token-Groups: <\/strong><\/em>If you are not using Distribution groups within Jenkins to assign authorization (and you probably shouldn\u2019t since it\u2019s a distribution group, not a security group), you can select the Token-groups user attribute to handle recursive group membership. Token-groups won\u2019t work if you are using distribution groups within Jenkins, though, as <em>only<\/em> security groups show up in the token-groups attribute.<\/p>\n<p><em><strong>LDAP_MATCHING_RULE_IN_CHAIN:<\/strong><\/em> OID 1.2.840.113556.1.4.1941, LDAP_MATCHING_GROUP_IN_CHAIN is an extended matching operator (something Microsoft added back in Windows 2003 R2) that can be used in LDAP filters:<\/p>\n<pre>(member:1.2.840.113556.1.4.1941:=cn=Bob,ou=ResourceUsers,dc=domain,dc=ccTLD)<\/pre>\n<p>This operator has known issues with high fan-outs and <em>can<\/em> cause hangs while data is retrieved. It is, however, a more efficient way of handling recursive group memberships. If your Jenkins groups contain only users, you will not encounter the known issue. If you <em>are<\/em> using nested groups, my personal recommendation would be to test each option and time logon activities \u2026 but if you do not wish to perform a test, this is a good starting option.<\/p>\n<p><em><strong>Recursive Group Queries: <\/strong><\/em>Jenkins issues a new LDAP query for each group \u2013 a lot of queries, but straight-forward queries. This is my last choice \u2013 i.e. if everything else hangs and causes poor user experience, try this selection.<\/p>\n<p>For Active Directory domains that experience slow authentication through the AD plug-in regardless of the selected recursion scheme, I\u2019ve set up the LDAP plug-in (it does not handle recursive group memberships) <em>but<\/em> it\u2019s not a straight-forward configuration.<\/p>\n<p><strong><em>LDAP:<\/em><\/strong><\/p>\n<p>Click the button to expand the advanced server configuration. Enter the LDAP directory connection details. I usually start with clear text LDAP. Once the clear text connection tests successfully, the certificate trust can be established.<\/p>\n<p>You <em>can<\/em> add a group search filter, but this is not required. If you request your group names start with a specific string, e.g. my ITSS CSG organization\u2019s Jenkins server might use groups that start with ITSS-CSG-Jenkins, you can add a cn filter here to restrict the number of groups your implementation looks through to determine authorization. My filter, for example, is cn=ITSS-CSG-Jenkins*<\/p>\n<p>Once everything is working with clear text, load the Root and Web CA public keys into your Java instance\u2019s cacerts file (if you have more than once instance of Java and don\u2019t know which one is being used \u2026 either figure out which one is actually being used or repeat the keytool commands for <em>each<\/em> cacerts file on your machine).<\/p>\n<p>In the Docker container, the file is \/usr\/lib\/jvm\/java-8-openjdk-amd64\/jre\/lib\/security\/cacerts and I\u2019ve mapped in from a locally maintained cacerts file that already contains our public keys for our CA chain.<\/p>\n<p><a href=\"http:\/\/lisa.rushworth.us\/?attachment_id=3412\" rel=\"attachment wp-att-3412\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3412\" src=\"http:\/\/lisa.rushworth.us\/wp-content\/uploads\/2018\/09\/Jenkins04.png\" alt=\"\" width=\"499\" height=\"327\" srcset=\"https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins04.png 499w, https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins04-300x197.png 300w\" sizes=\"auto, (max-width: 499px) 100vw, 499px\" \/><\/a><\/p>\n<p>Before saving your changes, make sure you TEST the connection.<\/p>\n<p>Under Authorization, you can add any of your AD\/LDAP groups and assign them rights (make sure your local back door account has full rights too!).<\/p>\n<p>Finally, we want to set up an SSL web site. Request a certificate for your server\u2019s hostname (make sure to include a SAN if you don\u2019t want Chrome to call your cert invalid). Shell into the Docker instance, cd into $JENKINS_HOME, and scp the certificate pfx file.<\/p>\n<p>Use the keytool command to create a JKS file from this PFX file \u2013 make sure the certificate (PFX) and keystore (JKS) passwords are the same.<\/p>\n<p><a href=\"http:\/\/lisa.rushworth.us\/?attachment_id=3413\" rel=\"attachment wp-att-3413\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3413\" src=\"http:\/\/lisa.rushworth.us\/wp-content\/uploads\/2018\/09\/Jenkins05.png\" alt=\"\" width=\"624\" height=\"362\" srcset=\"https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins05.png 624w, https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins05-300x174.png 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/a><\/p>\n<p>Now <em>remove<\/em> the container we created earlier. Don\u2019t delete the local files, just \u201cdocker rm &lt;containerid&gt;\u201d and create It again<\/p>\n<p><i>docker run &#8211;name jenkins -p 8443:8443 -p 50000:50000 -v \/c\/docker\/jenkins\/jenkins_home:\/var\/jenkins_home -v \/c\/docker\/jenkins\/cacerts:\/usr\/lib\/jvm\/java-8-openjdk-amd64\/jre\/lib\/security\/cacerts jenkins\/jenkins:lts &#8211;httpPort=-1 &#8211;httpsPort=8443 &#8211;httpsKeyStore=\/var\/jenkins_home\/jenkins.cert.file.jks &#8211;httpsKeyStorePassword=keystorepassword<\/i><\/p>\n<p>Voila, you can access your server using an HTTPS URL. If you review the Jenkins documentation, they prefer leaving the Jenkins web server on http and using something like a reverse proxy to perform SSL offloading. This is reasonable in a production environment, but for a sandbox \u2026 there\u2019s no need to bring up a sandbox Apache server just to configure a reverse proxy. Since we\u2019re connecting our instance to the real user passwords, sending passwords around in clear text isn\u2019t a good idea either. If <em>only<\/em> you will be accessing your sandbox (i.e. <a class=\"jive-link-external-small\" href=\"https:\/\/windstream.jiveon.com\/external-link.jspa?url=http%3A%2F%2Flocalhost\" target=\"_blank\" rel=\"nofollow noopener\">http:\/\/localhost<\/a>) then there\u2019s no <em>need<\/em> to perform this additional step. The server traffic to the LDAP \/ AD directory for authentication <em>is<\/em> encrypted. This encryption is <em>just<\/em> for the client communication with the web server.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Using Jenkins \u2013 System Admin Stuff<\/strong><\/p>\n<p>There are several of \u201chidden\u201d URLs that can be used to control the Jenkins service (LMGTFY, basically). When testing and playing with config parameters, restarting the service was a frequent operation, so I\u2019ve included two service restart URLs here:<\/p>\n<p><a class=\"jive-link-external-small\" href=\"https:\/\/windstream.jiveon.com\/external-link.jspa?url=https%3A%2F%2Fjenkins.domain.ccTLD%3A8443%2FsafeRestart\" target=\"_blank\" rel=\"nofollow noopener\">\u00a0\u00a0\u00a0https:\/\/jenkins.domain.ccTLD:8443\/safeRestart<\/a> ==&gt; enter quiet mode, wait for running builds to complete, then restart<\/p>\n<p><a class=\"jive-link-external-small\" href=\"https:\/\/windstream.jiveon.com\/external-link.jspa?url=https%3A%2F%2Fjenkins.domain.ccTLD%3A8443%2Frestart\" target=\"_blank\" rel=\"nofollow noopener\">\u00a0\u00a0\u00a0https:\/\/jenkins.domain.ccTLD:8443\/restart<\/a> ==&gt; Restart not so cleanly<\/p>\n<p>Multiple discussions about creating a more fault tolerant authentication scheme within Jenkins exist on their &#8216;Issues&#8217; site. Currently, you cannot use local accounts if the directory service is unavailable. Not a big deal if you\u2019re on the company network and using one of our highly available directory solutions. Bit of a shocker, though, if your sandbox environment is on your laptop and you try to play with the instance when <em>not<\/em> on the company network. In production implementations, this would be a DR consideration (dependency on the directory being recovered). In a cloud-hosted implementation, this creates a dependency on network connectivity into the company.<\/p>\n<p>As an emergency solution, you <em>can<\/em> disable security on your Jenkins installation. I\u2019d also get some sort of firewall rule (OS-based or hardware firewall) to restrict console access to a trusted terminal server or workstation. To disable security, stop Jenkins. Edit the config.xml file in $JENKINS_HOME, and ifnd the &lt;useSecurity&gt; section. Change \u2018true\u2019 to \u2018false\u2019 and start Jenkins. You\u2019ll be able to access the console without credentials.<\/p>\n<p><a href=\"http:\/\/lisa.rushworth.us\/?attachment_id=3414\" rel=\"attachment wp-att-3414\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-3414\" src=\"http:\/\/lisa.rushworth.us\/wp-content\/uploads\/2018\/09\/Jenkins06.png\" alt=\"\" width=\"624\" height=\"150\" srcset=\"https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins06.png 624w, https:\/\/www.rushworth.us\/lisa\/wp-content\/uploads\/2018\/09\/Jenkins06-300x72.png 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/a><\/p>\n<p><strong>Updating Jenkins Image<\/strong><\/p>\n<p>General practice for updating an application is <em>not<\/em> to update a container. Instead, download an updated image and recreate the container with the new image. I store the container initialization command along with the folder to which image directories are mapped. My file system has \/path\/to\/docker\/storage\/AppName that contains a text file with the initialization command and folder(s) that are mapped into the container. This avoids having to <em>find<\/em> the proper initialization parameters when I upgrade the container.<\/p>\n<p>To update the container, pull a new image, stop the container, remove the container, and create it again. That is:<\/p>\n<p>docker stop jenkins<br \/>\ndocker pull jenkins\/jenkins:lts<br \/>\ndocker rm jenkins<br \/>\n&lt;whatever you used to create the container&gt;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You can use a pre-built docker container (the \u201clong term support\u201d iteration is published as jenkins\/jenkins:lts) or perform a local installation from https:\/\/jenkins.io\/download\/, add a package repo to your package manager config (http:\/\/pkg.jenkins-ci.org\/redhat-stable\/jenkins.repo for RedHat-based systems), or build it from the source repo. In this sandbox example, I will be using a Docker container. Map &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[623,30,29],"tags":[660,629,620,617,616],"class_list":["post-3408","post","type-post","status-publish","format-standard","hentry","category-containerized-development-and-deployment","category-system-administration","category-technology","tag-ci-cd","tag-containerized-development","tag-continuous-delivery","tag-continuous-integration","tag-jenkins"],"_links":{"self":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/3408","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3408"}],"version-history":[{"count":5,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/3408\/revisions"}],"predecessor-version":[{"id":3420,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/3408\/revisions\/3420"}],"wp:attachment":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3408"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3408"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3408"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}