This document will explain how to connect Jira Align SaaS to a Jira Data Center via Apigee with Basic Authentication (API Key) .
Given 1: The customer has selected Jira Align SaaS in either multi-tenant or dedicated VPC configuration. This does not directly apply for an on premise implementation of Jira Align.
Given 2: The customer hosts Jira Data Center behind a firewall, without currently exposing the Jira Data Center API ports externally
Given 3: The customer uses Apigee as an API Gateway for network edge security and REST API ingress.
Please review the following example and adjust for your organization's security policies, security posture, and security practices.
All REST API traffic will initiate from the Jira Connector for Jira Align.
The Jira Connector for Jira Align currently supports two authentication methods:
Basic Authentication
OAuth 1.0a.
The preferred authentication policy configuration for Apigee is the API Key, instead of Basic Authentication. This policy configuration allows Jira Align to send the API Key in the Basic Authentication header.
In the Jira Align administrator interface, the administrator would select Basic Auth and input the supported Apigee API key.
Using a custom Apigee integration, the Apigee tool would extract the API key from the Basic Auth header and validate it.
The next step in the custom Apigee integration would modify the inbound request to replace the Basic Authentication header with the Jira Service Account username and password, which is stored in an encrypted KVM and forward the request onto Jira Server/Data Center.
Note: At this point the Apigee solution would also perform the public to private DNS mapping.
Note 2: The Apigee service can also restrict the requests to the Jira endpoint.
We also highly recommend configuring Mutual TLS and/or IP Allow listing at the Apigee policy level to establish multi-factor authentication policy. A sample IP allow list policy is covered in this article. As always, please review and validate these policies with your Head of IT Security before configuring in your environment.
You’ll want one proxy for each Jira Align connector (Ex: Test and Prod).
The following configurations are not supported between Apigee and Jira Align:
OAuth 1.0a
OAuth 2.0
Bearer token
Mutual TLS between Jira Align and Apigee is not covered in this article but enabling MFA is part of the User Compensating Control requirements of the Jira Align SOC 2 compliance.
Jira Data Center service account is created.
Access to the Jira Data Center service account.
Admin access to Apigee Edge
Rights to create API key
Rights to create a new reverse proxy
Rights to add data to KVM
Super administrator access to instance of Jira Align
1.) Sign in to Apigee Edge and click on API Proxies.
2.) Click +Proxy to create a new Proxy.
3. Select Reverse proxy.
4.) Fill in the Proxy name, the base path, and Target API (Jira site).
You’ll need 2 base paths (one for prod, one for test) to connect Jira Align to your Production Jira DataCenter and Test Jira DataCenter.
5.) Select API Key in the Security: Authorization options.
Do not enable CORS
Quota configuration and design is not in scope for this document. For the purposes of establishing connections, please do not enable at this time.
6.) Select secure in the Virtual hosts options.
7.) Click Create.
8.) In the Apigee Edge tool, go to Admin > Environments > Key Value Maps.
Make sure to select the correct environment.
We recommend to use the test environment first.
9.) Create Key Value Map.
Example:
kvm_store_1 (encrypted)
key: name, value: <jira-service-acct-username>
key: pass, value: <jira-service-acct-password>
10) Navigate to Develop > API Proxies > Select your Proxy > Develop Tab.
11) Create these policies. You can paste the Verify API Key policy below over the existing one.
Type: AccessControl
This policy permits certain IPs (or IP ranges) to connect to the proxy.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AccessControl async="false" continueOnError="false" enabled="true" name="IP-Allow-List">
<DisplayName>IP Allow List</DisplayName>
<Properties/>
<IPRules noRuleMatchAction="DENY">
<MatchRule action="ALLOW">
<SourceAddress mask="32"><Example-IP></SourceAddress>
</MatchRule>
</IPRules>
</AccessControl>
Type: BasicAuthentication
This policy decodes the inbound (to Apigee) Basic Auth Header and stores the decoded username and password in variables.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<BasicAuthentication name="Decode-Basic-Auth-Headers">
<DisplayName>Decode Basic Auth Headers</DisplayName>
<Operation>Decode</Operation>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<User ref="request.header.username"/>
<Password ref="request.header.password"/>
<Source>request.header.Authorization</Source>
<Set/>
</BasicAuthentication>
Type: BasicAuthentication
This policy encodes the outbound (to Jira Data Center) Basic Auth Header using the variables created in the KeyValueMapOperations policy (Get-KVM).
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<BasicAuthentication async="false" continueOnError="false" enabled="true" name="Encode-Basic-Auth-Headers">
<DisplayName>Encode Basic Auth Headers</DisplayName>
<Operation>Encode</Operation>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<User ref="private.service.name"/>
<Password ref="private.service.pass"/>
<AssignTo createNew="true">request.header.Authorization</AssignTo>
<Source>request.header.Authorization</Source>
</BasicAuthentication>
Type: KeyValueMapOperations
This policy places the Jira service username and password defined in the Key Value Map Store into private variables.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<KeyValueMapOperations async="false" continueOnError="false" enabled="true" name="Get-KVM" mapIdentifier="kvm_store_1">
<DisplayName>Get KVM</DisplayName>
<Properties/>
<Get assignTo="private.service.name">
<Key>
<Parameter>name</Parameter>
</Key>
</Get>
<Get assignTo="private.service.pass">
<Key>
<Parameter>pass</Parameter>
</Key>
</Get>
<Scope>environment</Scope>
</KeyValueMapOperations>
Type: AssignMessage
This policy cleans up Basic Auth Headers that are no longer needed after decoding and extraction has been completed.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="Remove-Basic-Auth-Headers">
<DisplayName>Remove Basic Auth Headers</DisplayName>
<Properties/>
<Remove>
<Headers>
<Header name="request.header.Authorization"/>
</Headers>
</Remove>
<Remove>
<Headers>
<Header name="request.header.username"/>
</Headers>
</Remove>
<Remove>
<Headers>
<Header name="request.header.password"/>
</Headers>
</Remove>
<Remove>
<Headers>
<Header name="username"/>
</Headers>
</Remove>
<Remove>
<Headers>
<Header name="password"/>
</Headers>
</Remove>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
Type: VerifyAPIKey
This policy takes the password decoded during "Decode-Basic-Auth-Headers" and validates it against the Apigee API Key.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<VerifyAPIKey async="false" continueOnError="false" enabled="true" name="Verify-API-Key">
<DisplayName>Verify API Key</DisplayName>
<APIKey ref="request.header.password"/>
</VerifyAPIKey>
12) Place this in your Proxy Endpoint PreFlow and PostFlow after making any adjustments (such as BasePath).
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
<PreFlow name="PreFlow">
<Request>
<Step>
<Name>IP-Allow-List</Name>
</Step>
<Step>
<Condition>(proxy.pathsuffix != "/rest/api/2/serverInfo")</Condition>
<Name>Decode-Basic-Auth-Headers</Name>
</Step>
<Step>
<Condition>(proxy.pathsuffix != "/rest/api/2/serverInfo")</Condition>
<Name>Verify-API-Key</Name>
</Step>
<Step>
<Name>Remove-Basic-Auth-Headers</Name>
</Step>
</Request>
<Response/>
</PreFlow>
<Flows/>
<PostFlow name="PostFlow">
<Request>
<Step>
<Condition>(proxy.pathsuffix != "/rest/api/2/serverInfo")</Condition>
<Name>Get-KVM</Name>
</Step>
<Step>
<Condition>(proxy.pathsuffix != "/rest/api/2/serverInfo")</Condition>
<Name>Encode-Basic-Auth-Headers</Name>
</Step>
</Request>
<Response/>
</PostFlow>
<HTTPProxyConnection>
<BasePath>/Jira-Align-Test</BasePath>
<VirtualHost>secure</VirtualHost>
</HTTPProxyConnection>
<RouteRule name="default">
<TargetEndpoint>default</TargetEndpoint>
</RouteRule>
</ProxyEndpoint>
13) Validate that this in your Target Endpoint PreFlow and PostFlow. (Do not paste over the existing policy.)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TargetEndpoint name="default">
<PreFlow name="PreFlow">
<Request/>
<Response/>
</PreFlow>
<Flows/>
<PostFlow name="PostFlow">
<Request/>
<Response/>
</PostFlow>
<HTTPTargetConnection>
<URL>https://<your Jira server></URL>
</HTTPTargetConnection>
</TargetEndpoint>
14) Save and Deploy to Test (or Prod if you are skipping Test).
Note: Trace is a great way to test and troubleshoot.
15) Go to Publish > API Products. Create new API Product.
16.) Give the API Product a name, access, environment(s), and add the recently created API proxy.
17.) Click Save.
18.) Go to Publish > Apps. Create new App.
19.) Give the App a name and add the recently created API Product.
20.) Click Create.
21.) In the newly created app, you should see the Key. Note that key for later use.
22.) Sign in to Jira Align as a super administrator, and navigate to Admin > Jira Settings > Jira Connectors.
23.) Enter the Jira Base URL (+ /browse/{external} ) into Jira Link.
24.) Assign this connector a memorable name.
25.) Enter the Apigee API Endpoint and base path from step 6 and step 4 into Jira API URL. (ex: https://example.apigee.net/Jira-Align-Test )
26.) Select Basic with API token Authentication as Authentication Type and set the username to something random and password as Key from step 21.
27.) Click Save.
28.) Click Test Now. (Note: You’ll need to close and open this box to see the Test refresh.)
29.) Assuming the test was good, go ahead and press Activate and Save.
30.) Then you can proceed with Syncing a Project.
James McCulley
Network & Security Solutions Architect
Atlassian
2 comments