What Do You Mean by an Air-Gapped Environment?
Air-gapped environments are computer systems or networks that are physically isolated from the internet and other external networks. This means, your Julia app in this environment will not have access to any public or private package servers that are outside the network. Julia apps have specific deployment characteristics that differentiate them from other applications, especially when considering air-gapped systems. This blog will focus on how to make your Julia app usable in these environments.
Challenges That Your Julia App Will Face in an Air-Gapped Environment
Notarization and code-signing your Julia app:
Julia MacOS binaries might be code-signed and notarized but your Julia app will be shipping a lot more than a Julia binary, so you need to notarize and code-sign your Julia app using a dedicated certificate that's recognized by the operating system.On macOS, Gatekeeper performs an online check with Apple servers. In air-gapped environments, this fails because the OS cannot connect to Apple's servers.
Air-Gapped deployment challenges:
Dependency management for your Julia app must be done offline. Moreover, upgrading the app is more complex and must be managed by your installer.
User environment management:
Julia dependencies (artifacts, registries, package source code, environments, etc.) must work in distributed and multi-user setups. The app should handle diverse environments such as roaming profiles or shared network drives.
License management
This can be particularly tricky in air-gapped environments because you don't have an option to cross-check the license with your public license servers.
Overcoming the Challenges
1. Notarization and code-signing your Julia app:
Windows and Linux currently do not mandate online checks to validate an installer's authenticity, but macOS does. To address this, the first step is to create an installer—either a .pkg installer or a .dmg image is recommended.
Once your code-signed installer image is ready, upload it to Apple's servers for notarization. After Apple successfully checks your application, a ticket is generated. You can then staple this ticket to your installer, allowing Gatekeeper to verify its integrity and authenticity even when macOS is offline.
2. Deploying your app:
a. Dependency management: Ship all Julia prerequisites within your installer. These include (but are not limited to) the Julia binary, artifacts, and the SYSIMG of your Julia app. Be sure to compile the SYSIMG with generic CPU targets to ensure compatibility across devices.
b. Upgrades: Maintain separate depots for every version of your app (Example:- Appending app version to the directory name), and do not assume prerequisites are already installed. Since existing installation may be corrupt, your installer should always ship all prerequisites, even during upgrades. Wherever possible, support concurrent installations.
c. Alternative upgrade method: If your app is shipped as a Julia package, you can set up a local package server. This allows upgrades to be delivered through a bundle to the server, which then distributes updated packages across all Julia installations within the air-gapped environment.
3. User environment management:
a. Ensure your app supports both admin and non-admin installations, because many enterprises do not allow non-admin installations.
b. If the app is installed on a network drive for multi-user access, your startup scripts should support this setup and allow basic customization by storing configurations in each user's home directory. If the configuration spans multiple files, archive them into a single file for transfer, then extract them in the home directory. This significantly reduces time spent copying from a network drive to a local hard disk.
4. License management:
a. If you’re shipping your Julia app as a SYSIMG, integrate license checks within the __init()__ function of your app. Running license checks in __init()__ ensures validation occurs at every launch, and the app can terminate immediately if the check fails, preventing any exposure of functionality.
b. It is advisable to use mature third-party license management solutions rather than building your own, most third-party solutions support floating licenses for offline environments and include protections against clock tampering, one of the biggest threats in an offline environment, along with unauthorized activations (e.g., activating more devices than permitted by the license).
c. Setting up a local license server is a common enterprise approach to prevent unauthorized activations in air-gapped environments.