How to read system environment variables from repository-stored Java Specs
Platform notice: Server and Data Center only. This article only applies to Atlassian products on the Server and Data Center platforms.
Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.
*Except Fisheye and Crucible
The steps outlined on this article are provided AS-IS. This means we've had reports of them working for some customers — under certain circumstances — yet are not officially supported, nor can we guarantee they'll work for your specific scenario.
You may follow through and validate them on your own non-prod environments prior to production or fall back to supported alternatives if they don't work out.
We also invite you to reach out to our Community for matters that fall beyond Atlassian's scope of support!
Summary
Depending on your environment and scenario, you might need/want to read environment variables from your System. By default, it's not possible to do that, because, since version 6.3, Bamboo enables a Security Manager for Java Specs processing by default. It prevents the Java code from accessing the network, executing other applications, or reading/writing files. This strategy increases security since it could be very dangerous to get Java code from outside (remote repository) and execute it inside Bamboo.
Environment
Using Repository-stored Bamboo Java Specs.
Diagnosis
When trying to read environment variables (example below), the Java Specs processing will fail with the following error:
public static final String rootDomain = System.getenv("MY_VARIABLE");
[ERROR] -----------------------------------------------------: access denied ("java.lang.RuntimePermission" "getenv.MY_VARIABLE")
...
Caused by: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "getenv.MY_VARIABLE")
at java.security.AccessControlContext.checkPermission (AccessControlContext.java:472)
at java.security.AccessController.checkPermission (AccessController.java:886)
at java.lang.SecurityManager.checkPermission (SecurityManager.java:549)
at com.atlassian.bamboo.specs.maven.sandbox.AbstractThreadPermissionVerifier.checkPermission (AbstractThreadPermissionVerifier.java:18)
at com.atlassian.bamboo.specs.maven.sandbox.BambooSpecsSecurityManager.checkPermission (BambooSpecsSecurityManager.java:37)
at java.lang.System.getenv (System.java:894)
at PlanSpec.<clinit> (PlanSpec.java:23)
Cause
As previously mentioned, this is expected because Bamboo enables a Security Manager by default which prevents accessing and executing files.
Solution
Options 1-3 below only work if you are not processing Specs in Docker. If you are, please refer to the Docker section below. Additionally, please make sure that the variable you're trying to read has been picked up by Bamboo. You can check that by going to Cog icon >> Overview >> System information >> Environment Variables section. Environment variables need to be available for the user that runs Bamboo, and Bamboo needs to be restarted in order to pick up newly added variables.
Option 1
The best approach would be to manually modify the Java Policies used by the Security Manager to allow Bamboo to read the environment variables. This allows for more granular access control and poses fewer risks than Option 2 below.
In order to do that:
- Locate the .policy file under ${JAVA_HOME}/jre/lib/security/. It's usually default.policy or java.policy. Please note that this needs to be done under the Java Home directory of the JDK your Bamboo instance uses.
Add the required permissions within the last grant { section:
Policy filepermission java.lang.RuntimePermission "getenv.MY_VARIABLE";
- Save the file and run the Specs Scan again.
To know which permissions to add, please look at the error messages you get when you run the Specs Scan. You can grant access to specific variables only, or to all environment variables at once by using a wildcard: "getenv.*
" (less recommended).
Option 2 (less recommended)
You can fully disable the Security Manager for Specs by adding the following property to the <bamboo-install>/bin/setenv.sh
file and restarting Bamboo.
JVM_SUPPORT_RECOMMENDED_ARGS:="-Dbamboo.repository.stored.specs.security.manager.enabled=false"
Please see Configuring your system properties for detailed steps.
Disabling the Specs Security Manager brings some security risks since this way you will allow execution of any code in Specs.
Option 3
If your scenario doesn't require the value of a variable to be available during the specs scanning process, but rather only during build time (for example, you don't have Specs conditional code that depends on a variable), the best approach would be to use Bamboo Global Variables.
You can reference Bamboo's Global Variables in your Java code directly. Let's say you have defined a Global Variable in Bamboo called "MY_VARIABLE".
[...]
.tasks(new ScriptTask()
.inlineBody("echo ${bamboo_MY_VARIABLE}"))))
[...]
The variable's value will be used when running the build plan:
Substituting variable: ${bamboo.MY_VARIABLE} with GLOBALVALUE
Docker
If your Bamboo is set to process Specs using Docker (cog icon >> Overview >> Security Settings >> Process Bamboo Specs in Docker), the approach will be different. You'll need to maintain your own Docker image to be used by the Docker Specs Runner, with the Java Policies already configured, since Bamboo creates a new container based on the default image every time it runs the Specs analysis. It wouldn't be possible to configure java.policy through Bamboo and use it in the Docker Specs's containers because the Docker Specs Runner runs isolated from Bamboo.
Customizing the image
You can follow the steps below to create your own customized image of the Bamboo Specs Runner:
Pull Atlassian's default image from the Docker Hub repository, replacing
<BAMBOO_VERSION>
accordingly:docker pull atlassian/bamboo-specs-runner:<BAMBOO_VERSION>
Run a dummy container which we'll use as the base for our new image:
docker run atlassian/bamboo-specs-runner:<BAMBOO_VERSION>
The container's Maven output will be an error, but that's expected since we're not actually processing any code at this moment.
Get the ID of the container we've just created:
docker ps -a CONTAINER ID IMAGE COMMAND CREATED b76b7f9198f5 atlassian/bamboo-specs-runner:7.2.6 "/usr/local/bin/mvn-…" 3 minutes ago
Copy the Java Policy file from the container to your local machine:
docker cp <CONTAINER_ID>:/usr/local/openjdk-8/jre/lib/security/java.policy ~/Desktop
Edit the Java Policy file according to your needs. Please see the Option 1 section above to understand what permissions to grant.
Copy the updated Java Policy file back into the container:
docker cp ~/Desktop/java.policy <CONTAINER_ID>:/usr/local/openjdk-8/jre/lib/security/
Commit the container into a Docker Image:
docker commit <CONTAINER_ID> <YOUR_REPO>/<YOUR_IMAGE>:<TAG>
Push the image to your Docker repository:
docker push <YOUR_REPO>/<YOUR_IMAGE>:<TAG>
Once you have your customized image, it's time to configure your Bamboo to use it. Please see Processing Specs in Docker with a customized image for details on how to do that.