update
This commit is contained in:
@@ -48,9 +48,11 @@ keepalived Deploy Keepalived across the cluster
|
|||||||
## Companion files
|
## Companion files
|
||||||
|
|
||||||
Large installer artifacts used by this project are stored in the private
|
Large installer artifacts used by this project are stored in the private
|
||||||
`TAI/files` package registry. SentinelOne installation requires a temporary
|
`TAI/files` package registry. SentinelOne, RMM, Acronis, and ScreenConnect
|
||||||
deployment code from TAPM Deployment Access; the private Gitea credential is
|
installation require a temporary deployment code from TAPM Deployment Access.
|
||||||
never stored on or returned to a Proxmox host.
|
The private Gitea credentials are never stored on or returned to a Proxmox
|
||||||
|
host. SentinelOne package versions can be updated through the deployment
|
||||||
|
portal without changing ProxMenu.
|
||||||
|
|
||||||
## Runtime requirements
|
## Runtime requirements
|
||||||
|
|
||||||
|
|||||||
+3
-4
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
action="${1:-}"
|
action="${1:-}"
|
||||||
FOLDER='/opt/idssys/ta-proxmenu'
|
FOLDER='/opt/idssys/ta-proxmenu'
|
||||||
VERS='2026.7.25-19'
|
VERS='2026.7.25-20'
|
||||||
|
|
||||||
noupdate=' '
|
noupdate=' '
|
||||||
|
|
||||||
@@ -25,10 +25,9 @@ if [[ -z "$VIRTIO_DOWNLOAD_URL" ]]; then
|
|||||||
fi
|
fi
|
||||||
VIRTIO_FILE="${VIRTIO_DOWNLOAD_URL##*/}"
|
VIRTIO_FILE="${VIRTIO_DOWNLOAD_URL##*/}"
|
||||||
|
|
||||||
S1_VERSION='26_1_1_31'
|
TAPM_BROKER_URL='https://tapm.scity.us'
|
||||||
S1_PACKAGE="SentinelAgent_linux_x86_64_v${S1_VERSION}.deb"
|
|
||||||
S1_BROKER_URL='https://tapm.scity.us'
|
|
||||||
S1_BROKER_PACKAGE='sentinelone-linux'
|
S1_BROKER_PACKAGE='sentinelone-linux'
|
||||||
|
S1_PACKAGE='tapm-sentinelone.deb'
|
||||||
|
|
||||||
if [[ -d /mnt/pve/PVE-Shared-Storage/template/iso ]]; then
|
if [[ -d /mnt/pve/PVE-Shared-Storage/template/iso ]]; then
|
||||||
DLDIR='/mnt/pve/PVE-Shared-Storage/template/iso'
|
DLDIR='/mnt/pve/PVE-Shared-Storage/template/iso'
|
||||||
|
|||||||
+108
-60
@@ -14,6 +14,91 @@ FINISH_ACTION() {
|
|||||||
ENTER2CONTINUE
|
ENTER2CONTINUE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TAPM_CLEAR_AUTHORIZATION() {
|
||||||
|
unset TAPM_SESSION_TOKEN TAPM_PACKAGE_URL TAPM_PACKAGE_SHA256 TAPM_PACKAGE_VERSION
|
||||||
|
}
|
||||||
|
|
||||||
|
TAPM_AUTHORIZE() {
|
||||||
|
local required_action="${1:-}"
|
||||||
|
local required_package="${2:-}"
|
||||||
|
local authorization_label="${3:-this installation}"
|
||||||
|
local deploycode exchange_response host_fingerprint
|
||||||
|
local -a access
|
||||||
|
|
||||||
|
TAPM_CLEAR_AUTHORIZATION
|
||||||
|
if ! command -v python3 >/dev/null 2>&1; then
|
||||||
|
echo -e "${idsCL[LightRed]}Python 3 is required to authorize ${authorization_label}.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo -en "${idsCL[LightYellow]}Paste the TAPM deployment code: ${idsCL[Default]}"
|
||||||
|
read -r -s deploycode
|
||||||
|
echo
|
||||||
|
deploycode="${deploycode^^}"
|
||||||
|
if [[ ! "$deploycode" =~ ^TAPM-[0-9A-HJKMNP-TV-Z]{5}-[0-9A-HJKMNP-TV-Z]{5}$ ]]; then
|
||||||
|
unset deploycode
|
||||||
|
echo -e "${idsCL[LightRed]}The TAPM deployment code is not valid.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
host_fingerprint="$(sha256sum /etc/machine-id | cut -d' ' -f1)"
|
||||||
|
exchange_response="$(
|
||||||
|
TAPM_CODE="$deploycode" TAPM_FINGERPRINT="$host_fingerprint" TAPM_HOSTNAME="$(hostname)" \
|
||||||
|
TAPM_REQUESTED_ACTION="$required_action" TAPM_REQUESTED_PACKAGE="$required_package" \
|
||||||
|
python3 -c 'import json, os, sys; json.dump({"code": os.environ["TAPM_CODE"], "host_fingerprint": os.environ["TAPM_FINGERPRINT"], "hostname": os.environ["TAPM_HOSTNAME"], "requested_action": os.environ["TAPM_REQUESTED_ACTION"], "requested_package": os.environ["TAPM_REQUESTED_PACKAGE"]}, sys.stdout)' |
|
||||||
|
curl --fail --silent --show-error \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data-binary @- "${TAPM_BROKER_URL}/api/v1/exchange"
|
||||||
|
)" || {
|
||||||
|
unset deploycode host_fingerprint exchange_response
|
||||||
|
echo -e "${idsCL[LightRed]}TAPM could not authorize ${authorization_label}.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
unset deploycode host_fingerprint
|
||||||
|
|
||||||
|
mapfile -t access < <(
|
||||||
|
printf '%s' "$exchange_response" |
|
||||||
|
TAPM_REQUIRED_ACTION="$required_action" TAPM_REQUIRED_PACKAGE="$required_package" \
|
||||||
|
python3 -c '
|
||||||
|
import json, os, sys
|
||||||
|
data = json.load(sys.stdin)
|
||||||
|
required_action = os.environ["TAPM_REQUIRED_ACTION"]
|
||||||
|
required_package = os.environ["TAPM_REQUIRED_PACKAGE"]
|
||||||
|
if required_action and required_action not in data.get("actions", []):
|
||||||
|
raise SystemExit(1)
|
||||||
|
package = None
|
||||||
|
if required_package:
|
||||||
|
package = next((item for item in data.get("packages", []) if item.get("slug") == required_package), None)
|
||||||
|
if not package:
|
||||||
|
raise SystemExit(1)
|
||||||
|
print(data.get("session_token", ""))
|
||||||
|
print(package.get("download_url", "") if package else "")
|
||||||
|
print(package.get("sha256", "") if package else "")
|
||||||
|
print(package.get("version", "") if package else "")
|
||||||
|
'
|
||||||
|
) || true
|
||||||
|
unset exchange_response
|
||||||
|
|
||||||
|
if [[ ${#access[@]} -ne 4 || -z "${access[0]}" ]]; then
|
||||||
|
unset access
|
||||||
|
echo -e "${idsCL[LightRed]}This deployment code does not authorize ${authorization_label}.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [[ -n "$required_package" &&
|
||||||
|
( -z "${access[1]}" || ! "${access[2]}" =~ ^[0-9a-fA-F]{64}$ ) ]]; then
|
||||||
|
unset access
|
||||||
|
echo -e "${idsCL[LightRed]}The authorized package metadata is incomplete.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TAPM_SESSION_TOKEN="${access[0]}"
|
||||||
|
TAPM_PACKAGE_URL="${access[1]}"
|
||||||
|
TAPM_PACKAGE_SHA256="${access[2],,}"
|
||||||
|
TAPM_PACKAGE_VERSION="${access[3]}"
|
||||||
|
unset access
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
INSTALL_PULSE() {
|
INSTALL_PULSE() {
|
||||||
echo
|
echo
|
||||||
bash <(curl -fsSL https://github.com/rcourtman/Pulse/releases/latest/download/install.sh)
|
bash <(curl -fsSL https://github.com/rcourtman/Pulse/releases/latest/download/install.sh)
|
||||||
@@ -28,6 +113,11 @@ INSTALL_ACRONIS() {
|
|||||||
[Nn]) echo;;
|
[Nn]) echo;;
|
||||||
* )
|
* )
|
||||||
echo
|
echo
|
||||||
|
if ! TAPM_AUTHORIZE "install-acronis" "" "Acronis installation"; then
|
||||||
|
FINISH_ACTION
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
TAPM_CLEAR_AUTHORIZATION
|
||||||
cd /tmp || return 1
|
cd /tmp || return 1
|
||||||
wget "https://us5-cloud.acronis.com/bc/api/ams/links/agents/redirect?language=multi&channel=CURRENT&system=linux&architecture=64&productType=enterprise&login=010180ae-63c4-4495-bed0-4ec934c25af9&white_labeled=0" -O ./acronisinstall
|
wget "https://us5-cloud.acronis.com/bc/api/ams/links/agents/redirect?language=multi&channel=CURRENT&system=linux&architecture=64&productType=enterprise&login=010180ae-63c4-4495-bed0-4ec934c25af9&white_labeled=0" -O ./acronisinstall
|
||||||
chmod +x ./acronisinstall
|
chmod +x ./acronisinstall
|
||||||
@@ -81,6 +171,11 @@ INSTALL_SCREENCONNECT() {
|
|||||||
[Nn]) echo;;
|
[Nn]) echo;;
|
||||||
* )
|
* )
|
||||||
echo
|
echo
|
||||||
|
if ! TAPM_AUTHORIZE "install-screenconnect" "" "ScreenConnect installation"; then
|
||||||
|
FINISH_ACTION
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
TAPM_CLEAR_AUTHORIZATION
|
||||||
echo -en "\n${idsCL[LightYellow]}Paste the URL provided from the Build Installer: ${idsCL[Default]}"
|
echo -en "\n${idsCL[LightYellow]}Paste the URL provided from the Build Installer: ${idsCL[Default]}"
|
||||||
read -r -s SCURL
|
read -r -s SCURL
|
||||||
echo
|
echo
|
||||||
@@ -104,6 +199,11 @@ INSTALL_RMM() {
|
|||||||
[Nn]) echo;;
|
[Nn]) echo;;
|
||||||
* )
|
* )
|
||||||
echo
|
echo
|
||||||
|
if ! TAPM_AUTHORIZE "install-rmm" "" "RMM installation"; then
|
||||||
|
FINISH_ACTION
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
TAPM_CLEAR_AUTHORIZATION
|
||||||
|
|
||||||
echo -en "\n${idsCL[LightYellow]}Paste the Linux Server URL provided from the Download Agent screen: ${idsCL[Default]}"
|
echo -en "\n${idsCL[LightYellow]}Paste the Linux Server URL provided from the Download Agent screen: ${idsCL[Default]}"
|
||||||
read -r -s RMMURL
|
read -r -s RMMURL
|
||||||
@@ -131,81 +231,29 @@ INSTALL_RMM() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
INSTALL_S1() {
|
INSTALL_S1() {
|
||||||
local deploycode exchange_response host_fingerprint
|
if ! TAPM_AUTHORIZE "" "$S1_BROKER_PACKAGE" "SentinelOne installation"; then
|
||||||
local -a s1_access
|
|
||||||
|
|
||||||
echo
|
|
||||||
if ! command -v python3 >/dev/null 2>&1; then
|
|
||||||
echo -e "${idsCL[LightRed]}Python 3 is required to request the protected installer.${idsCL[Default]}"
|
|
||||||
FINISH_ACTION
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
echo -en "${idsCL[LightYellow]}Paste the TAPM deployment code: ${idsCL[Default]}"
|
|
||||||
read -r -s deploycode
|
|
||||||
echo
|
|
||||||
deploycode="${deploycode^^}"
|
|
||||||
if [[ ! "$deploycode" =~ ^TAPM-[0-9A-HJKMNP-TV-Z]{5}-[0-9A-HJKMNP-TV-Z]{5}$ ]]; then
|
|
||||||
unset deploycode
|
|
||||||
echo -e "${idsCL[LightRed]}The TAPM deployment code is not valid.${idsCL[Default]}"
|
|
||||||
FINISH_ACTION
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
host_fingerprint="$(sha256sum /etc/machine-id | cut -d' ' -f1)"
|
|
||||||
exchange_response="$(
|
|
||||||
TAPM_CODE="$deploycode" TAPM_FINGERPRINT="$host_fingerprint" TAPM_HOSTNAME="$(hostname)" \
|
|
||||||
python3 -c 'import json, os, sys; json.dump({"code": os.environ["TAPM_CODE"], "host_fingerprint": os.environ["TAPM_FINGERPRINT"], "hostname": os.environ["TAPM_HOSTNAME"]}, sys.stdout)' |
|
|
||||||
curl --fail --silent --show-error \
|
|
||||||
--header 'Content-Type: application/json' \
|
|
||||||
--data-binary @- "${S1_BROKER_URL}/api/v1/exchange"
|
|
||||||
)" || {
|
|
||||||
unset deploycode host_fingerprint exchange_response
|
|
||||||
echo -e "${idsCL[LightRed]}The protected SentinelOne installer could not be authorized.${idsCL[Default]}"
|
|
||||||
FINISH_ACTION
|
|
||||||
return
|
|
||||||
}
|
|
||||||
unset deploycode host_fingerprint
|
|
||||||
|
|
||||||
mapfile -t s1_access < <(
|
|
||||||
printf '%s' "$exchange_response" |
|
|
||||||
S1_SLUG="$S1_BROKER_PACKAGE" python3 -c '
|
|
||||||
import json, os, sys
|
|
||||||
data = json.load(sys.stdin)
|
|
||||||
package = next((item for item in data.get("packages", []) if item.get("slug") == os.environ["S1_SLUG"]), None)
|
|
||||||
if not package:
|
|
||||||
raise SystemExit(1)
|
|
||||||
print(data.get("session_token", ""))
|
|
||||||
print(package.get("download_url", ""))
|
|
||||||
print(package.get("sha256", ""))
|
|
||||||
'
|
|
||||||
) || true
|
|
||||||
unset exchange_response
|
|
||||||
if [[ ${#s1_access[@]} -ne 3 || -z "${s1_access[0]}" ||
|
|
||||||
! "${s1_access[2]}" =~ ^[0-9a-fA-F]{64}$ ]]; then
|
|
||||||
unset s1_access
|
|
||||||
echo -e "${idsCL[LightRed]}SentinelOne is not included in this deployment authorization.${idsCL[Default]}"
|
|
||||||
FINISH_ACTION
|
FINISH_ACTION
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -f "/tmp/${S1_PACKAGE}"
|
rm -f "/tmp/${S1_PACKAGE}"
|
||||||
if ! printf 'header = "Authorization: Bearer %s"\n' "${s1_access[0]}" |
|
if ! printf 'header = "Authorization: Bearer %s"\n' "$TAPM_SESSION_TOKEN" |
|
||||||
curl --fail --location --show-error --config - \
|
curl --fail --location --show-error --config - \
|
||||||
--output "/tmp/${S1_PACKAGE}" "${s1_access[1]}"; then
|
--output "/tmp/${S1_PACKAGE}" "$TAPM_PACKAGE_URL"; then
|
||||||
unset s1_access
|
TAPM_CLEAR_AUTHORIZATION
|
||||||
rm -f "/tmp/${S1_PACKAGE}"
|
rm -f "/tmp/${S1_PACKAGE}"
|
||||||
echo -e "${idsCL[LightRed]}The SentinelOne installer download failed.${idsCL[Default]}"
|
echo -e "${idsCL[LightRed]}The SentinelOne installer download failed.${idsCL[Default]}"
|
||||||
FINISH_ACTION
|
FINISH_ACTION
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
if [[ "$(sha256sum "/tmp/${S1_PACKAGE}" | cut -d' ' -f1)" != "${s1_access[2],,}" ]]; then
|
if [[ "$(sha256sum "/tmp/${S1_PACKAGE}" | cut -d' ' -f1)" != "$TAPM_PACKAGE_SHA256" ]]; then
|
||||||
unset s1_access
|
TAPM_CLEAR_AUTHORIZATION
|
||||||
rm -f "/tmp/${S1_PACKAGE}"
|
rm -f "/tmp/${S1_PACKAGE}"
|
||||||
echo -e "${idsCL[LightRed]}The SentinelOne installer checksum did not match. The file was removed.${idsCL[Default]}"
|
echo -e "${idsCL[LightRed]}The SentinelOne installer checksum did not match. The file was removed.${idsCL[Default]}"
|
||||||
FINISH_ACTION
|
FINISH_ACTION
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
unset s1_access
|
TAPM_CLEAR_AUTHORIZATION
|
||||||
|
|
||||||
echo -en "${idsCL[LightYellow]}Paste the customers SentinelOne Site Token: ${idsCL[Default]}"
|
echo -en "${idsCL[LightYellow]}Paste the customers SentinelOne Site Token: ${idsCL[Default]}"
|
||||||
read -r -s s1token
|
read -r -s s1token
|
||||||
@@ -773,7 +821,7 @@ MONITORING_MENU() {
|
|||||||
|
|
||||||
dpkg-query -W -f='${Status}' sentinelagent 2>/dev/null | grep -q "install ok installed" &&
|
dpkg-query -W -f='${Status}' sentinelagent 2>/dev/null | grep -q "install ok installed" &&
|
||||||
labels+=("SentinelOne agent (installed)") ||
|
labels+=("SentinelOne agent (installed)") ||
|
||||||
labels+=("Install SentinelOne agent v${S1_VERSION//_/.}")
|
labels+=("Install SentinelOne agent")
|
||||||
|
|
||||||
systemctl is-active --quiet 'connectwise*' &&
|
systemctl is-active --quiet 'connectwise*' &&
|
||||||
labels+=("ScreenConnect agent (installed)") ||
|
labels+=("ScreenConnect agent (installed)") ||
|
||||||
|
|||||||
Reference in New Issue
Block a user