This article is based on a post originally published on the Atlassian Developer Blog. It describes the architecture and design decisions behind the Jira Software Cloud plugin for Jenkins.
Jenkins to Jira: A New Type of Integration
The Jira Software Cloud plugin for Jenkins allows engineering teams to automatically send build and deployment information from Jenkins pipelines into Jira Cloud. Once connected, build and deployment status appears directly on Jira issues and boards, and can be queried using JQL. Deep links let engineers jump from a failed build or deployment in Jira straight to the relevant Jenkins job for investigation.
The integration is open source and available on the Jenkins Plugin Index. If you want to contribute or fork the plugin, the source is hosted on the Jenkins GitHub repository.
The Core Security Challenge: Behind-the-Firewall to Cloud
Connecting an on-premises tool like Jenkins to a cloud product like Jira Software Cloud introduces a fundamental security challenge: how do you allow the Jenkins server to push data outward without opening inbound firewall ports or exposing your Jira instance to potential breaches?
The solution Atlassian built is a new two-legged OAuth (2LO) credential that Jira administrators create directly within their Jira Cloud site. Key properties of this credential include:
- Explicit scoping: The credential is scoped only to send build and deployment information and associate it with Jira issue keys. It cannot be used to read or modify any other Jira data.
- One-way data flow: Jenkins sends data outbound to Jira Cloud APIs. No inbound connection to the Jenkins server is required, so no firewall ports need to be opened.
- Minimal blast radius on credential leak: Even if the credential were compromised, an attacker could only determine whether a given Jira issue key is valid — they could not access any private Jira issue data.
This approach also deliberately avoids the limitations of Atlassian Connect, the standard integration framework, which requires a callback to a shared secret (meaning customers must keep a firewall port open) and uses a coarse-grained permission model where a scoped app can read broadly across Jira issue data.
How the Jenkins Plugin Works
The Jenkins plugin is built on the Jenkins Pipeline API and consists of three main components:
- Global configuration — a section added to Manage Jenkins → Configure System where administrators define Jira Cloud sites and their corresponding OAuth credentials. Credentials are encrypted and stored in the Jenkins credentials store.
- jiraSendBuildInfo — a Pipeline step that collects and sends build information to Jira Cloud.
- jiraSendDeploymentInfo — a Pipeline step that collects and sends deployment information to Jira Cloud.
jiraSendBuildInfo
This step is designed to run as a post-build action in a Jenkinsfile. It collects the current build status and sends it to the configured Jira Cloud site using the Jira Cloud Builds API.
To associate the build with one or more Jira issues, the plugin parses the branch name for Jira issue keys. For example, a branch named TEST-123-awesome-new-feature will result in the build being linked to issue TEST-123. By default the branch name is read from the Jenkins SCM API, but it can also be specified explicitly as a parameter — useful when you want to associate a build result with a specific issue regardless of branch naming.
post {
always {
jiraSendBuildInfo site: 'example.atlassian.net'
}
}Code language: JavaScript (javascript)
jiraSendDeploymentInfo
This step also runs as a post-build action and sends deployment information to Jira Cloud using the Jira Cloud Deployments API. It requires the following parameters:
site— the Jira Cloud site hostname, e.g.example.atlassian.netenvironmentId— a unique identifier for the environment, e.g.prod-eastenvironmentName— a human-readable name, e.g.Production EastenvironmentType— one of:development,testing,staging, orproduction
Rather than parsing branch names, this step associates deployments with Jira issues by scanning commit messages in the Jenkins ChangeLogSet API. For example, if the changelog includes commits with messages like TEST-123 First commit and TEST-345 Second commit, the deployment is linked to both TEST-123 and TEST-345.
post {
always {
jiraSendDeploymentInfo(
site: 'example.atlassian.net',
environmentId: 'prod-east',
environmentName: 'Production East',
environmentType: 'production'
)
}
}Code language: JavaScript (javascript)
How the Jira Side Was Built
The Atlassian team identified three key challenges when building the Jira Cloud back-end for this integration:
- Keeping the UI simple enough for a Jira administrator with no developer background to use
- Ensuring maximum credential and data security
- Avoiding adding code to the Jira monolith codebase
The UI
Atlassian was migrating its Jira front-end to a React/Redux single-page application (SPA) at the time of development. The team used internal front-end platform tooling that pre-wired state management, analytics, and AtlasKit UI components. This allowed the team to focus on shipping a minimal, functional UI quickly — deliberately deferring features like in-place editing of application names until customer demand was confirmed.
Security Design
Security was the highest priority for the back-end service. Before the initial rollout, the team partnered with Atlassian’s security team for a full audit. Notable security decisions included:
- No credentials stored in the service. A stateless service with no persistent credential store presents a much smaller attack surface.
- Audit trail data only. The service does store some data, but only for traceability purposes — it contains no information that could be used to access private resources.
- Log filtering. Care was taken to ensure credentials cannot appear in logs or stack traces, a common and easily missed vulnerability.
- Fine-grained OAuth scopes. As described above, the credential is explicitly scoped to the build and deployment APIs only, limiting exposure in the event of a credential leak.
Avoiding the Monolith
The team built a dedicated microservice for the back-end rather than adding code to the Jira monolith. Their stated reasons for this approach reflect common microservices migration motivations:
- The monolith’s development loop is slow — a full branch build in Bamboo reportedly takes over an hour.
- Releasing a feature through the monolith takes approximately two days; deploying from the microservice takes under 20 minutes from pull request merge.
- Adding to the monolith creates additional technical debt and complicates the ongoing migration to microservices.
- The internal microservices platform offers higher reliability and lower response times than the monolith.
The new microservice was written in Kotlin on Spring Boot, with a single DynamoDB table used for audit trail data. All core functionality is implemented by chaining REST calls to Atlassian’s platform APIs — the team reports the core logic fits in under 1,000 lines of Kotlin.
One practical challenge the team encountered: because this is a system-to-system integration, traffic volume is inherently low and credentials have long lifespans. A dependency could break its API and the problem might not surface until a customer reports an issue days later. The team addressed this by implementing frequent semantic monitoring — proactive checks that validate the behavior of dependencies, not just their availability.
What This Enables for Teams
With the integration in place, engineering teams gain:
- Build status on Jira issues: Every issue linked to a branch or commit shows the current build state (passing, failing, in progress) without leaving Jira.
- Deployment tracking: Jira issues show which environments a feature has been deployed to and when.
- JQL queries: Teams can filter and search Jira issues by build or deployment status using JQL.
- Deep links to Jenkins: Failed builds or deployments in Jira link directly to the relevant Jenkins job for fast investigation.
- No firewall changes required: Jenkins communicates outbound only; no inbound rules need to change.
Future Direction
At the time of the original post (December 2019), Atlassian indicated plans to expand the OAuth credential scope to support additional data types — including commits, branches, and pull requests — which would enable similar integrations for Bitbucket Server, GitHub Enterprise, and GitLab with Jira Software Cloud. The team expressed a goal of being able to add support for new data types in under a month by extending the API specification.
Check the Jenkins Plugin Index and the Jenkins GitHub organisation for the current state of the plugin and any updates to its capabilities.