From 5f4b31102dbd760c9e3144bd20f33e2c19e41f6c Mon Sep 17 00:00:00 2001 From: BitterPanda Date: Wed, 11 Mar 2026 15:27:16 +0100 Subject: [PATCH 1/2] Create a new aikido_endpoint_mdm_ca_install flag --- README.md | 23 +++++++++++++++++++++++ internal/proxy/proxy_ca.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/README.md b/README.md index 6cc3cd99..754ec7c4 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,29 @@ Invoke-WebRequest -Uri "https://github.com/AikidoSec/safechain-internals/release msiexec /i SafeChainUltimate.msi /qn /norestart AIKIDO_TOKEN=YOUR_TOKEN ``` +## MDM Installs + +### CA Certificates + +When deploying via an MDM solution (e.g. Jamf, Mosyle, Kandji), the CA certificate can be pushed by the MDM rather than installed interactively by the agent. + +Create the flag file before running the `.pkg` installer: + +```bash +touch /tmp/aikido_endpoint_mdm_ca_install.txt +``` + +When this flag is present, after the `.pkg` install completes the daemon will: +1. Start the proxy. +2. Download the CA certificate to the run directory (path below) — this is the file your MDM configuration profile should deploy as a trusted root CA. +3. Poll every minute for up to 20 minutes until the MDM has installed the certificate into the system trust store. +4. Only once the certificate is trusted: apply system proxy settings and begin sending heartbeats. + +**CA certificate path (reference this in your MDM configuration profile):** + +- **macOS:** `/Library/Application Support/AikidoSecurity/SafeChainUltimate/run/safechain-proxy-ca-crt.pem` +- **Windows:** `%ProgramData%\AikidoSecurity\SafeChainUltimate\run\safechain-proxy-ca-crt.pem` + ## Uninstall ### macOS diff --git a/internal/proxy/proxy_ca.go b/internal/proxy/proxy_ca.go index ccfd2d71..c13948c9 100644 --- a/internal/proxy/proxy_ca.go +++ b/internal/proxy/proxy_ca.go @@ -6,11 +6,14 @@ import ( "log" "os" "path/filepath" + "time" "github.com/AikidoSec/safechain-internals/internal/platform" "github.com/AikidoSec/safechain-internals/internal/utils" ) +const mdmCAInstallFlagPath = "/tmp/aikido_endpoint_mdm_ca_install.txt" + func GetProxyCAInstalledMarker() string { return filepath.Join(platform.GetRunDir(), ".proxy_ca_installed") } @@ -61,6 +64,12 @@ func InstallProxyCA(ctx context.Context) error { if err := DownloadCACertFromProxy(); err != nil { return err } + + if _, err := os.Stat(mdmCAInstallFlagPath); err == nil { + log.Println("MDM CA install flag detected, polling for MDM-managed CA cert installation...") + return waitForMDMCAInstall(ctx) + } + if err := platform.InstallProxyCA(ctx, GetCaCertPath()); err != nil { return fmt.Errorf("failed to install ca cert: %v", err) } @@ -72,6 +81,30 @@ func InstallProxyCA(ctx context.Context) error { return nil } +func waitForMDMCAInstall(ctx context.Context) error { + const maxAttempts = 20 + + for i := range maxAttempts { + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(time.Minute): + } + + if err := platform.IsProxyCAInstalled(ctx); err == nil { + log.Println("MDM-managed CA cert detected, creating installed marker...") + if err := CreateProxyCAInstalledMarker(); err != nil { + return fmt.Errorf("failed to create proxy CA installed marker: %v", err) + } + log.Println("CA cert installed by MDM successfully") + return nil + } + log.Printf("CA cert not yet installed by MDM, still waiting... (%d/%d)", i+1, maxAttempts) + } + + return fmt.Errorf("CA cert was not installed by MDM within %d minutes", maxAttempts) +} + func UninstallProxyCA(ctx context.Context) error { if err := platform.UninstallProxyCA(ctx); err != nil { return fmt.Errorf("failed to uninstall ca cert: %v", err) From 2ce218da20dc8ce0e6f934f0595610411b30ee6c Mon Sep 17 00:00:00 2001 From: BitterPanda Date: Wed, 11 Mar 2026 15:30:57 +0100 Subject: [PATCH 2/2] Update postinstall for macOS to wait after daemon start for ca cert --- packaging/macos/scripts/postinstall | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packaging/macos/scripts/postinstall b/packaging/macos/scripts/postinstall index 4771dd02..52b258f7 100755 --- a/packaging/macos/scripts/postinstall +++ b/packaging/macos/scripts/postinstall @@ -30,6 +30,8 @@ chown -R root:wheel "$RUN_DIR" AIKIDO_TOKEN="" CONFIG_FILE="$RUN_DIR/config.json" TOKEN_STAGING_FILE="/tmp/aikido_endpoint_token.txt" +MDM_CA_FLAG="/tmp/aikido_endpoint_mdm_ca_install.txt" +CA_CERT_PATH="$RUN_DIR/safechain-proxy-ca-crt.pem" # 1) Explicit token via staging file always wins (fresh install or re-provisioning) if [ -f "$TOKEN_STAGING_FILE" ]; then @@ -86,6 +88,26 @@ else echo "Warning: LaunchDaemon plist not found at $LAUNCHDAEMON_PLIST" fi +# If MDM CA install flag is present, wait for the daemon to download the CA cert +# before exiting so the MDM solution can immediately install it from the known path. +# This is best-effort (120s); use the mdm-install-ca-cert.sh script on the MDM side +# for a reliable install with a longer timeout. +if [ -f "$MDM_CA_FLAG" ]; then + echo "MDM CA install flag detected, waiting for CA cert to be downloaded..." + echo " Expected path: $CA_CERT_PATH" + MAX_WAIT=120 + WAITED=0 + while [ ! -f "$CA_CERT_PATH" ] && [ "$WAITED" -lt "$MAX_WAIT" ]; do + sleep 5 + WAITED=$((WAITED + 5)) + done + if [ -f "$CA_CERT_PATH" ]; then + echo "CA cert is ready at: $CA_CERT_PATH" + else + echo "Warning: CA cert not yet downloaded after ${MAX_WAIT}s — the MDM install script will keep polling." + fi +fi + echo "Post-installation completed" echo "" echo "SafeChain Ultimate has been installed successfully!"