Template Security

If everyone who defines templates is a Jenkins administrator—specifically if they have the Overall/RunScripts permission, used for example by the Script Console link—then they can write whatever scripts they like in templates. These scripts may directly refer to internal Jenkins objects using the same API offered to plugins. (Script languages included Groovy, used for several transformers; Jelly, also used for a couple of transformers; and JEXL, used in computed value attributes.) Such users must be completely trusted, as they can do anything to Jenkins (even changing its security settings or running shell commands on the server).

However, if some template creators/maintainers are “regular users” with only more limited permissions, such as Job/Configure, it is inappropriate to let them run arbitrary scripts. To support such a division of roles, the Templates plugin as of version 4.0 supports two related systems: script approval, and Groovy sandboxing. As of 4.6 it includes a binding to the Script Security plugin, which should be consulted for general information on these systems. The following guide merely notes how the Script Security plugin is used by Templates.

Script Approval

The first, and simpler, security system is to allow any kind of script to be run, but only with an administrator’s approval. There is a globally maintained list of approved scripts which are judged to not perform any malicious actions.

When an administrator saves a template configuration, any scripts it contains are automatically added to the approved list. They are ready to run with no further intervention. (“Saving” usually means from the web UI, but could also mean uploading a new configuration via REST or CLI. See the section called “Scripting Templates”.)

When a non-administrator saves a template configuration, a check is done whether any contained scripts have been edited from an approved text. (More precisely, whether the requested content has ever been approved before.) If it has not been approved, a request for approval of this script is added to a queue. (A warning is also displayed in the configuration screen UI when the current text of a script is not currently approved.)

An administrator may now go to Manage Jenkins » In-process Script Approval where a list of scripts pending approval will be shown. Assuming nothing dangerous-looking is being requested, just click Approve to let the script be run henceforth.

Builder and publisher templates using unapproved scripts (mainly Groovy or Jelly transformers, but also JEXL computed values) present no special issue: unless and until the script is approved, trying to run a build using that build step will fail. You may retry once the script has been approved.

Job and folder templates using unapproved transformer scripts are a little trickier. Existing template instances will continue to use the former script definition; as soon as the script is approved, they will be updated. New jobs or folders cannot be created from the template until its script is approved. (Currently unapproved computed values will just be left as null, but there is no such fallback option in general for job template transformers.)

Groovy Sandboxing

Waiting for an administrator to approve every change to a script, no matter how seemingly trivial, could be unacceptable in a team spread across timezones or during tight deadlines. As an alternative option, the Templates plugin lets Groovy scripts be run without approval so long as they limit themselves to operations considered inherently safe. This limited execution environment is called a sandbox. (Currently no sandbox implementations are available for the Jelly or JEXL languages, so all such scripts must be approved if configured by non-administrators.)

To switch to this mode, simply check the box Use Groovy Sandbox below the Groovy script’s entry field. Sandboxed scripts can be run immediately by anyone. (Even administrators, though the script is subject to the same restrictions regardless of who wrote it.) When the script is run, every method call, object construction, and field access is checked against a whitelist of approved operations. If an unapproved operation is attempted, the script is killed and the template cannot be used.

The Templates plugin ships with a small default whitelist: enough to print the values of template attributes (including those from auxiliary models), and not much else. The Script Security plugin, or other plugins, may offer other whitelisted operations by default.

But you are not limited to the default whitelist: every time a script fails before running an operation that is not yet whitelisted, that operation is automatically added to another approval queue. An administrator can go to the same page described above for approval of entire scripts, and see a list of pending operation approvals. If Approve is clicked next to the signature of an operation, it is immediately added to the whitelist and available for sandboxed scripts.

Most signatures be of the form method class.Name methodName arg1Type arg2Type…, indicating a Java method call with a specific “receiver” class (this), method name, and list of argument (or parameter) types. (The most general signature of an attempted method call will be offered for approval, even when the actual object it was to be called on was of a more specific type overriding that method.) You may also see staticMethod for static (class) methods, new for constructors, and field or staticField for field accesses (get or set).

As with unapproved scripts, sandboxed scripts using illegal operations pose no special issue for builder and publisher templates; just try rerunning the build. New job or folder instances again cannot be created from the template until it uses only whitelisted operations. Existing job or folder templates instances also will not be updated before all operations run by the script are approved; unlike whole-script approval, in this case the instances are not automatically refreshed just because the whitelist has been expanded. To trigger a refresh, resave the template (or of course you may edit its script to not invoke unapproved operations).

Administrators in security-sensitive environments should carefully consider which operations to whitelist. Operations which change state of persisted objects (such as Jenkins jobs) should generally be denied (and these have no legitimate use in templates anyway, which are not supposed to have any side effects). Most getSomething methods are harmless.

Be aware however that even some “getter” methods are designed to check specific permissions, whereas scripts are often run by a system pseudo-user to whom all permissions are granted. So for example method hudson.model.AbstractItem getParent (which obtains the folder containing a job) is in and of itself harmless, but the possible follow-up call method hudson.model.ItemGroup getItems (which lists jobs by name within a folder) checks Job/Read. This second call would be dangerous to whitelist unconditionally, since it would mean that a user who is granted Job/Create in a folder would be able to read at least some information from any jobs in that folder, even those which are supposed to be hidden according to e.g. RBAC role filtering; it would suffice to create a job template using a Groovy transformer like this:

<project><description>I sniffed ${parent.getItems()}!</description></project>

When instantiated as a throwaway job, its description would display at least the names of supposedly secret projects. You may instead click Approve assuming permission check for getItems; this will permit the call when run as an actual user (for example when someone saves the templatized job), while forbidding it when run as the system user (for example when someone saves the template and its instances are updated in the background). In this case, getItems will actually return only those jobs which the current user has access to, so if run in the former case (by saving the templatized job), the description will show just those jobs they could see anyway. This more advanced button is shown only for method calls (and constructors), and should be used only where you know that Jenkins is doing a permission check.