Execute confirmed timezone provisioning safely #6
7 changed files with 687 additions and 2 deletions
8
.github/workflows/linux-control-agent.yml
vendored
8
.github/workflows/linux-control-agent.yml
vendored
|
|
@ -37,6 +37,14 @@ jobs:
|
||||||
bash -n tests/acceptance/three-server-mesh.sh
|
bash -n tests/acceptance/three-server-mesh.sh
|
||||||
shellcheck --severity=error tests/acceptance/three-server-mesh.sh
|
shellcheck --severity=error tests/acceptance/three-server-mesh.sh
|
||||||
|
|
||||||
|
- name: Verify standalone bootstrap
|
||||||
|
run: |
|
||||||
|
bash -n deploy/ochenstarik-server-monitor-manager.sh
|
||||||
|
bash -n deploy/ochenstarik-smm-policy-apply
|
||||||
|
shellcheck --severity=error deploy/ochenstarik-server-monitor-manager.sh
|
||||||
|
shellcheck --severity=error deploy/ochenstarik-smm-policy-apply
|
||||||
|
bash tests/bootstrap/test-bootstrap-contract.sh
|
||||||
|
|
||||||
- name: Publish agent amd64
|
- name: Publish agent amd64
|
||||||
run: dotnet publish src/ServerMonitorManager.Agent/ServerMonitorManager.Agent.csproj --configuration Release --runtime linux-x64 --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
|
run: dotnet publish src/ServerMonitorManager.Agent/ServerMonitorManager.Agent.csproj --configuration Release --runtime linux-x64 --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
|
||||||
|
|
||||||
|
|
|
||||||
55
.github/workflows/linux-release.yml
vendored
55
.github/workflows/linux-release.yml
vendored
|
|
@ -10,6 +10,54 @@ permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
bootstrap:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Validate bootstrap
|
||||||
|
run: |
|
||||||
|
bash -n deploy/ochenstarik-server-monitor-manager.sh
|
||||||
|
bash -n deploy/ochenstarik-smm-policy-apply
|
||||||
|
shellcheck --severity=error deploy/ochenstarik-server-monitor-manager.sh
|
||||||
|
shellcheck --severity=error deploy/ochenstarik-smm-policy-apply
|
||||||
|
bash tests/bootstrap/test-bootstrap-contract.sh
|
||||||
|
|
||||||
|
- name: Package bootstrap
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -Eeuo pipefail
|
||||||
|
install -m 0755 deploy/ochenstarik-server-monitor-manager.sh ochenstarik-server-monitor-manager.sh
|
||||||
|
sha256sum ochenstarik-server-monitor-manager.sh > ochenstarik-server-monitor-manager.sh.sha256
|
||||||
|
bootstrap_sha="$(sha256sum ochenstarik-server-monitor-manager.sh | awk '{print $1}')"
|
||||||
|
jq -n \
|
||||||
|
--arg schema "smm-bootstrap-manifest/v1" \
|
||||||
|
--arg version "${GITHUB_REF_NAME}" \
|
||||||
|
--arg bootstrap "ochenstarik-server-monitor-manager.sh" \
|
||||||
|
--arg bootstrap_sha256 "$bootstrap_sha" \
|
||||||
|
'{schema: $schema, version: $version, bootstrap: $bootstrap, bootstrap_sha256: $bootstrap_sha256, supported_runtimes: ["linux-x64", "linux-arm64"]}' \
|
||||||
|
> server-monitor-manager-bootstrap-manifest.json
|
||||||
|
|
||||||
|
- name: Upload bootstrap artifact
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: server-monitor-manager-bootstrap
|
||||||
|
path: |
|
||||||
|
ochenstarik-server-monitor-manager.sh
|
||||||
|
ochenstarik-server-monitor-manager.sh.sha256
|
||||||
|
server-monitor-manager-bootstrap-manifest.json
|
||||||
|
|
||||||
|
- name: Attach bootstrap to GitHub Release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
prerelease: ${{ contains(github.ref_name, '-') }}
|
||||||
|
files: |
|
||||||
|
ochenstarik-server-monitor-manager.sh
|
||||||
|
ochenstarik-server-monitor-manager.sh.sha256
|
||||||
|
server-monitor-manager-bootstrap-manifest.json
|
||||||
|
|
||||||
publish:
|
publish:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
|
|
@ -34,8 +82,13 @@ jobs:
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
install -d out/deploy out/bootstrap
|
||||||
|
install -m 0644 deploy/ochenstarik-smm-control.service out/deploy/
|
||||||
|
install -m 0644 deploy/ochenstarik-smm-agent.service out/deploy/
|
||||||
|
install -m 0755 deploy/ochenstarik-smm-policy-apply out/deploy/
|
||||||
|
install -m 0755 deploy/ochenstarik-server-monitor-manager.sh out/bootstrap/
|
||||||
archive="server-monitor-manager-${{ matrix.runtime }}.tar.gz"
|
archive="server-monitor-manager-${{ matrix.runtime }}.tar.gz"
|
||||||
tar -C out -czf "$archive" agent control
|
tar -C out -czf "$archive" agent control deploy bootstrap
|
||||||
sha256sum "$archive" > "$archive.sha256"
|
sha256sum "$archive" > "$archive.sha256"
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ The control plane and data plane are separated:
|
||||||
|
|
||||||
See [architecture](docs/architecture.md), [security model](docs/security-model.md), [roadmap](docs/roadmap.md), [Linux bootstrap contract](docs/installer-contract.md), and the [Provisioning and Xray specification](docs/provisioning-vpn-requirements.md).
|
See [architecture](docs/architecture.md), [security model](docs/security-model.md), [roadmap](docs/roadmap.md), [Linux bootstrap contract](docs/installer-contract.md), and the [Provisioning and Xray specification](docs/provisioning-vpn-requirements.md).
|
||||||
|
|
||||||
Operational procedures are documented in [Control backup and recovery](docs/control-backup.md) and the [three-server acceptance test](docs/three-server-acceptance.md).
|
Operational procedures are documented in [Linux bootstrap](docs/linux-bootstrap.md), [Control backup and recovery](docs/control-backup.md), and the [three-server acceptance test](docs/three-server-acceptance.md).
|
||||||
|
|
||||||
## Repository layout
|
## Repository layout
|
||||||
|
|
||||||
|
|
|
||||||
486
deploy/ochenstarik-server-monitor-manager.sh
Executable file
486
deploy/ochenstarik-server-monitor-manager.sh
Executable file
|
|
@ -0,0 +1,486 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
readonly PROGRAM="ochenstarik-server-monitor-manager"
|
||||||
|
readonly VERSION="0.2.0-dev"
|
||||||
|
readonly ETC_DIR="/etc/ochenstarik-server-monitor-manager"
|
||||||
|
readonly LIB_DIR="/usr/local/lib/ochenstarik-server-monitor-manager"
|
||||||
|
readonly STATE_DIR="/var/lib/ochenstarik-server-monitor-manager"
|
||||||
|
readonly BACKUP_DIR="${STATE_DIR}/bootstrap-backups"
|
||||||
|
readonly CONTROL_USER="ochenstarik-smm-control"
|
||||||
|
readonly AGENT_USER="ochenstarik-smm-agent"
|
||||||
|
readonly CONTROL_UNIT="ochenstarik-smm-control.service"
|
||||||
|
readonly AGENT_UNIT="ochenstarik-smm-agent.service"
|
||||||
|
readonly POLICY_HELPER="/usr/local/libexec/ochenstarik-smm-policy-apply"
|
||||||
|
readonly SUDOERS_FILE="/etc/sudoers.d/ochenstarik-smm-control"
|
||||||
|
|
||||||
|
TEMP_DIR=""
|
||||||
|
|
||||||
|
log() { printf '%s\n' "[$PROGRAM] $*"; }
|
||||||
|
fail() { printf '%s\n' "[$PROGRAM] ERROR: $*" >&2; exit 1; }
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if [[ -n "$TEMP_DIR" && -d "$TEMP_DIR" ]]; then
|
||||||
|
rm -rf -- "$TEMP_DIR"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Server Monitor Manager Linux bootstrap
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
ochenstarik-server-monitor-manager.sh preflight
|
||||||
|
ochenstarik-server-monitor-manager.sh install-control ARCHIVE PUBLIC_HOST [HTTPS_PORT]
|
||||||
|
ochenstarik-server-monitor-manager.sh install-agent ARCHIVE NODE_ID CONTROL_URL CA_CERT
|
||||||
|
ochenstarik-server-monitor-manager.sh update-control ARCHIVE
|
||||||
|
ochenstarik-server-monitor-manager.sh update-agent ARCHIVE
|
||||||
|
ochenstarik-server-monitor-manager.sh rollback control|agent [BACKUP_ID]
|
||||||
|
ochenstarik-server-monitor-manager.sh node-token NODE_ID
|
||||||
|
ochenstarik-server-monitor-manager.sh control-ca-fingerprint
|
||||||
|
ochenstarik-server-monitor-manager.sh status
|
||||||
|
ochenstarik-server-monitor-manager.sh uninstall-agent [--purge]
|
||||||
|
ochenstarik-server-monitor-manager.sh uninstall-control --confirm-destroy-control
|
||||||
|
ochenstarik-server-monitor-manager.sh version
|
||||||
|
|
||||||
|
ARCHIVE must have a matching ARCHIVE.sha256 file. Agent enrollment reads the
|
||||||
|
one-time token from SMM_ENROLL_TOKEN or from a hidden local prompt; it is never
|
||||||
|
written to agent.env.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
require_root() {
|
||||||
|
[[ ${EUID:-$(id -u)} -eq 0 ]] || fail "This action must run as root (use sudo)."
|
||||||
|
}
|
||||||
|
|
||||||
|
require_command() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || fail "Required command is missing: $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_platform() {
|
||||||
|
[[ -r /etc/os-release ]] || fail "/etc/os-release is missing."
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. /etc/os-release
|
||||||
|
case "${ID:-}" in
|
||||||
|
ubuntu)
|
||||||
|
case "${VERSION_ID:-}" in 22.04|24.04) ;; *) fail "Unsupported Ubuntu version: ${VERSION_ID:-unknown}" ;; esac
|
||||||
|
;;
|
||||||
|
debian)
|
||||||
|
case "${VERSION_ID:-}" in 12|13) ;; *) fail "Unsupported Debian version: ${VERSION_ID:-unknown}" ;; esac
|
||||||
|
;;
|
||||||
|
*) fail "Unsupported distribution: ${ID:-unknown}" ;;
|
||||||
|
esac
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64|aarch64|arm64) ;;
|
||||||
|
*) fail "Unsupported architecture: $(uname -m)" ;;
|
||||||
|
esac
|
||||||
|
[[ "$(ps -p 1 -o comm=)" == "systemd" ]] || fail "systemd must be PID 1."
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_node_id() {
|
||||||
|
[[ "$1" =~ ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ ]] \
|
||||||
|
|| fail "Node id must contain 1-63 lowercase letters, digits, or hyphens."
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_port() {
|
||||||
|
[[ "$1" =~ ^[0-9]+$ ]] && (( 10#$1 >= 1 && 10#$1 <= 65535 )) \
|
||||||
|
|| fail "Port must be in range 1-65535."
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_control_url() {
|
||||||
|
[[ "$1" =~ ^https://[A-Za-z0-9._:\[\]-]+(:[0-9]{1,5})?/?$ ]] \
|
||||||
|
|| fail "Control URL must be an https URL without a path or credentials."
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_archive() {
|
||||||
|
local archive="$1" checksum_file expected actual entry
|
||||||
|
[[ -f "$archive" ]] || fail "Archive not found: $archive"
|
||||||
|
checksum_file="${archive}.sha256"
|
||||||
|
[[ -f "$checksum_file" ]] || fail "Checksum file not found: $checksum_file"
|
||||||
|
expected="$(awk 'NR == 1 { print $1 }' "$checksum_file")"
|
||||||
|
[[ "$expected" =~ ^[0-9a-fA-F]{64}$ ]] || fail "Invalid checksum file: $checksum_file"
|
||||||
|
actual="$(sha256sum "$archive" | awk '{ print $1 }')"
|
||||||
|
[[ "${actual,,}" == "${expected,,}" ]] || fail "Archive checksum mismatch."
|
||||||
|
|
||||||
|
while IFS= read -r entry; do
|
||||||
|
[[ -n "$entry" ]] || continue
|
||||||
|
[[ "$entry" != /* && "$entry" != *".."* ]] || fail "Unsafe archive entry: $entry"
|
||||||
|
case "$entry" in
|
||||||
|
agent|agent/*|control|control/*|deploy|deploy/*|bootstrap|bootstrap/*) ;;
|
||||||
|
*) fail "Unexpected archive entry: $entry" ;;
|
||||||
|
esac
|
||||||
|
done < <(tar -tzf "$archive")
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_archive() {
|
||||||
|
local archive="$1"
|
||||||
|
verify_archive "$archive"
|
||||||
|
TEMP_DIR="$(mktemp -d -t smm-bootstrap.XXXXXXXX)"
|
||||||
|
chmod 700 "$TEMP_DIR"
|
||||||
|
tar -xzf "$archive" -C "$TEMP_DIR" --no-same-owner --no-same-permissions
|
||||||
|
[[ -f "$TEMP_DIR/deploy/$CONTROL_UNIT" ]] || fail "Control systemd unit is missing from archive."
|
||||||
|
[[ -f "$TEMP_DIR/deploy/$AGENT_UNIT" ]] || fail "Agent systemd unit is missing from archive."
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_system_user() {
|
||||||
|
local user="$1"
|
||||||
|
if ! getent group "$user" >/dev/null; then
|
||||||
|
groupadd --system "$user"
|
||||||
|
fi
|
||||||
|
if ! id "$user" >/dev/null 2>&1; then
|
||||||
|
useradd --system --gid "$user" --home-dir /nonexistent --no-create-home --shell /usr/sbin/nologin "$user"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_tree_atomic() {
|
||||||
|
local source="$1" destination="$2" owner="$3" staging
|
||||||
|
[[ -d "$source" ]] || fail "Release payload is missing: $source"
|
||||||
|
staging="${destination}.new.$$"
|
||||||
|
rm -rf -- "$staging"
|
||||||
|
install -d -m 0755 "$staging"
|
||||||
|
cp -a -- "$source/." "$staging/"
|
||||||
|
chown -R "$owner" "$staging"
|
||||||
|
find "$staging" -type d -exec chmod 0755 {} +
|
||||||
|
find "$staging" -type f -exec chmod 0644 {} +
|
||||||
|
find "$staging" -type f -name 'ochenstarik-smm-*' -exec chmod 0755 {} +
|
||||||
|
rm -rf -- "$destination"
|
||||||
|
mv -- "$staging" "$destination"
|
||||||
|
}
|
||||||
|
|
||||||
|
create_backup() {
|
||||||
|
local role="$1" backup_id archive list=()
|
||||||
|
backup_id="$(date -u +%Y%m%dT%H%M%SZ)-${role}-$RANDOM"
|
||||||
|
install -d -m 0700 "$BACKUP_DIR"
|
||||||
|
archive="$BACKUP_DIR/${backup_id}.tar.gz"
|
||||||
|
case "$role" in
|
||||||
|
control)
|
||||||
|
list=(
|
||||||
|
"usr/local/lib/ochenstarik-server-monitor-manager/control"
|
||||||
|
"etc/ochenstarik-server-monitor-manager/control.env"
|
||||||
|
"etc/ochenstarik-server-monitor-manager/control-ca.pfx"
|
||||||
|
"etc/ochenstarik-server-monitor-manager/control-server.pfx"
|
||||||
|
"etc/systemd/system/$CONTROL_UNIT"
|
||||||
|
"usr/local/libexec/ochenstarik-smm-policy-apply"
|
||||||
|
"etc/sudoers.d/ochenstarik-smm-control"
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
agent)
|
||||||
|
list=(
|
||||||
|
"usr/local/lib/ochenstarik-server-monitor-manager/agent"
|
||||||
|
"etc/ochenstarik-server-monitor-manager/agent.env"
|
||||||
|
"etc/ochenstarik-server-monitor-manager/control-ca.crt"
|
||||||
|
"etc/systemd/system/$AGENT_UNIT"
|
||||||
|
)
|
||||||
|
;;
|
||||||
|
*) fail "Unknown backup role: $role" ;;
|
||||||
|
esac
|
||||||
|
local existing=() item
|
||||||
|
for item in "${list[@]}"; do
|
||||||
|
[[ -e "/$item" ]] && existing+=("$item")
|
||||||
|
done
|
||||||
|
if (( ${#existing[@]} == 0 )); then
|
||||||
|
printf '%s\n' "empty" >"$BACKUP_DIR/${backup_id}.empty"
|
||||||
|
else
|
||||||
|
tar -C / -czf "$archive" -- "${existing[@]}"
|
||||||
|
chmod 0600 "$archive"
|
||||||
|
fi
|
||||||
|
printf '%s\n' "$backup_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_unit() {
|
||||||
|
local source="$1" unit="$2"
|
||||||
|
install -m 0644 "$source" "/etc/systemd/system/$unit"
|
||||||
|
systemctl daemon-reload
|
||||||
|
}
|
||||||
|
|
||||||
|
create_control_certificates() {
|
||||||
|
local public_host="$1" ca_key ca_cert serial_file server_key server_csr ext_file san
|
||||||
|
ca_key="$TEMP_DIR/control-ca.key"
|
||||||
|
ca_cert="$TEMP_DIR/control-ca.crt"
|
||||||
|
serial_file="$TEMP_DIR/control-ca.srl"
|
||||||
|
server_key="$TEMP_DIR/control-server.key"
|
||||||
|
server_csr="$TEMP_DIR/control-server.csr"
|
||||||
|
ext_file="$TEMP_DIR/control-server.ext"
|
||||||
|
if [[ "$public_host" == *:* || "$public_host" =~ ^[0-9]+(\.[0-9]+){3}$ ]]; then
|
||||||
|
san="IP:$public_host"
|
||||||
|
else
|
||||||
|
[[ "$public_host" =~ ^[A-Za-z0-9]([A-Za-z0-9.-]{0,251}[A-Za-z0-9])?$ ]] \
|
||||||
|
|| fail "Invalid public host name."
|
||||||
|
san="DNS:$public_host"
|
||||||
|
fi
|
||||||
|
|
||||||
|
openssl ecparam -name prime256v1 -genkey -noout -out "$ca_key"
|
||||||
|
openssl req -x509 -new -sha256 -days 3650 -key "$ca_key" -out "$ca_cert" \
|
||||||
|
-subj "/CN=Server Monitor Manager Control CA" \
|
||||||
|
-addext "basicConstraints=critical,CA:TRUE" \
|
||||||
|
-addext "keyUsage=critical,keyCertSign,cRLSign"
|
||||||
|
openssl ecparam -name prime256v1 -genkey -noout -out "$server_key"
|
||||||
|
openssl req -new -sha256 -key "$server_key" -out "$server_csr" \
|
||||||
|
-subj "/CN=$public_host"
|
||||||
|
printf '%s\n' \
|
||||||
|
"basicConstraints=critical,CA:FALSE" \
|
||||||
|
"keyUsage=critical,digitalSignature,keyEncipherment" \
|
||||||
|
"extendedKeyUsage=serverAuth" \
|
||||||
|
"subjectAltName=$san" >"$ext_file"
|
||||||
|
openssl x509 -req -sha256 -days 825 -in "$server_csr" -CA "$ca_cert" -CAkey "$ca_key" \
|
||||||
|
-CAserial "$serial_file" -CAcreateserial -out "$TEMP_DIR/control-server.crt" -extfile "$ext_file"
|
||||||
|
openssl pkcs12 -export -out "$ETC_DIR/control-ca.pfx" -inkey "$ca_key" -in "$ca_cert" -passout pass:
|
||||||
|
openssl pkcs12 -export -out "$ETC_DIR/control-server.pfx" -inkey "$server_key" \
|
||||||
|
-in "$TEMP_DIR/control-server.crt" -certfile "$ca_cert" -passout pass:
|
||||||
|
install -m 0644 "$ca_cert" "$ETC_DIR/control-ca.crt"
|
||||||
|
chown root:"$CONTROL_USER" "$ETC_DIR/control-ca.pfx" "$ETC_DIR/control-server.pfx"
|
||||||
|
chmod 0640 "$ETC_DIR/control-ca.pfx" "$ETC_DIR/control-server.pfx"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_control() {
|
||||||
|
local archive="$1" public_host="$2" port="${3:-7443}" backup_id
|
||||||
|
require_root
|
||||||
|
validate_platform
|
||||||
|
validate_port "$port"
|
||||||
|
require_command openssl
|
||||||
|
require_command sha256sum
|
||||||
|
require_command tar
|
||||||
|
require_command systemctl
|
||||||
|
require_command sudo
|
||||||
|
require_command visudo
|
||||||
|
extract_archive "$archive"
|
||||||
|
[[ -x "$TEMP_DIR/control/ochenstarik-smm-control" ]] || fail "Control binary is missing."
|
||||||
|
backup_id="$(create_backup control)"
|
||||||
|
ensure_system_user "$CONTROL_USER"
|
||||||
|
install -d -m 0750 -o root -g "$CONTROL_USER" "$ETC_DIR"
|
||||||
|
install -d -m 0750 -o "$CONTROL_USER" -g "$CONTROL_USER" "$STATE_DIR" "$STATE_DIR/backups"
|
||||||
|
install_tree_atomic "$TEMP_DIR/control" "$LIB_DIR/control" "root:root"
|
||||||
|
if [[ ! -f "$ETC_DIR/control-ca.pfx" || ! -f "$ETC_DIR/control-server.pfx" ]]; then
|
||||||
|
create_control_certificates "$public_host"
|
||||||
|
fi
|
||||||
|
cat >"$ETC_DIR/control.env" <<EOF
|
||||||
|
ASPNETCORE_URLS=https://0.0.0.0:$port
|
||||||
|
ASPNETCORE_Kestrel__Certificates__Default__Path=$ETC_DIR/control-server.pfx
|
||||||
|
Control__DatabasePath=$STATE_DIR/control.db
|
||||||
|
Control__CertificateAuthorityPath=$ETC_DIR/control-ca.pfx
|
||||||
|
Control__BackupDirectory=$STATE_DIR/backups
|
||||||
|
Control__HubHelperPath=$POLICY_HELPER
|
||||||
|
Control__PrivilegeEscalationPath=/usr/bin/sudo
|
||||||
|
EOF
|
||||||
|
chown root:"$CONTROL_USER" "$ETC_DIR/control.env"
|
||||||
|
chmod 0640 "$ETC_DIR/control.env"
|
||||||
|
install -m 0755 "$TEMP_DIR/deploy/ochenstarik-smm-policy-apply" "$POLICY_HELPER"
|
||||||
|
printf '%s\n' "$CONTROL_USER ALL=(root) NOPASSWD: $POLICY_HELPER *" >"$SUDOERS_FILE"
|
||||||
|
chmod 0440 "$SUDOERS_FILE"
|
||||||
|
visudo -cf "$SUDOERS_FILE" >/dev/null
|
||||||
|
install_unit "$TEMP_DIR/deploy/$CONTROL_UNIT" "$CONTROL_UNIT"
|
||||||
|
systemctl enable --now "$CONTROL_UNIT"
|
||||||
|
systemctl is-active --quiet "$CONTROL_UNIT" || {
|
||||||
|
systemctl status --no-pager "$CONTROL_UNIT" >&2 || true
|
||||||
|
fail "Control service failed; backup is $backup_id"
|
||||||
|
}
|
||||||
|
log "Control installed. Backup: $backup_id"
|
||||||
|
log "CA fingerprint: $(openssl x509 -in "$ETC_DIR/control-ca.crt" -noout -fingerprint -sha256 | cut -d= -f2)"
|
||||||
|
}
|
||||||
|
|
||||||
|
read_enrollment_token() {
|
||||||
|
if [[ -n "${SMM_ENROLL_TOKEN:-}" ]]; then
|
||||||
|
ENROLL_TOKEN="$SMM_ENROLL_TOKEN"
|
||||||
|
unset SMM_ENROLL_TOKEN
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
[[ -t 0 ]] || fail "Set SMM_ENROLL_TOKEN or run from an interactive local terminal."
|
||||||
|
read -r -s -p "One-time enrollment token: " ENROLL_TOKEN
|
||||||
|
printf '\n'
|
||||||
|
[[ -n "$ENROLL_TOKEN" ]] || fail "Enrollment token is empty."
|
||||||
|
}
|
||||||
|
|
||||||
|
install_agent() {
|
||||||
|
local archive="$1" node_id="$2" control_url="$3" ca_cert="$4" backup_id
|
||||||
|
require_root
|
||||||
|
validate_platform
|
||||||
|
validate_node_id "$node_id"
|
||||||
|
validate_control_url "$control_url"
|
||||||
|
[[ -f "$ca_cert" ]] || fail "Control CA certificate not found: $ca_cert"
|
||||||
|
require_command sha256sum
|
||||||
|
require_command tar
|
||||||
|
require_command systemctl
|
||||||
|
require_command runuser
|
||||||
|
require_command openssl
|
||||||
|
openssl x509 -in "$ca_cert" -noout >/dev/null 2>&1 || fail "Invalid Control CA certificate."
|
||||||
|
extract_archive "$archive"
|
||||||
|
[[ -x "$TEMP_DIR/agent/ochenstarik-smm-agent" ]] || fail "Agent binary is missing."
|
||||||
|
backup_id="$(create_backup agent)"
|
||||||
|
ensure_system_user "$AGENT_USER"
|
||||||
|
install -d -m 0750 -o root -g "$AGENT_USER" "$ETC_DIR"
|
||||||
|
install -d -m 0700 -o "$AGENT_USER" -g "$AGENT_USER" "$STATE_DIR/agent"
|
||||||
|
install_tree_atomic "$TEMP_DIR/agent" "$LIB_DIR/agent" "root:root"
|
||||||
|
if [[ "$(realpath "$ca_cert")" != "$(realpath -m "$ETC_DIR/control-ca.crt")" ]]; then
|
||||||
|
install -m 0600 -o "$AGENT_USER" -g "$AGENT_USER" "$ca_cert" "$ETC_DIR/control-ca.crt"
|
||||||
|
else
|
||||||
|
chown "$AGENT_USER:$AGENT_USER" "$ETC_DIR/control-ca.crt"
|
||||||
|
chmod 0600 "$ETC_DIR/control-ca.crt"
|
||||||
|
fi
|
||||||
|
cat >"$ETC_DIR/agent.env" <<EOF
|
||||||
|
SMM_NodeId=$node_id
|
||||||
|
SMM_ControlUrl=${control_url%/}
|
||||||
|
SMM_StateDirectory=$STATE_DIR/agent
|
||||||
|
SMM_CertificateAuthorityPath=$ETC_DIR/control-ca.crt
|
||||||
|
EOF
|
||||||
|
chown root:"$AGENT_USER" "$ETC_DIR/agent.env"
|
||||||
|
chmod 0640 "$ETC_DIR/agent.env"
|
||||||
|
read_enrollment_token
|
||||||
|
runuser -u "$AGENT_USER" -- env \
|
||||||
|
"SMM_NodeId=$node_id" \
|
||||||
|
"SMM_ControlUrl=${control_url%/}" \
|
||||||
|
"SMM_StateDirectory=$STATE_DIR/agent" \
|
||||||
|
"SMM_CertificateAuthorityPath=$ETC_DIR/control-ca.crt" \
|
||||||
|
"SMM_EnrollToken=$ENROLL_TOKEN" \
|
||||||
|
"$LIB_DIR/agent/ochenstarik-smm-agent"
|
||||||
|
ENROLL_TOKEN=""
|
||||||
|
chown root:"$AGENT_USER" "$ETC_DIR/control-ca.crt"
|
||||||
|
chmod 0640 "$ETC_DIR/control-ca.crt"
|
||||||
|
install_unit "$TEMP_DIR/deploy/$AGENT_UNIT" "$AGENT_UNIT"
|
||||||
|
systemctl enable --now "$AGENT_UNIT"
|
||||||
|
systemctl is-active --quiet "$AGENT_UNIT" || {
|
||||||
|
systemctl status --no-pager "$AGENT_UNIT" >&2 || true
|
||||||
|
fail "Agent service failed; backup is $backup_id"
|
||||||
|
}
|
||||||
|
log "Agent $node_id installed and enrolled. Backup: $backup_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
update_role() {
|
||||||
|
local role="$1" archive="$2" binary unit user backup_id
|
||||||
|
require_root
|
||||||
|
validate_platform
|
||||||
|
extract_archive "$archive"
|
||||||
|
case "$role" in
|
||||||
|
control) binary="ochenstarik-smm-control"; unit="$CONTROL_UNIT"; user="root:root" ;;
|
||||||
|
agent) binary="ochenstarik-smm-agent"; unit="$AGENT_UNIT"; user="root:root" ;;
|
||||||
|
*) fail "Unknown role: $role" ;;
|
||||||
|
esac
|
||||||
|
[[ -x "$TEMP_DIR/$role/$binary" ]] || fail "$role binary is missing."
|
||||||
|
systemctl stop "$unit"
|
||||||
|
backup_id="$(create_backup "$role")"
|
||||||
|
install_tree_atomic "$TEMP_DIR/$role" "$LIB_DIR/$role" "$user"
|
||||||
|
systemctl start "$unit"
|
||||||
|
if ! systemctl is-active --quiet "$unit"; then
|
||||||
|
log "Update failed; restoring backup $backup_id"
|
||||||
|
restore_backup "$role" "$backup_id"
|
||||||
|
fail "$role update was rolled back."
|
||||||
|
fi
|
||||||
|
log "$role updated. Backup: $backup_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
latest_backup_id() {
|
||||||
|
local role="$1" path
|
||||||
|
path="$(find "$BACKUP_DIR" -maxdepth 1 -type f \( -name "*-${role}-*.tar.gz" -o -name "*-${role}-*.empty" \) -printf '%f\n' 2>/dev/null | sort | tail -n1)"
|
||||||
|
[[ -n "$path" ]] || fail "No backup found for $role."
|
||||||
|
printf '%s\n' "${path%.tar.gz}" | sed 's/\.empty$//'
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_backup() {
|
||||||
|
local role="$1" backup_id="$2" archive="$BACKUP_DIR/${backup_id}.tar.gz" unit
|
||||||
|
case "$role" in control) unit="$CONTROL_UNIT" ;; agent) unit="$AGENT_UNIT" ;; *) fail "Unknown role: $role" ;; esac
|
||||||
|
[[ -f "$archive" ]] || fail "Backup archive not found: $backup_id"
|
||||||
|
systemctl stop "$unit" || true
|
||||||
|
tar -C / -xzf "$archive"
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl start "$unit"
|
||||||
|
systemctl is-active --quiet "$unit" || fail "Rollback restored files but service is not active."
|
||||||
|
log "$role restored from $backup_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
rollback_role() {
|
||||||
|
local role="$1" backup_id="${2:-}"
|
||||||
|
require_root
|
||||||
|
[[ -n "$backup_id" ]] || backup_id="$(latest_backup_id "$role")"
|
||||||
|
restore_backup "$role" "$backup_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_status() {
|
||||||
|
local unit
|
||||||
|
for unit in "$CONTROL_UNIT" "$AGENT_UNIT"; do
|
||||||
|
if systemctl list-unit-files "$unit" --no-legend 2>/dev/null | grep -q "^$unit"; then
|
||||||
|
printf '%s: %s\n' "$unit" "$(systemctl is-active "$unit" 2>/dev/null || true)"
|
||||||
|
else
|
||||||
|
printf '%s: not-installed\n' "$unit"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ -f "$ETC_DIR/control-ca.crt" ]] && command -v openssl >/dev/null; then
|
||||||
|
printf 'control-ca: %s\n' "$(openssl x509 -in "$ETC_DIR/control-ca.crt" -noout -fingerprint -sha256 | cut -d= -f2)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_control_cli() {
|
||||||
|
local command_name="$1" identifier="$2"
|
||||||
|
require_root
|
||||||
|
validate_node_id "$identifier"
|
||||||
|
[[ -x "$LIB_DIR/control/ochenstarik-smm-control" ]] || fail "Control is not installed."
|
||||||
|
[[ -f "$ETC_DIR/control.env" ]] || fail "Control environment is missing."
|
||||||
|
require_command systemd-run
|
||||||
|
systemd-run --wait --pipe --quiet --collect \
|
||||||
|
--uid="$CONTROL_USER" \
|
||||||
|
--gid="$CONTROL_USER" \
|
||||||
|
-p "EnvironmentFile=$ETC_DIR/control.env" \
|
||||||
|
"$LIB_DIR/control/ochenstarik-smm-control" "$command_name" "$identifier"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_ca_fingerprint() {
|
||||||
|
[[ -f "$ETC_DIR/control-ca.crt" ]] || fail "Control CA certificate is not installed."
|
||||||
|
require_command openssl
|
||||||
|
openssl x509 -in "$ETC_DIR/control-ca.crt" -noout -fingerprint -sha256
|
||||||
|
}
|
||||||
|
|
||||||
|
uninstall_agent() {
|
||||||
|
local purge="${1:-}"
|
||||||
|
require_root
|
||||||
|
systemctl disable --now "$AGENT_UNIT" 2>/dev/null || true
|
||||||
|
rm -f -- "/etc/systemd/system/$AGENT_UNIT" "$ETC_DIR/agent.env"
|
||||||
|
rm -rf -- "$LIB_DIR/agent"
|
||||||
|
[[ "$purge" == "--purge" ]] && rm -rf -- "$STATE_DIR/agent" "$ETC_DIR/control-ca.crt"
|
||||||
|
systemctl daemon-reload
|
||||||
|
log "Agent removed${purge:+ ($purge)}."
|
||||||
|
}
|
||||||
|
|
||||||
|
uninstall_control() {
|
||||||
|
[[ "${1:-}" == "--confirm-destroy-control" ]] || fail "Control removal requires --confirm-destroy-control"
|
||||||
|
require_root
|
||||||
|
systemctl disable --now "$CONTROL_UNIT" 2>/dev/null || true
|
||||||
|
rm -f -- "/etc/systemd/system/$CONTROL_UNIT" "$ETC_DIR/control.env" \
|
||||||
|
"$ETC_DIR/control-ca.pfx" "$ETC_DIR/control-server.pfx" "$ETC_DIR/control-ca.crt" \
|
||||||
|
"$POLICY_HELPER" "$SUDOERS_FILE"
|
||||||
|
rm -rf -- "$LIB_DIR/control" "$STATE_DIR/control.db" "$STATE_DIR/control.db-wal" \
|
||||||
|
"$STATE_DIR/control.db-shm" "$STATE_DIR/backups"
|
||||||
|
systemctl daemon-reload
|
||||||
|
log "Control role and its state were removed."
|
||||||
|
}
|
||||||
|
|
||||||
|
preflight() {
|
||||||
|
validate_platform
|
||||||
|
local command_name
|
||||||
|
for command_name in openssl sha256sum tar systemctl getent useradd groupadd; do
|
||||||
|
require_command "$command_name"
|
||||||
|
done
|
||||||
|
log "Supported platform: $(. /etc/os-release; printf '%s %s' "$ID" "$VERSION_ID"), $(uname -m)"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
local action="${1:-help}"
|
||||||
|
shift || true
|
||||||
|
case "$action" in
|
||||||
|
help|-h|--help) usage ;;
|
||||||
|
version|--version) printf '%s %s\n' "$PROGRAM" "$VERSION" ;;
|
||||||
|
preflight) preflight ;;
|
||||||
|
install-control) [[ $# -ge 2 && $# -le 3 ]] || fail "install-control requires ARCHIVE PUBLIC_HOST [HTTPS_PORT]"; install_control "$@" ;;
|
||||||
|
install-agent) [[ $# -eq 4 ]] || fail "install-agent requires ARCHIVE NODE_ID CONTROL_URL CA_CERT"; install_agent "$@" ;;
|
||||||
|
update-control) [[ $# -eq 1 ]] || fail "update-control requires ARCHIVE"; update_role control "$1" ;;
|
||||||
|
update-agent) [[ $# -eq 1 ]] || fail "update-agent requires ARCHIVE"; update_role agent "$1" ;;
|
||||||
|
rollback) [[ $# -ge 1 && $# -le 2 ]] || fail "rollback requires control|agent [BACKUP_ID]"; rollback_role "$@" ;;
|
||||||
|
node-token) [[ $# -eq 1 ]] || fail "node-token requires NODE_ID"; run_control_cli token-create "$1" ;;
|
||||||
|
control-ca-fingerprint) [[ $# -eq 0 ]] || fail "control-ca-fingerprint takes no arguments"; show_ca_fingerprint ;;
|
||||||
|
status) show_status ;;
|
||||||
|
uninstall-agent) [[ $# -le 1 ]] || fail "uninstall-agent accepts only [--purge]"; uninstall_agent "${1:-}" ;;
|
||||||
|
uninstall-control) [[ $# -eq 1 ]] || fail "uninstall-control requires confirmation"; uninstall_control "$1" ;;
|
||||||
|
*) fail "Unknown action: $action (run with --help)" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
27
deploy/ochenstarik-smm-policy-apply
Executable file
27
deploy/ochenstarik-smm-policy-apply
Executable file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
fail() { printf '%s\n' "policy helper: $*" >&2; exit 78; }
|
||||||
|
|
||||||
|
[[ ${EUID:-$(id -u)} -eq 0 ]] || fail "root is required"
|
||||||
|
action="${1:-}"
|
||||||
|
case "$action" in
|
||||||
|
link-connect)
|
||||||
|
[[ $# -eq 6 ]] || fail "invalid link-connect argument count"
|
||||||
|
;;
|
||||||
|
link-disconnect)
|
||||||
|
[[ $# -eq 5 ]] || fail "invalid link-disconnect argument count"
|
||||||
|
;;
|
||||||
|
*) fail "unsupported action" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
node_pattern='^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$'
|
||||||
|
[[ "$2" =~ $node_pattern && "$3" =~ $node_pattern ]] || fail "invalid node id"
|
||||||
|
[[ "$4" == "tcp" || "$4" == "udp" ]] || fail "invalid protocol"
|
||||||
|
[[ "$5" =~ ^[0-9]+$ ]] && (( 10#$5 >= 1 && 10#$5 <= 65535 )) || fail "invalid port"
|
||||||
|
if [[ "$action" == "link-connect" ]]; then
|
||||||
|
[[ "$6" =~ ^[0-9]+$ ]] && (( 10#$6 >= 1 && 10#$6 <= 10080 )) || fail "invalid TTL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fail "WireGuard/nftables data-plane configuration is not installed yet"
|
||||||
83
docs/linux-bootstrap.md
Normal file
83
docs/linux-bootstrap.md
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
# Linux bootstrap: первая тестовая версия
|
||||||
|
|
||||||
|
Собственный bootstrap Server Monitor Manager устанавливает Control или Agent из локального release-архива. Архив принимается только вместе с файлом `<archive>.sha256`, проверяется до распаковки и может содержать лишь каталоги `agent`, `control`, `deploy` и `bootstrap`.
|
||||||
|
|
||||||
|
Текущая версия предназначена для подготовки следующего alpha release. Она устанавливает Control/Agent и mTLS enrollment, но пока не настраивает WireGuard data plane. Ограниченный policy helper намеренно отклоняет Link mutations до реализации следующего этапа.
|
||||||
|
|
||||||
|
## Поддерживаемые системы
|
||||||
|
|
||||||
|
- Ubuntu Server 22.04/24.04;
|
||||||
|
- Debian 12/13;
|
||||||
|
- `amd64` и `arm64`;
|
||||||
|
- systemd.
|
||||||
|
|
||||||
|
## Установка Control
|
||||||
|
|
||||||
|
Скачайте из одного release:
|
||||||
|
|
||||||
|
- `ochenstarik-server-monitor-manager.sh` и его `.sha256`;
|
||||||
|
- `server-monitor-manager-linux-x64.tar.gz` или `server-monitor-manager-linux-arm64.tar.gz`;
|
||||||
|
- соответствующий `.tar.gz.sha256`.
|
||||||
|
|
||||||
|
Сначала проверьте bootstrap, затем установите Control. `PUBLIC_HOST` должен совпадать с DNS-именем или IP, по которому Agents обращаются к Hub:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sha256sum -c ochenstarik-server-monitor-manager.sh.sha256
|
||||||
|
chmod 700 ochenstarik-server-monitor-manager.sh
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh preflight
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh install-control \
|
||||||
|
./server-monitor-manager-linux-x64.tar.gz \
|
||||||
|
hub.example.com \
|
||||||
|
7443
|
||||||
|
```
|
||||||
|
|
||||||
|
Bootstrap создаёт собственный Control CA и HTTPS certificate, системного пользователя, root-only configuration, SQLite directory и hardened systemd unit. В конце он показывает SHA-256 fingerprint CA.
|
||||||
|
|
||||||
|
Создайте десятиминутный token для Node:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh node-token home
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh control-ca-fingerprint
|
||||||
|
```
|
||||||
|
|
||||||
|
Скопируйте на Node только публичный файл `/etc/ochenstarik-server-monitor-manager/control-ca.crt`. Приватный CA PFX остаётся на Hub.
|
||||||
|
|
||||||
|
## Установка Agent
|
||||||
|
|
||||||
|
`CONTROL_URL` обязан использовать то же DNS-имя/IP, которое было передано при установке Control. Token вводится скрыто в локальном терминале и не сохраняется в `agent.env`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh install-agent \
|
||||||
|
./server-monitor-manager-linux-x64.tar.gz \
|
||||||
|
home \
|
||||||
|
https://hub.example.com:7443 \
|
||||||
|
./control-ca.crt
|
||||||
|
```
|
||||||
|
|
||||||
|
Для автоматизированного теста token можно передать только в окружении одного процесса:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo SMM_ENROLL_TOKEN='one-time-token' \
|
||||||
|
./ochenstarik-server-monitor-manager.sh install-agent \
|
||||||
|
./server-monitor-manager-linux-x64.tar.gz home \
|
||||||
|
https://hub.example.com:7443 ./control-ca.crt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Жизненный цикл
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh status
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh update-control ARCHIVE
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh update-agent ARCHIVE
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh rollback control
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh rollback agent
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh uninstall-agent
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh uninstall-agent --purge
|
||||||
|
sudo ./ochenstarik-server-monitor-manager.sh uninstall-control --confirm-destroy-control
|
||||||
|
```
|
||||||
|
|
||||||
|
Update создаёт root-only backup перед заменой binaries. При неуспешном health state предыдущая версия восстанавливается. Agent uninstall без `--purge` сохраняет state; удаление Control требует явного подтверждения и удаляет его SQLite/CA state.
|
||||||
|
|
||||||
|
## Следующий этап
|
||||||
|
|
||||||
|
До тестирования Mesh необходимо добавить WireGuard Hub/Node setup, выдачу адресов, persistent keepalive и применение nftables Links в policy helper. До этого момента bootstrap подходит для тестирования Control, Agent, enrollment, heartbeat, update и rollback, но не для сетевого объединения серверов.
|
||||||
28
tests/bootstrap/test-bootstrap-contract.sh
Executable file
28
tests/bootstrap/test-bootstrap-contract.sh
Executable file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
bootstrap="$root/deploy/ochenstarik-server-monitor-manager.sh"
|
||||||
|
helper="$root/deploy/ochenstarik-smm-policy-apply"
|
||||||
|
|
||||||
|
help_output="$(bash "$bootstrap" --help)"
|
||||||
|
version_output="$(bash "$bootstrap" --version)"
|
||||||
|
|
||||||
|
grep -Fq "install-control ARCHIVE PUBLIC_HOST" <<<"$help_output"
|
||||||
|
grep -Fq "install-agent ARCHIVE NODE_ID CONTROL_URL CA_CERT" <<<"$help_output"
|
||||||
|
grep -Fq "SMM_ENROLL_TOKEN" <<<"$help_output"
|
||||||
|
grep -Fq "node-token NODE_ID" <<<"$help_output"
|
||||||
|
grep -Eq '^ochenstarik-server-monitor-manager [0-9]+\.[0-9]+\.[0-9]+-' <<<"$version_output"
|
||||||
|
|
||||||
|
if bash "$bootstrap" unsupported-action >/dev/null 2>&1; then
|
||||||
|
printf '%s\n' "unsupported bootstrap action unexpectedly succeeded" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if env -u SUDO_UID -u SUDO_USER bash "$helper" link-connect source target tcp 22 10 >/dev/null 2>&1; then
|
||||||
|
printf '%s\n' "policy helper unexpectedly applied an unconfigured rule" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\n' "BOOTSTRAP_CONTRACT=PASS"
|
||||||
Loading…
Reference in a new issue