Add single-code Node enrollment
This commit is contained in:
parent
d3da396c7e
commit
d91f2d380c
3 changed files with 103 additions and 14 deletions
|
|
@ -35,9 +35,11 @@ Usage:
|
||||||
ochenstarik-server-monitor-manager.sh preflight
|
ochenstarik-server-monitor-manager.sh preflight
|
||||||
ochenstarik-server-monitor-manager.sh install-control ARCHIVE PUBLIC_HOST [HTTPS_PORT]
|
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 install-agent ARCHIVE NODE_ID CONTROL_URL CA_CERT
|
||||||
|
ochenstarik-server-monitor-manager.sh install-node ARCHIVE
|
||||||
ochenstarik-server-monitor-manager.sh update-control ARCHIVE
|
ochenstarik-server-monitor-manager.sh update-control ARCHIVE
|
||||||
ochenstarik-server-monitor-manager.sh update-agent ARCHIVE
|
ochenstarik-server-monitor-manager.sh update-agent ARCHIVE
|
||||||
ochenstarik-server-monitor-manager.sh rollback control|agent [BACKUP_ID]
|
ochenstarik-server-monitor-manager.sh rollback control|agent [BACKUP_ID]
|
||||||
|
ochenstarik-server-monitor-manager.sh node-code NODE_ID
|
||||||
ochenstarik-server-monitor-manager.sh node-token NODE_ID
|
ochenstarik-server-monitor-manager.sh node-token NODE_ID
|
||||||
ochenstarik-server-monitor-manager.sh control-ca-fingerprint
|
ochenstarik-server-monitor-manager.sh control-ca-fingerprint
|
||||||
ochenstarik-server-monitor-manager.sh status
|
ochenstarik-server-monitor-manager.sh status
|
||||||
|
|
@ -51,6 +53,23 @@ written to agent.env.
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base64url_encode() {
|
||||||
|
base64 -w 0 | tr '+/' '-_' | tr -d '='
|
||||||
|
}
|
||||||
|
|
||||||
|
base64url_decode() {
|
||||||
|
local value="$1" remainder
|
||||||
|
[[ "$value" =~ ^[A-Za-z0-9_-]+$ ]] || fail "Enrollment code contains invalid base64url data."
|
||||||
|
remainder=$(( ${#value} % 4 ))
|
||||||
|
case "$remainder" in
|
||||||
|
0) ;;
|
||||||
|
2) value+="==" ;;
|
||||||
|
3) value+="=" ;;
|
||||||
|
*) fail "Enrollment code contains invalid base64url length." ;;
|
||||||
|
esac
|
||||||
|
printf '%s' "$value" | tr '_-' '/+' | base64 -d
|
||||||
|
}
|
||||||
|
|
||||||
require_root() {
|
require_root() {
|
||||||
[[ ${EUID:-$(id -u)} -eq 0 ]] || fail "This action must run as root (use sudo)."
|
[[ ${EUID:-$(id -u)} -eq 0 ]] || fail "This action must run as root (use sudo)."
|
||||||
}
|
}
|
||||||
|
|
@ -264,8 +283,10 @@ Control__BackupDirectory=$STATE_DIR/backups
|
||||||
Control__HubHelperPath=$POLICY_HELPER
|
Control__HubHelperPath=$POLICY_HELPER
|
||||||
Control__PrivilegeEscalationPath=/usr/bin/sudo
|
Control__PrivilegeEscalationPath=/usr/bin/sudo
|
||||||
EOF
|
EOF
|
||||||
|
printf '%s\n' "https://$public_host:$port" >"$ETC_DIR/control-public-url"
|
||||||
chown root:"$CONTROL_USER" "$ETC_DIR/control.env"
|
chown root:"$CONTROL_USER" "$ETC_DIR/control.env"
|
||||||
chmod 0640 "$ETC_DIR/control.env"
|
chmod 0640 "$ETC_DIR/control.env"
|
||||||
|
chmod 0644 "$ETC_DIR/control-public-url"
|
||||||
install -m 0755 "$TEMP_DIR/deploy/ochenstarik-smm-policy-apply" "$POLICY_HELPER"
|
install -m 0755 "$TEMP_DIR/deploy/ochenstarik-smm-policy-apply" "$POLICY_HELPER"
|
||||||
printf '%s\n' "$CONTROL_USER ALL=(root) NOPASSWD: $POLICY_HELPER *" >"$SUDOERS_FILE"
|
printf '%s\n' "$CONTROL_USER ALL=(root) NOPASSWD: $POLICY_HELPER *" >"$SUDOERS_FILE"
|
||||||
chmod 0440 "$SUDOERS_FILE"
|
chmod 0440 "$SUDOERS_FILE"
|
||||||
|
|
@ -346,6 +367,54 @@ EOF
|
||||||
log "Agent $node_id installed and enrolled. Backup: $backup_id"
|
log "Agent $node_id installed and enrolled. Backup: $backup_id"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
read_enrollment_code() {
|
||||||
|
if [[ -n "${SMM_ENROLL_CODE:-}" ]]; then
|
||||||
|
ENROLL_CODE="$SMM_ENROLL_CODE"
|
||||||
|
unset SMM_ENROLL_CODE
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
[[ -t 0 ]] || fail "Set SMM_ENROLL_CODE or run from an interactive local terminal."
|
||||||
|
read -r -s -p "SMMNODE1 enrollment code: " ENROLL_CODE
|
||||||
|
printf '\n'
|
||||||
|
[[ -n "$ENROLL_CODE" ]] || fail "Enrollment code is empty."
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm_ca_fingerprint() {
|
||||||
|
local ca_file="$1" answer
|
||||||
|
log "Control CA fingerprint: $(openssl x509 -in "$ca_file" -noout -fingerprint -sha256 | cut -d= -f2)"
|
||||||
|
if [[ "${SMM_ACCEPT_CA_FINGERPRINT:-}" == "1" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
[[ -t 0 ]] || fail "Set SMM_ACCEPT_CA_FINGERPRINT=1 only after verifying the fingerprint out of band."
|
||||||
|
read -r -p "Type 'yes' after comparing this fingerprint with the Hub: " answer
|
||||||
|
[[ "$answer" == "yes" ]] || fail "Control CA fingerprint was not confirmed."
|
||||||
|
}
|
||||||
|
|
||||||
|
install_node_from_code() {
|
||||||
|
local archive="$1" prefix control_part ca_part node_part token_part extra
|
||||||
|
local control_url node_id token ca_file
|
||||||
|
require_root
|
||||||
|
require_command base64
|
||||||
|
require_command openssl
|
||||||
|
read_enrollment_code
|
||||||
|
IFS='.' read -r prefix control_part ca_part node_part token_part extra <<<"$ENROLL_CODE"
|
||||||
|
ENROLL_CODE=""
|
||||||
|
[[ "$prefix" == "SMMNODE1" && -n "$control_part" && -n "$ca_part" \
|
||||||
|
&& -n "$node_part" && -n "$token_part" && -z "${extra:-}" ]] \
|
||||||
|
|| fail "Invalid SMMNODE1 enrollment code."
|
||||||
|
control_url="$(base64url_decode "$control_part")"
|
||||||
|
node_id="$(base64url_decode "$node_part")"
|
||||||
|
token="$(base64url_decode "$token_part")"
|
||||||
|
ca_file="$(mktemp -t smm-control-ca.XXXXXXXX.crt)"
|
||||||
|
chmod 0600 "$ca_file"
|
||||||
|
base64url_decode "$ca_part" >"$ca_file"
|
||||||
|
confirm_ca_fingerprint "$ca_file"
|
||||||
|
SMM_ENROLL_TOKEN="$token"
|
||||||
|
token=""
|
||||||
|
install_agent "$archive" "$node_id" "$control_url" "$ca_file"
|
||||||
|
rm -f -- "$ca_file"
|
||||||
|
}
|
||||||
|
|
||||||
update_role() {
|
update_role() {
|
||||||
local role="$1" archive="$2" binary unit user backup_id
|
local role="$1" archive="$2" binary unit user backup_id
|
||||||
require_root
|
require_root
|
||||||
|
|
@ -423,6 +492,26 @@ run_control_cli() {
|
||||||
"$LIB_DIR/control/ochenstarik-smm-control" "$command_name" "$identifier"
|
"$LIB_DIR/control/ochenstarik-smm-control" "$command_name" "$identifier"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_node_code() {
|
||||||
|
local node_id="$1" token control_url ca_pem
|
||||||
|
require_root
|
||||||
|
validate_node_id "$node_id"
|
||||||
|
[[ -r "$ETC_DIR/control-public-url" ]] || fail "Control public URL is missing; reinstall Control with PUBLIC_HOST."
|
||||||
|
[[ -r "$ETC_DIR/control-ca.crt" ]] || fail "Control CA certificate is missing."
|
||||||
|
require_command base64
|
||||||
|
control_url="$(tr -d '\r\n' <"$ETC_DIR/control-public-url")"
|
||||||
|
validate_control_url "$control_url"
|
||||||
|
token="$(run_control_cli token-create "$node_id")"
|
||||||
|
[[ -n "$token" && "$token" != *$'\n'* ]] || fail "Control returned an invalid enrollment token."
|
||||||
|
ca_pem="$(cat "$ETC_DIR/control-ca.crt")"
|
||||||
|
printf 'SMMNODE1.%s.%s.%s.%s\n' \
|
||||||
|
"$(printf '%s' "$control_url" | base64url_encode)" \
|
||||||
|
"$(printf '%s' "$ca_pem" | base64url_encode)" \
|
||||||
|
"$(printf '%s' "$node_id" | base64url_encode)" \
|
||||||
|
"$(printf '%s' "$token" | base64url_encode)"
|
||||||
|
token=""
|
||||||
|
}
|
||||||
|
|
||||||
show_ca_fingerprint() {
|
show_ca_fingerprint() {
|
||||||
[[ -f "$ETC_DIR/control-ca.crt" ]] || fail "Control CA certificate is not installed."
|
[[ -f "$ETC_DIR/control-ca.crt" ]] || fail "Control CA certificate is not installed."
|
||||||
require_command openssl
|
require_command openssl
|
||||||
|
|
@ -471,9 +560,11 @@ main() {
|
||||||
preflight) preflight ;;
|
preflight) preflight ;;
|
||||||
install-control) [[ $# -ge 2 && $# -le 3 ]] || fail "install-control requires ARCHIVE PUBLIC_HOST [HTTPS_PORT]"; install_control "$@" ;;
|
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 "$@" ;;
|
install-agent) [[ $# -eq 4 ]] || fail "install-agent requires ARCHIVE NODE_ID CONTROL_URL CA_CERT"; install_agent "$@" ;;
|
||||||
|
install-node) [[ $# -eq 1 ]] || fail "install-node requires ARCHIVE"; install_node_from_code "$1" ;;
|
||||||
update-control) [[ $# -eq 1 ]] || fail "update-control requires ARCHIVE"; update_role control "$1" ;;
|
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" ;;
|
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 "$@" ;;
|
rollback) [[ $# -ge 1 && $# -le 2 ]] || fail "rollback requires control|agent [BACKUP_ID]"; rollback_role "$@" ;;
|
||||||
|
node-code) [[ $# -eq 1 ]] || fail "node-code requires NODE_ID"; create_node_code "$1" ;;
|
||||||
node-token) [[ $# -eq 1 ]] || fail "node-token requires NODE_ID"; run_control_cli token-create "$1" ;;
|
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 ;;
|
control-ca-fingerprint) [[ $# -eq 0 ]] || fail "control-ca-fingerprint takes no arguments"; show_ca_fingerprint ;;
|
||||||
status) show_status ;;
|
status) show_status ;;
|
||||||
|
|
|
||||||
|
|
@ -33,34 +33,30 @@ sudo ./ochenstarik-server-monitor-manager.sh install-control \
|
||||||
|
|
||||||
Bootstrap создаёт собственный Control CA и HTTPS certificate, системного пользователя, root-only configuration, SQLite directory и hardened systemd unit. В конце он показывает SHA-256 fingerprint CA.
|
Bootstrap создаёт собственный Control CA и HTTPS certificate, системного пользователя, root-only configuration, SQLite directory и hardened systemd unit. В конце он показывает SHA-256 fingerprint CA.
|
||||||
|
|
||||||
Создайте десятиминутный token для Node:
|
Создайте десятиминутный самодостаточный код `SMMNODE1` для Node:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo ./ochenstarik-server-monitor-manager.sh node-token home
|
sudo ./ochenstarik-server-monitor-manager.sh node-code home
|
||||||
sudo ./ochenstarik-server-monitor-manager.sh control-ca-fingerprint
|
sudo ./ochenstarik-server-monitor-manager.sh control-ca-fingerprint
|
||||||
```
|
```
|
||||||
|
|
||||||
Скопируйте на Node только публичный файл `/etc/ochenstarik-server-monitor-manager/control-ca.crt`. Приватный CA PFX остаётся на Hub.
|
Код содержит URL Control, Node ID, одноразовый token и только публичный CA certificate. Приватный CA PFX остаётся на Hub.
|
||||||
|
|
||||||
## Установка Agent
|
## Установка Agent
|
||||||
|
|
||||||
`CONTROL_URL` обязан использовать то же DNS-имя/IP, которое было передано при установке Control. Token вводится скрыто в локальном терминале и не сохраняется в `agent.env`:
|
Вставьте код `SMMNODE1` в скрытый prompt. Bootstrap покажет fingerprint CA и потребует сравнить его с Hub до создания локального Agent key и CSR. Token не сохраняется в `agent.env`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo ./ochenstarik-server-monitor-manager.sh install-agent \
|
sudo ./ochenstarik-server-monitor-manager.sh install-node \
|
||||||
./server-monitor-manager-linux-x64.tar.gz \
|
./server-monitor-manager-linux-x64.tar.gz
|
||||||
home \
|
|
||||||
https://hub.example.com:7443 \
|
|
||||||
./control-ca.crt
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Для автоматизированного теста token можно передать только в окружении одного процесса:
|
Для автоматизированного теста код и явное принятие уже сверенного fingerprint можно передать только в окружении одного процесса:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo SMM_ENROLL_TOKEN='one-time-token' \
|
sudo SMM_ENROLL_CODE='SMMNODE1....' SMM_ACCEPT_CA_FINGERPRINT=1 \
|
||||||
./ochenstarik-server-monitor-manager.sh install-agent \
|
./ochenstarik-server-monitor-manager.sh install-node \
|
||||||
./server-monitor-manager-linux-x64.tar.gz home \
|
./server-monitor-manager-linux-x64.tar.gz
|
||||||
https://hub.example.com:7443 ./control-ca.crt
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Жизненный цикл
|
## Жизненный цикл
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@ version_output="$(bash "$bootstrap" --version)"
|
||||||
|
|
||||||
grep -Fq "install-control ARCHIVE PUBLIC_HOST" <<<"$help_output"
|
grep -Fq "install-control ARCHIVE PUBLIC_HOST" <<<"$help_output"
|
||||||
grep -Fq "install-agent ARCHIVE NODE_ID CONTROL_URL CA_CERT" <<<"$help_output"
|
grep -Fq "install-agent ARCHIVE NODE_ID CONTROL_URL CA_CERT" <<<"$help_output"
|
||||||
|
grep -Fq "install-node ARCHIVE" <<<"$help_output"
|
||||||
grep -Fq "SMM_ENROLL_TOKEN" <<<"$help_output"
|
grep -Fq "SMM_ENROLL_TOKEN" <<<"$help_output"
|
||||||
|
grep -Fq "node-code NODE_ID" <<<"$help_output"
|
||||||
grep -Fq "node-token NODE_ID" <<<"$help_output"
|
grep -Fq "node-token NODE_ID" <<<"$help_output"
|
||||||
grep -Eq '^ochenstarik-server-monitor-manager [0-9]+\.[0-9]+\.[0-9]+-' <<<"$version_output"
|
grep -Eq '^ochenstarik-server-monitor-manager [0-9]+\.[0-9]+\.[0-9]+-' <<<"$version_output"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue