{"id":42552,"date":"2023-12-04T11:56:00","date_gmt":"2023-12-04T16:56:00","guid":{"rendered":"https:\/\/netfoundry.io\/?p=42552"},"modified":"2024-12-05T10:32:43","modified_gmt":"2024-12-05T15:32:43","slug":"this-is-the-way-invisible-jenkins","status":"publish","type":"post","link":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/","title":{"rendered":"This is the Way: Invisible Jenkins"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"42552\" class=\"elementor elementor-42552\" data-elementor-post-type=\"post\">\n\t\t\t\t<div class=\"elementor-element elementor-element-29f327ee e-flex e-con-boxed e-con e-parent\" data-id=\"29f327ee\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-43f6bdb3 elementor-widget elementor-widget-text-editor\" data-id=\"43f6bdb3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Why Jenkins?<\/h2>\n<p><strong>Jenkins<\/strong> is a widely adopted automation tool for building software with a broad array of plugins and\u00a0integrations\u00a0with key DevOps tools like Docker and Kubernetes. Here at NetFoundry, we started out using Jenkins to automate our builds, run tests, and promote releases. Eventually, we expanded to use CI as a service too. There were some builds that needed to happen in GitHub or BitBucket. Some jobs were not as readily migrated to a new CI system, and why bother? It made more sense to keep running those jobs in Jenkins, and so a new problem was introduced: how do we trigger Jenkins jobs from an external system like GitHub?<\/p>\n<p>In our case, the Jenkins jobs needed certain parameters not available in GitHub\u2019s built-in webhooks. We created a custom Jenkins-style webhook generator that we could use in GitHub, but the core problem remained: anyone could still \u201csee\u201d our Jenkins server on the internet. This exposure was intentional, but it could have become a serious problem if our server had been the target of a network-launched attack. One layer of security didn\u2019t seem like enough protection for something so valuable. We knew that we wanted to use our home-grown networking framework OpenZiti to solve this kind of problem, so we used the OpenZiti SDK for Node.JS to create a GitHub Action to send a webhook securely via OpenZiti instead of over the internet.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-baa427a elementor-widget elementor-widget-image\" data-id=\"baa427a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"782\" height=\"389\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/jenkins.png\" class=\"attachment-large size-large wp-image-42555\" alt=\"NetFoundry | Webhook Visible Jenkins\" loading=\"lazy\" srcset=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/jenkins.png 782w, https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/jenkins-300x149.png 300w, https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/jenkins-768x382.png 768w\" sizes=\"auto, (max-width: 782px) 100vw, 782px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2d73cda0 e-grid e-con-full e-con e-child\" data-id=\"2d73cda0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-10d060c5 elementor-widget elementor-widget-image\" data-id=\"10d060c5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-64c15dee elementor-widget__width-inherit elementor-widget-divider--view-line elementor-widget elementor-widget-divider\" data-id=\"64c15dee\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7df69ae7 elementor-widget elementor-widget-image\" data-id=\"7df69ae7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-953eedf e-flex e-con-boxed e-con e-parent\" data-id=\"953eedf\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-c91f20a elementor-widget elementor-widget-text-editor\" data-id=\"c91f20a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>Checkmate: Jenkins is a High-Value Target<\/h3>\n<p>I would be surprised if a resourceful attacker failed to deliver a damaging blow after finding a foothold on a Jenkins server. If this were chess, then Jenkins is the queen. One of the reasons the target value is so high is that Jenkins tends to store powerful credentials needed to deploy cloud infrastructure and applications automatically. A compromised Jenkins server is also an opportunity to introduce malicious code into a build. If successful, that infected build could be distributed through the trusted supply chain.<\/p>\n<p>The tools for attacking Jenkins have become\u00a0<a href=\"https:\/\/web.archive.org\/web\/20240420171325\/https:\/\/github.com\/Accenture\/jenkins-attack-framework\" target=\"_blank\" rel=\"noopener\">more sophisticated and accessible<\/a>,\u00a0making Jenkins a softer target. Popularity is a double-edged sword. The rule of thumb for defensive security is to balance the scales with target value on one side and defensive measures on the other. As our Head of Security Mike Gorman likes to say, \u201cYou don\u2019t need a $100 lock for a $10 bike.\u201d We knew that losing control of Jenkins would be a severe incident, so we got to work.<\/p>\n<p><!-- \/wp:paragraph --><!-- wp:heading {\"level\":3} --><!-- \/wp:paragraph --><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-8e41f65 e-grid e-con-full e-con e-child\" data-id=\"8e41f65\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e6fae85 elementor-widget elementor-widget-image\" data-id=\"e6fae85\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fd36bf2 elementor-widget__width-inherit elementor-widget-divider--view-line elementor-widget elementor-widget-divider\" data-id=\"fd36bf2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9196ed1 elementor-widget elementor-widget-image\" data-id=\"9196ed1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-dc58e9b e-flex e-con-boxed e-con e-parent\" data-id=\"dc58e9b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-54926c2 elementor-widget elementor-widget-text-editor\" data-id=\"54926c2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>A Quick Inventory of the Problems and Alternatives<\/h3>\n<p>We knew we\u2019d need to solve several problems before taking the Jenkins server off the public internet.\u00a0<\/p>\n<p><em><strong>How will users access the UI?<\/strong><\/em><\/p>\n<p><em><strong>How will administrators access SSH?<\/strong><\/em><\/p>\n<p><em><strong>How will we receive webhooks from external CI systems?<\/strong><\/em><\/p>\n<p>In times past, I\u2019ve used tools like SSH tunnels, VPNs, virtual desktops, and webhook relays to solve these kinds of problems. It\u2019s simpler to make the server intentionally public and trust that the login method will prevent unauthorized use, but that\u2019s just one layer of security. I\u2019m guessing this partially explains why Mikail Tun\u00e7 found 25K Jenkins servers directly exposed to the internet during\u00a0<a href=\"https:\/\/web.archive.org\/web\/20240420171325\/https:\/\/emtunc.org\/blog\/01\/2018\/research-misconfigured-jenkins-servers\/\" target=\"_blank\" rel=\"noopener\">his 2018 survey of the internet via Shodan<\/a>.<\/p>\n<p>Those traditional solutions like VPNs and relays incur hidden, ongoing costs associated with the complexity and rigidity of a configuration that is not tightly coupled to the application\u2019s needs. This slows down work that relies on those solutions because things often break when changes are made. The server is separate from the security, so they always have to be configured separately, which is inherently fragile. Despite all the care taken to make a server private from the internet, the core problem remains. While the application server is still listening on any network port, it is vulnerable to attack.<\/p>\n<p>I\u2019ve personally spent my fair share of time troubleshooting and managing bolt-on security measures like those VPNs. I came to regard them as a necessary evil. Whenever a problem arose with an IPSec tunnel, it was always my top priority because of the high costs associated with a loss of availability. It would have been so much better if those solutions didn\u2019t catch on fire in the first place, and ideal if they were not even necessary.<\/p>\n<p>In the next section, I\u2019ll explain how these problems are solved by combining a strong identity with a service policy. This allows us to keep servers invisible on the network unless a caller has permission to connect.<\/p>\n<p><!-- \/wp:paragraph --><!-- wp:heading {\"level\":3} --><!-- \/wp:paragraph --><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9135641 e-grid e-con-full e-con e-child\" data-id=\"9135641\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3b9354b elementor-widget elementor-widget-image\" data-id=\"3b9354b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bd18e82 elementor-widget__width-inherit elementor-widget-divider--view-line elementor-widget elementor-widget-divider\" data-id=\"bd18e82\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c3377a8 elementor-widget elementor-widget-image\" data-id=\"c3377a8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-b0825e6 e-flex e-con-boxed e-con e-parent\" data-id=\"b0825e6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-291c207 elementor-widget elementor-widget-text-editor\" data-id=\"291c207\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>Why use an Overlay? Identity vs Network Perimeter<\/h3>\n<p>OpenZiti is an example of a networking overlay that uses identities instead of a network perimeter as a basis for access control. So what is an identity-based control vs network perimeter control? Metaphorically, basing security on a private network perimeter is like saying \u201cYou\u2019re allowed to knock on my front door if you can look up my address in a public directory and walk into my yard.\u201d whereas requiring an identity for an invisible service is like saying \u201cYou\u2019re allowed to knock on my front door if I sent you the secret map to my neighborhood and you have your own unique PIN for the front gate.\u201d The identity that permits you to knock on the door is separate from the login credential, like the key that lets you open the front door.<\/p>\n<p>A familiar example of network perimeter control would be limiting access to the Jenkins UI login prompt to private user network addresses on a VPN or the VPC\u2019s private\u00a0subnets attached to an SSH bastion. An example of an identity control is that your device was issued a certificate that allows you to access the Jenkins server\u2019s login prompt from anywhere. In other words, it\u2019s who you are (your verifiable identity), not where you are (your address with respect to the perimeter).<\/p>\n<p><!-- \/wp:paragraph --><!-- wp:heading {\"level\":3} --><!-- \/wp:paragraph --><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-fecca87 e-grid e-con-full e-con e-child\" data-id=\"fecca87\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-deb056f elementor-widget elementor-widget-image\" data-id=\"deb056f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9ec3b97 elementor-widget__width-inherit elementor-widget-divider--view-line elementor-widget elementor-widget-divider\" data-id=\"9ec3b97\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-230448c elementor-widget elementor-widget-image\" data-id=\"230448c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-8f923a0 e-flex e-con-boxed e-con e-parent\" data-id=\"8f923a0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4815fd2 elementor-widget elementor-widget-text-editor\" data-id=\"4815fd2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>How Do Users Log in to Invisible Jenkins?<\/h3>\n<p>Everyone that needs to log in to Jenkins runs an OpenZiti tunneler on their computer. Each tunneler has an identity installed on the same computer. The OpenZiti network administrator issues these identities via email or chat in the form of one-time enrollment tokens and assigns role attributes that match up with a service policy. The service policies grant permission for those tunneler identities to use Jenkins. We control the service policies through a web console or CLI. As soon as the policy grants access to an enrolled identity, the tunneler automatically configures a private domain name and IP route to the Jenkins server on that user\u2019s computer.<\/p>\n<p>These new controls completely replaced the global DNS and public IP address of the Jenkins server. The Jenkins server stopped listening on an attached network interface address (e.g., 0.0.0.0:443) and is instead only exposed to other processes running on the same device through the loopback interface (e.g., 127.0.0.1:443). The OpenZiti \u201ctunneler\u201d running on the Jenkins server acts like a gatekeeper allowing connections only from OpenZiti identities that are authorized by an OpenZiti service policy.<\/p>\n<p>In an OpenZiti network, your servers and clients are secure network peers and you control the direction of access and which applications are allowed.<\/p>\n<p><!-- \/wp:paragraph --><!-- wp:heading {\"level\":3} --><!-- \/wp:paragraph --><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f6332d6 e-grid e-con-full e-con e-child\" data-id=\"f6332d6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-96a5f93 elementor-widget elementor-widget-image\" data-id=\"96a5f93\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-800765c elementor-widget__width-inherit elementor-widget-divider--view-line elementor-widget elementor-widget-divider\" data-id=\"800765c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e2882de elementor-widget elementor-widget-image\" data-id=\"e2882de\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f94d781 e-flex e-con-boxed e-con e-parent\" data-id=\"f94d781\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-90f4e0f elementor-widget elementor-widget-text-editor\" data-id=\"90f4e0f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>How Does Invisible Jenkins Receive Webhooks From GitHub?<\/h3>\n<p>Here are two examples of Jenkins jobs in our environment. Both are triggered by a GitHub webhook that is sent via OpenZiti instead of the open internet. I used\u00a0<a href=\"https:\/\/web.archive.org\/web\/20240420171325\/https:\/\/github.com\/marketplace\/actions\/ziti-webhook-action\" target=\"_blank\" rel=\"noopener\">the OpenZiti Webhook \u201cAction\u201d from GitHub Actions Marketplace<\/a>\u00a0in both of these cases. This is a Node.JS application that uses the OpenZiti SDK to contact the Jenkins API in the same way the OpenZiti tunnelers do that we installed on our workstations to reach the Jenkins UI.<\/p>\n<p><!-- \/wp:paragraph --><!-- wp:heading {\"level\":3} --><!-- \/wp:paragraph --><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f3feff7 elementor-widget elementor-widget-image\" data-id=\"f3feff7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"750\" height=\"373\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/webhook-invisible-jenkins.png\" class=\"attachment-large size-large wp-image-42556\" alt=\"NetFoundry | Invisible Jenkins\" loading=\"lazy\" srcset=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/webhook-invisible-jenkins.png 750w, https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/webhook-invisible-jenkins-300x149.png 300w\" sizes=\"auto, (max-width: 750px) 100vw, 750px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-0436258 e-grid e-con-full e-con e-child\" data-id=\"0436258\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b8e11fb elementor-widget elementor-widget-image\" data-id=\"b8e11fb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-62756db elementor-widget__width-inherit elementor-widget-divider--view-line elementor-widget elementor-widget-divider\" data-id=\"62756db\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-aa7d2ee elementor-widget elementor-widget-image\" data-id=\"aa7d2ee\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-17213ae e-flex e-con-boxed e-con e-parent\" data-id=\"17213ae\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ffceb1b elementor-widget elementor-widget-text-editor\" data-id=\"ffceb1b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>The Simple Jenkins Job: Just Poll GitHub For Changes<\/h3>\n<p>The simplest example of the OpenZiti webhook is our Jenkins job that needs to poll for changes in a GitHub repo whenever commits are pushed to GitHub. This event triggers a workflow that sends the webhook to Jenkins. This webhook triggers the Jenkins job to poll for changes in the GitHub repo. This is a more secure alternative to sending a GitHub webhook to Jenkins over the internet.<\/p>\n<p>Jenkins can poll a Git remote according to a schedule, but waiting for a scheduled job to run also means waiting to learn whether the build will succeed. To shift that build pain as early as possible I needed the Jenkins job to run as soon as the GitHub event occurred. We were using a custom Jenkins-style webhook generator in GitHub, and so I swapped in the OpenZiti webhook Action in its place. The webhook payload\/context sent by the OpenZiti webhook Action is the same as GitHub\u2019s built-in webhook generator. Still, the OpenZiti webhook Action runs as a step in a GitHub Actions workflow instead of through the GitHub Actions settings. Here\u2019s an example workflow step that sends a webhook via OpenZiti. I\u2019ll explain the three inputs right after the example.<\/p>\n<p><!-- \/wp:paragraph --><!-- wp:heading {\"level\":3} --><!-- \/wp:paragraph --><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a1b5ba9 elementor-widget elementor-widget-image\" data-id=\"a1b5ba9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"784\" height=\"296\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/github.png\" class=\"attachment-large size-large wp-image-42557\" alt=\"NetFoundry | Webhook\" loading=\"lazy\" srcset=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/github.png 784w, https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/github-300x113.png 300w, https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/github-768x290.png 768w\" sizes=\"auto, (max-width: 784px) 100vw, 784px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-46b590d elementor-widget elementor-widget-text-editor\" data-id=\"46b590d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>This is a GitHub Actions workflow that runs on Git push events. The workflow will send the full GitHub event context to the specified URL via OpenZiti instead of the internet. The setup to enable this is as follows:<\/p>\n<ol>\n<li>Create an identity each for:\n<ul>\n<li>Jenkins server<\/li>\n<li>Webhook workflow<\/li>\n<\/ul>\n<\/li>\n<li>Create a service that defines the URL to receive the webhook.<\/li>\n<li>Install an OpenZiti tunneler on the Jenkins host with the first identity you created for Jenkins.<\/li>\n<li>Create Actions secrets for the repo with the three required values:\n<ul>\n<li><strong>ziti-id<\/strong>: the JSON of the second enrolled identity you created for this workflow.<\/li>\n<li><strong>webhook-url<\/strong>: The URL of Jenkins including the service\u2019s OpenZiti domain name, e.g. \u201csomeapp.ziti\u201d<\/li>\n<li><strong>webhook-secret<\/strong>: A random string that\u2019s only saved in the Actions secret and is used by the webhook sender to compute a data integrity hash for the payload data.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9e50588 e-grid e-con-full e-con e-child\" data-id=\"9e50588\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-64afc33 elementor-widget elementor-widget-image\" data-id=\"64afc33\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9793b8d elementor-widget__width-inherit elementor-widget-divider--view-line elementor-widget elementor-widget-divider\" data-id=\"9793b8d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0b44bbf elementor-widget elementor-widget-image\" data-id=\"0b44bbf\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d6ccc7c e-flex e-con-boxed e-con e-parent\" data-id=\"d6ccc7c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f4d3103 elementor-widget elementor-widget-text-editor\" data-id=\"f4d3103\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>The Slightly More Complex Jenkins Job: Adding in Build Parameters<\/h3>\n<p>This job required a little extra setup for Jenkins and GitHub. The result is that I can send custom Jenkins job build parameters inside the same GitHub-style webhook via OpenZiti.<\/p>\n<ol>\n<li>A Git push event triggers the GitHub workflow.<\/li>\n<li>The workflow has a step that uses the OpenZiti webhook.<\/li>\n<li>The OpenZiti webhook accepts \u201cinputs\u201d. We send the Git branch name, the committer, and the computed version as extra data fields to the webhook Action as workflow inputs.<\/li>\n<li>The webhook uses OpenZiti to send the combined GitHub context and extra inputs to Jenkins.<\/li>\n<li>The webhook arrives via the OpenZiti tunneler to the Jenkins server on 127.0.0.1:443 and is parsed by the\u00a0<a href=\"https:\/\/web.archive.org\/web\/20240420171325\/https:\/\/plugins.jenkins.io\/generic-webhook-trigger\/\" target=\"_blank\" rel=\"noopener\">\u201cgeneric webhook trigger\u201d plugin for Jenkins<\/a>.<\/li>\n<li>The JSON fields are parsed as Jenkins job parameters with JSONPath by the Jenkins plugin.<\/li>\n<\/ol>\n<p>The \u201cgeneric webhook trigger\u201d adds a new REST endpoint in the Jenkins server that functions similarly to the Jenkin server\u2019s built-in webhook API. I didn\u2019t modify this Jenkins plugin, but if I had imported the OpenZiti SDK to the plugin, it would have simplified my solution even further by eliminating the need for a running OpenZiti tunneler on the Jenkins server. Here\u2019s\u00a0<a href=\"https:\/\/web.archive.org\/web\/20240420171325\/https:\/\/github.com\/openziti\/ziti\/blob\/main\/.github\/workflows\/jenkins-smoketest.yml\" target=\"_blank\" rel=\"noopener\">a sample workflow<\/a>\u00a0copied below that has two triggers:\u00a0<strong>workflow_call<\/strong>\u00a0and\u00a0<strong>workflow_dispatch<\/strong>. The\u00a0<strong>ziti-version<\/strong>\u00a0input to these triggers is copied to the\u00a0<strong>data<\/strong>\u00a0input of the webhook Action along with the Git\u00a0<strong>branch<\/strong> name from the GitHub context.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6553d28 elementor-widget elementor-widget-image\" data-id=\"6553d28\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"787\" height=\"616\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/jenkins-test.png\" class=\"attachment-large size-large wp-image-42558\" alt=\"NetFoundry | Jenkins Smoketest\" loading=\"lazy\" srcset=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/jenkins-test.png 787w, https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/jenkins-test-300x235.png 300w, https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/jenkins-test-768x601.png 768w\" sizes=\"auto, (max-width: 787px) 100vw, 787px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f78c66b e-grid e-con-full e-con e-child\" data-id=\"f78c66b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-89c3b12 elementor-widget elementor-widget-image\" data-id=\"89c3b12\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-801129f elementor-widget__width-inherit elementor-widget-divider--view-line elementor-widget elementor-widget-divider\" data-id=\"801129f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ea2c17c elementor-widget elementor-widget-image\" data-id=\"ea2c17c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"24\" height=\"24\" src=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-endpoint-gray.svg\" class=\"attachment-large size-large wp-image-36613\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5334972 e-flex e-con-boxed e-con e-parent\" data-id=\"5334972\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7835320 elementor-widget elementor-widget-text-editor\" data-id=\"7835320\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h3>Taking it to the Next Level<\/h3>\n<p>I described a solution for the existing Jenkins users to continue using Jenkins after we switched off the internet visibility of the server. I also explained the configuration in GitHub and Jenkins for two jobs that are both triggered by a GitHub event.<\/p>\n<p>What I\u2019ve done here for Jenkins is highly similar to\u00a0<a href=\"https:\/\/web.archive.org\/web\/20240420171325\/https:\/\/developer.netfoundry.io\/bastion-dark-mode\/\" target=\"_blank\" rel=\"noopener\">what we did for our SSH bastions<\/a>. As you can see, this is a familiar pattern here at NetFoundry! No more mystery connections, no more presumed trust for any address or zone, including private addresses. This problem and the solution are equally applicable to\u00a0<a href=\"https:\/\/web.archive.org\/web\/20240420171325\/https:\/\/github.com\/marketplace\/actions\/ziti-webhook-action\" target=\"_blank\" rel=\"noopener\">GitHub<\/a>\u00a0or\u00a0<a href=\"https:\/\/web.archive.org\/web\/20240420171325\/https:\/\/github.com\/openziti\/ziti-gitlab-webhook\" target=\"_blank\" rel=\"noopener\">GitLab.<\/a>\u00a0There is already an OpenZiti webhook plugin available for both!<\/p>\n<p>The OpenZiti maintainers are reachable at\u00a0<a href=\"https:\/\/web.archive.org\/web\/20240420171325\/https:\/\/openziti.org\/\" target=\"_blank\" rel=\"noopener\">openziti.org.<\/a>\u00a0You can sign up for a free-forever NetFoundry Teams plan to get up and running instantly with a hosted, managed, opinionated deployment of OpenZiti:\u00a0<a href=\"https:\/\/web.archive.org\/web\/20240420171325\/https:\/\/nfconsole.io\/signup\" target=\"_blank\" rel=\"noopener\">nfconsole.io\/signup<\/a>.<\/p>\n<p>Please give our\u00a0<a href=\"https:\/\/web.archive.org\/web\/20240420171325\/https:\/\/github.com\/openziti\/ziti\" target=\"_blank\" rel=\"noopener\">GitHub repo a GOLD STAR<\/a>\u00a0to let us know you\u2019re glad OpenZiti is a thing, and let us know what you\u2019re building\u00a0<a href=\"https:\/\/web.archive.org\/web\/20240420171325\/https:\/\/openziti.discourse.group\/\" target=\"_blank\" rel=\"noopener\">in Discourse<\/a>\u00a0so we can brag on it and help out!<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Why Jenkins? Jenkins is a widely adopted automation tool for building software with a broad array of plugins and\u00a0integrations\u00a0with key DevOps tools like Docker and Kubernetes. Here at NetFoundry, we started out using Jenkins to automate our builds, run tests, and promote releases. Eventually, we expanded to use CI as a service too. There were [&hellip;]<\/p>\n","protected":false},"author":92,"featured_media":42554,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"content-type":"","footnotes":""},"categories":[541],"tags":[970,977,971,973,969,975,976,972,974,857],"class_list":["post-42552","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-ci-cd-pipeline","tag-devops-best-practices","tag-devops-security","tag-invisible-jenkins","tag-jenkins-security","tag-jenkins-server-protection","tag-secure-ci-cd-workflows","tag-secure-jenkins-access","tag-software-development-security","tag-zero-trust-architecture"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.3 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>This is the Way: Invisible Jenkins<\/title>\n<meta name=\"description\" content=\"Discover how to implement Jenkins security and leverage zero trust to secure CI\/CD pipelines, ensuring private, hidden access to your Jenkins servers.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"This is the Way: Invisible Jenkins\" \/>\n<meta property=\"og:description\" content=\"Discover how to implement Jenkins security and leverage zero trust to secure CI\/CD pipelines, ensuring private, hidden access to your Jenkins servers.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/\" \/>\n<meta property=\"og:site_name\" content=\"NetFoundry\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/netfoundry.io\" \/>\n<meta property=\"article:published_time\" content=\"2023-12-04T16:56:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-12-05T15:32:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/this-is-the-way-invisible-jenkins.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1536\" \/>\n\t<meta property=\"og:image:height\" content=\"804\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Philip Griffiths\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@netfoundry\" \/>\n<meta name=\"twitter:site\" content=\"@netfoundry\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Philip Griffiths\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/netfoundry.io\\\/devops\\\/this-is-the-way-invisible-jenkins\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/netfoundry.io\\\/devops\\\/this-is-the-way-invisible-jenkins\\\/\"},\"author\":{\"name\":\"Philip Griffiths\",\"@id\":\"https:\\\/\\\/netfoundry.io\\\/#\\\/schema\\\/person\\\/2020f6a86319585ac99dc3262fb40673\"},\"headline\":\"This is the Way: Invisible Jenkins\",\"datePublished\":\"2023-12-04T16:56:00+00:00\",\"dateModified\":\"2024-12-05T15:32:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/netfoundry.io\\\/devops\\\/this-is-the-way-invisible-jenkins\\\/\"},\"wordCount\":2069,\"publisher\":{\"@id\":\"https:\\\/\\\/netfoundry.io\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/netfoundry.io\\\/devops\\\/this-is-the-way-invisible-jenkins\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/netfoundry.io\\\/wp-content\\\/uploads\\\/2024\\\/12\\\/this-is-the-way-invisible-jenkins.jpg\",\"keywords\":[\"CI\\\/CD Pipeline\",\"DevOps Best Practices\",\"DevOps Security\",\"Invisible Jenkins\",\"Jenkins Security\",\"Jenkins Server Protection\",\"Secure CI\\\/CD Workflows\",\"Secure Jenkins Access\",\"Software Development Security\",\"Zero Trust Architecture\"],\"articleSection\":[\"DevOps\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/netfoundry.io\\\/devops\\\/this-is-the-way-invisible-jenkins\\\/\",\"url\":\"https:\\\/\\\/netfoundry.io\\\/devops\\\/this-is-the-way-invisible-jenkins\\\/\",\"name\":\"This is the Way: Invisible Jenkins\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/netfoundry.io\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/netfoundry.io\\\/devops\\\/this-is-the-way-invisible-jenkins\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/netfoundry.io\\\/devops\\\/this-is-the-way-invisible-jenkins\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/netfoundry.io\\\/wp-content\\\/uploads\\\/2024\\\/12\\\/this-is-the-way-invisible-jenkins.jpg\",\"datePublished\":\"2023-12-04T16:56:00+00:00\",\"dateModified\":\"2024-12-05T15:32:43+00:00\",\"description\":\"Discover how to implement Jenkins security and leverage zero trust to secure CI\\\/CD pipelines, ensuring private, hidden access to your Jenkins servers.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/netfoundry.io\\\/devops\\\/this-is-the-way-invisible-jenkins\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/netfoundry.io\\\/devops\\\/this-is-the-way-invisible-jenkins\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/netfoundry.io\\\/devops\\\/this-is-the-way-invisible-jenkins\\\/#primaryimage\",\"url\":\"https:\\\/\\\/netfoundry.io\\\/wp-content\\\/uploads\\\/2024\\\/12\\\/this-is-the-way-invisible-jenkins.jpg\",\"contentUrl\":\"https:\\\/\\\/netfoundry.io\\\/wp-content\\\/uploads\\\/2024\\\/12\\\/this-is-the-way-invisible-jenkins.jpg\",\"width\":1536,\"height\":804,\"caption\":\"NetFoundry | This is the Way: Invisible Jenkins\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/netfoundry.io\\\/devops\\\/this-is-the-way-invisible-jenkins\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/netfoundry.io\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"This is the Way: Invisible Jenkins\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/netfoundry.io\\\/#website\",\"url\":\"https:\\\/\\\/netfoundry.io\\\/\",\"name\":\"NetFoundry\",\"description\":\"Identity-First\u2122 Networking\",\"publisher\":{\"@id\":\"https:\\\/\\\/netfoundry.io\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/netfoundry.io\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/netfoundry.io\\\/#organization\",\"name\":\"NetFoundry\",\"url\":\"https:\\\/\\\/netfoundry.io\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/netfoundry.io\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/netfoundry.io\\\/wp-content\\\/uploads\\\/2024\\\/08\\\/netfoundry-icon-color.png\",\"contentUrl\":\"https:\\\/\\\/netfoundry.io\\\/wp-content\\\/uploads\\\/2024\\\/08\\\/netfoundry-icon-color.png\",\"width\":512,\"height\":512,\"caption\":\"NetFoundry\"},\"image\":{\"@id\":\"https:\\\/\\\/netfoundry.io\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/netfoundry.io\",\"https:\\\/\\\/x.com\\\/netfoundry\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/netfoundry\\\/\",\"https:\\\/\\\/www.youtube.com\\\/channel\\\/UCGN6PFj1rZu50yme9YsICmg\",\"https:\\\/\\\/www.instagram.com\\\/netfoundry.io\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/netfoundry.io\\\/#\\\/schema\\\/person\\\/2020f6a86319585ac99dc3262fb40673\",\"name\":\"Philip Griffiths\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/dca9b7a1e6d3a47ce3440cd0d6e3d5362df9613f48558fd1dd0ce8816f7c70af?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/dca9b7a1e6d3a47ce3440cd0d6e3d5362df9613f48558fd1dd0ce8816f7c70af?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/dca9b7a1e6d3a47ce3440cd0d6e3d5362df9613f48558fd1dd0ce8816f7c70af?s=96&d=mm&r=g\",\"caption\":\"Philip Griffiths\"},\"url\":\"https:\\\/\\\/netfoundry.io\\\/author\\\/philip-griffiths\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"This is the Way: Invisible Jenkins","description":"Discover how to implement Jenkins security and leverage zero trust to secure CI\/CD pipelines, ensuring private, hidden access to your Jenkins servers.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/","og_locale":"en_US","og_type":"article","og_title":"This is the Way: Invisible Jenkins","og_description":"Discover how to implement Jenkins security and leverage zero trust to secure CI\/CD pipelines, ensuring private, hidden access to your Jenkins servers.","og_url":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/","og_site_name":"NetFoundry","article_publisher":"https:\/\/www.facebook.com\/netfoundry.io","article_published_time":"2023-12-04T16:56:00+00:00","article_modified_time":"2024-12-05T15:32:43+00:00","og_image":[{"width":1536,"height":804,"url":"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/this-is-the-way-invisible-jenkins.jpg","type":"image\/jpeg"}],"author":"Philip Griffiths","twitter_card":"summary_large_image","twitter_creator":"@netfoundry","twitter_site":"@netfoundry","twitter_misc":{"Written by":"Philip Griffiths","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/#article","isPartOf":{"@id":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/"},"author":{"name":"Philip Griffiths","@id":"https:\/\/netfoundry.io\/#\/schema\/person\/2020f6a86319585ac99dc3262fb40673"},"headline":"This is the Way: Invisible Jenkins","datePublished":"2023-12-04T16:56:00+00:00","dateModified":"2024-12-05T15:32:43+00:00","mainEntityOfPage":{"@id":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/"},"wordCount":2069,"publisher":{"@id":"https:\/\/netfoundry.io\/#organization"},"image":{"@id":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/#primaryimage"},"thumbnailUrl":"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/this-is-the-way-invisible-jenkins.jpg","keywords":["CI\/CD Pipeline","DevOps Best Practices","DevOps Security","Invisible Jenkins","Jenkins Security","Jenkins Server Protection","Secure CI\/CD Workflows","Secure Jenkins Access","Software Development Security","Zero Trust Architecture"],"articleSection":["DevOps"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/","url":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/","name":"This is the Way: Invisible Jenkins","isPartOf":{"@id":"https:\/\/netfoundry.io\/#website"},"primaryImageOfPage":{"@id":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/#primaryimage"},"image":{"@id":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/#primaryimage"},"thumbnailUrl":"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/this-is-the-way-invisible-jenkins.jpg","datePublished":"2023-12-04T16:56:00+00:00","dateModified":"2024-12-05T15:32:43+00:00","description":"Discover how to implement Jenkins security and leverage zero trust to secure CI\/CD pipelines, ensuring private, hidden access to your Jenkins servers.","breadcrumb":{"@id":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/#primaryimage","url":"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/this-is-the-way-invisible-jenkins.jpg","contentUrl":"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/12\/this-is-the-way-invisible-jenkins.jpg","width":1536,"height":804,"caption":"NetFoundry | This is the Way: Invisible Jenkins"},{"@type":"BreadcrumbList","@id":"https:\/\/netfoundry.io\/devops\/this-is-the-way-invisible-jenkins\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/netfoundry.io\/"},{"@type":"ListItem","position":2,"name":"This is the Way: Invisible Jenkins"}]},{"@type":"WebSite","@id":"https:\/\/netfoundry.io\/#website","url":"https:\/\/netfoundry.io\/","name":"NetFoundry","description":"Identity-First\u2122 Networking","publisher":{"@id":"https:\/\/netfoundry.io\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/netfoundry.io\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/netfoundry.io\/#organization","name":"NetFoundry","url":"https:\/\/netfoundry.io\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/netfoundry.io\/#\/schema\/logo\/image\/","url":"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-icon-color.png","contentUrl":"https:\/\/netfoundry.io\/wp-content\/uploads\/2024\/08\/netfoundry-icon-color.png","width":512,"height":512,"caption":"NetFoundry"},"image":{"@id":"https:\/\/netfoundry.io\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/netfoundry.io","https:\/\/x.com\/netfoundry","https:\/\/www.linkedin.com\/company\/netfoundry\/","https:\/\/www.youtube.com\/channel\/UCGN6PFj1rZu50yme9YsICmg","https:\/\/www.instagram.com\/netfoundry.io"]},{"@type":"Person","@id":"https:\/\/netfoundry.io\/#\/schema\/person\/2020f6a86319585ac99dc3262fb40673","name":"Philip Griffiths","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/dca9b7a1e6d3a47ce3440cd0d6e3d5362df9613f48558fd1dd0ce8816f7c70af?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/dca9b7a1e6d3a47ce3440cd0d6e3d5362df9613f48558fd1dd0ce8816f7c70af?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/dca9b7a1e6d3a47ce3440cd0d6e3d5362df9613f48558fd1dd0ce8816f7c70af?s=96&d=mm&r=g","caption":"Philip Griffiths"},"url":"https:\/\/netfoundry.io\/author\/philip-griffiths\/"}]}},"_links":{"self":[{"href":"https:\/\/netfoundry.io\/wp-json\/wp\/v2\/posts\/42552","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/netfoundry.io\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/netfoundry.io\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/netfoundry.io\/wp-json\/wp\/v2\/users\/92"}],"replies":[{"embeddable":true,"href":"https:\/\/netfoundry.io\/wp-json\/wp\/v2\/comments?post=42552"}],"version-history":[{"count":0,"href":"https:\/\/netfoundry.io\/wp-json\/wp\/v2\/posts\/42552\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/netfoundry.io\/wp-json\/wp\/v2\/media\/42554"}],"wp:attachment":[{"href":"https:\/\/netfoundry.io\/wp-json\/wp\/v2\/media?parent=42552"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/netfoundry.io\/wp-json\/wp\/v2\/categories?post=42552"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/netfoundry.io\/wp-json\/wp\/v2\/tags?post=42552"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}