ServiceNow and Jira Setup
Connecting CBOM Secure's notification engine to a ticketing system, so that a policy failure or an expiring certificate opens a ticket in the system your team already works from. This page covers what to create, the exact values to collect, and the field behaviours that most often cost time.
Read the Notification Engine page first for the rule model. This page is the account and credential setup that a destination needs before a rule can use it.
Before you start
| Decision | Why it matters |
|---|---|
| Which system — ServiceNow, Jira, or both | Each is a separate destination; a rule can target either. |
| Which project or table tickets land in | Changing it later means reworking the field map. |
| Who owns the queue | A ticket that lands in an unrouted queue is a silent no-op, which defeats the point of the integration. |
Jira
Which Jira
The two editions differ in ways that affect configuration:
| Jira Cloud | Jira Data Center / Server | |
|---|---|---|
| Base URL | https://<site>.atlassian.net | Your own host |
| Authentication | Basic — email and API token | Bearer — personal access token |
| API path | /rest/api/3/ or /rest/api/2/ | /rest/api/2/ |
| Token created at | id.atlassian.com | User profile, Personal Access Tokens |
Both are supported. The difference is confined to the authentication header and the API version.
Create a service account
Create a dedicated account for CBOM Secure — not a person's account.
A personal account attributes every ticket CBOM opens to a human and breaks the day that person leaves the organisation. Invite the service account to the site as you would any other user.
Create the API token
Sign in as the service account.
Go to Account settings → Security → API tokens.
Create a token, label it for this integration, and copy the value.
The token is displayed once and is a password equivalent. If you create a scoped token instead of a classic one, it needs at minimum read:jira-work and write:jira-work.
Choose the project
Prefer a company-managed project. Company-managed projects share workflow schemes, so the transition names you configure are stable across projects; team-managed projects each carry their own workflow, so a configuration proven in one will not necessarily hold in another.
Record the project key — the prefix on issue identifiers, so CBOM-1 has the key CBOM.
Values to collect
| Field | Example | Secret | Notes |
|---|---|---|---|
base_url | https://example.atlassian.net | No trailing slash | |
email | The service account's address | This is the Basic-auth username | |
api_token | Yes | Encrypted at rest | |
api_version | 3 | Use 2 for plain-text descriptions | |
project_key | CBOM | ||
issue_type | Task | Must exist in that project | |
priority_map | {"critical":"Highest","warning":"Medium"} | Severity to Jira priority | |
labels | ["cbom","crypto-policy"] | Optional | |
done_transition | Resolve by status category, not by name |
Confirm what the project accepts
Run this once against the project, before configuring the destination. It returns the valid issue types and every required field for each — which is where you find out about a mandatory custom field, rather than from a rejected ticket later.
curl -su "$JIRA_EMAIL:$JIRA_API_TOKEN" \
"$JIRA_BASE_URL/rest/api/3/issue/createmeta?projectKeys=CBOM&expand=projects.issuetypes.fields"
Jira behaviours worth knowing
Resolve by status category, not by transition name. Transition names are renamed freely by project administrators; the underlying status category is not. Matching on the name breaks the first time someone renames "Done" to "Complete".
Required in
createmetais not the same as "you must send it". Some fields reported as required have a default that applies on creation. Test rather than assuming.API v3 takes rich-text descriptions in Atlassian Document Format, not plain strings. Use v2 if you want plain text.
A
204means accepted, not applied. Verify a write by reading it back at least once during setup. A comment embedded in a transition request can be accepted and then silently discarded.
ServiceNow
Create the integration user
User Administration → Users → New
| Field | Value | Why |
|---|---|---|
| User ID | cbom.integration | |
| Password | See below | This is what CBOM Secure stores |
| Web service access only | Checked | Blocks interactive sign-in for this account |
| Internal Integration User | Checked | Avoids consuming a fulfiller licence |
| Password needs reset | Unchecked | The most common cause of a correct password returning 401 |
| Active | Checked |
Do not integrate as admin. An admin account bypasses every access control, so the integration works in a test instance and then fails on the production instance the moment a real role model applies. Using a least-privileged account means you meet the same permission boundary during setup that you will meet in production.
Password composition
Use 40 alphanumeric characters. This is a configuration constraint, not a security one: 40 characters of [A-Za-z0-9] is far beyond anything brute-forceable, and it survives every configuration format the value passes through.
Punctuation causes repeated, hard-to-diagnose problems:
| Character | Breaks |
|---|---|
$ # | Environment-file parsing, depending on the loader |
: | Anything storing user:pass as one string |
{ } , | Hand-edited JSON or YAML |
< > & ^ | Windows command-shell metacharacters |
If a credential has appeared in a chat transcript, a shell history file or a ticket, rotate it. On Windows, the PowerShell console keeps history at %APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt.
Assign the role
On the user's Roles tab, add itil. That is the minimum needed to create, read and update incidents. Do not add admin.
Check the Basic Auth Restriction state
If your instance has the Basic Auth Restriction feature active, record four things:
| Item | What you need to know |
|---|---|
| Feature enabled | Is the plugin active |
| Enforcement mode | Tracking, or blocking |
| Default decision | What happens to accounts that have not been reviewed |
| Integration user reviewed | The CBOM account should be explicitly allowed |
An unreviewed account with a deny default is a delayed-fuse failure. The integration works today and stops on the date enforcement begins, with nothing having changed on the CBOM side. Check this before going live, not afterwards.
Create the assignment group
User Administration → Groups → New. Fill in the name and submit.
Two things the new-group form does not show:
| Expected field | Where it actually is |
|---|---|
| Group members | A related list, which does not render on an unsaved record. Submit first, then add members on reload. |
| Type | Not on the default form layout. Add it through Configure → Form Layout if you want it. |
Add at least one real member after saving. An incident assigned to an empty group is technically routed and practically invisible.
Group Type is a form constraint, not an API one: an untyped group accepts the write from CBOM Secure regardless. It matters only when a person picks the group from the incident form.
Collect the group's sys_id by API
Query for it rather than copying it from the record header. Querying proves something the copy does not: that the integration user can read the group. It must be able to, or the reference write will not resolve.
Values to collect
Required — cannot be defaulted
| Field | Example | Secret | Notes |
|---|---|---|---|
base_url | https://example.service-now.com | No trailing slash | |
username | cbom.integration | Not admin | |
password | Yes | Encrypted at rest | |
assignment_group | A sys_id | The identifier, not the display name | |
close_code | From the choice list on your instance | Required in order to resolve a ticket | |
caller_id | A sys_id | Required where your instance enforces it on the API |
Defaultable
| Field | Default | Notes |
|---|---|---|
table | incident | See below |
category | Software | Confirm it exists on your instance |
impact_map | {"critical":"1","warning":"2","info":"3"} | 1 High, 2 Medium, 3 Low |
urgency_map | {"critical":"1","warning":"2","info":"3"} | Same scale |
contact_type | Integration | Cosmetic; makes filtering easy |
dedupe_field | correlation_id | Use a custom field if this one is taken |
journal_field | work_notes | See below |
There is no priority field and there must not be. Priority is derived from impact and urgency through the Priority Lookup table. Configure impact and urgency; a written priority is ignored.
Which table
| Table | Fit | Cost |
|---|---|---|
incident | Works everywhere and is universally understood. Semantically "something broke", which a standing cryptographic weakness is not quite. | Included in the ITSM baseline |
sn_si_incident | Better semantic fit — severity, MITRE fields, Security Operations workflow | Paid module |
sn_vul_vulnerable_item | Best conceptual fit — a weak key is a vulnerable item | Paid module |
change_request | Fits organisations that remediate by change | Included, but the wrong lifecycle |
Start with incident unless you have Security Operations licensed. The table and its field map are configuration, so you can repoint them later without a code change.
work_notes or comments
ServiceNow has two journal fields. work_notes is internal; comments is visible to the caller in the service portal. CBOM Secure's updates are engineering detail, so work_notes is the correct choice. Setting this the other way round exposes infrastructure detail to whoever the caller is.
ServiceNow behaviours worth knowing
Ordered by how much time they typically cost.
Reference fields need a
sys_id, not a display name. Passing a group's name stores nothing on many instances — no error, empty field.priorityis read-only. Writing it is ignored rather than rejected.Resolving needs both
close_codeandclose_notes. A bare state change is rejected or partially applied depending on business rules, and valid close codes differ per instance.State 6 is Resolved, state 7 is Closed. Many instances auto-close resolved incidents after a number of days. Both must be treated as closed, or a case reopens itself when ServiceNow auto-closes it.
Journal fields read back empty on a plain request. You write
work_noteson update but read history from the journal table or with display values requested. An empty read looks exactly like a failed write.A mandatory-field business rule returns 403, not 400. It reads as a permissions problem. Pre-empt it by creating one incident by hand and noting what the form forces.
State values are numeric: 1 New, 2 In Progress, 3 On Hold, 6 Resolved, 7 Closed, 8 Cancelled.
Both
/api/now/and/api/now/v1/work. Be consistent.A
204means accepted, not effective. Read a write back at least once during setup.
If you are using a Personal Developer Instance for testing, note that it hibernates after a period of inactivity and then returns an HTML page with a 200 status. A parse error immediately after a quiet period usually means hibernation, not a configuration fault.
Verify before going live
Confirm each of these before enabling a rule that targets the destination:
The credential authenticates.
The integration user can read the assignment group or project.
A ticket can be created with the exact field set the destination is configured to send.
The created ticket lands in the intended queue and a real person can see it.
A comment or work note can be added to that ticket.
The ticket can be transitioned to resolved or closed with the configured close values.
The ticket can be read back and shows every value that was written.
Step 7 is the one most often skipped, and it is the one that catches an accepted-but-discarded write.
Where credentials are stored
| Stage | Location |
|---|---|
| At rest | Encrypted in the integration record, using the platform's credential encryption key |
| On read | Masked. Writing the mask back does not overwrite the stored secret. |
| In logs | Never. Credential values are redacted across every logging path. |
Credentials must never be placed in a discovery task definition, a dashboard, a widget configuration, or any field that is exported. The integration record is the only place they belong.