Security hardening: bind kubeconfig server to localhost, mount hardening (noexec/nosuid/nodev on tmpfs), sysctl network hardening, kernel module loading lock after boot, SHA256 checksum verification for downloads, kernel AppArmor + Audit support, complain-mode AppArmor profiles for containerd and kubelet, and security integration test. ARM64 Raspberry Pi support: piCore64 base extraction, RPi kernel build from raspberrypi/linux fork, RPi firmware fetch, SD card image with 4- partition GPT and tryboot A/B mechanism, BootEnv Go interface abstracting GRUB vs RPi boot environments, architecture-aware build scripts, QEMU aarch64 dev VM and boot test. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
56 lines
1.6 KiB
Go
56 lines
1.6 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"time"
|
|
|
|
"github.com/portainer/kubesolo-os/update/pkg/health"
|
|
)
|
|
|
|
// Healthcheck performs post-boot health verification.
|
|
// If all checks pass, it marks the boot as successful in GRUB.
|
|
// This should be run after every boot (typically via a systemd unit or
|
|
// init script) to confirm the system is healthy.
|
|
func Healthcheck(args []string) error {
|
|
opts := parseOpts(args)
|
|
env := opts.NewBootEnv()
|
|
|
|
// Check if already marked successful
|
|
success, err := env.BootSuccess()
|
|
if err != nil {
|
|
slog.Warn("could not read boot_success", "error", err)
|
|
}
|
|
if success {
|
|
fmt.Println("Boot already marked successful")
|
|
return nil
|
|
}
|
|
|
|
timeout := time.Duration(opts.TimeoutSecs) * time.Second
|
|
checker := health.NewChecker("", "", timeout)
|
|
|
|
slog.Info("running post-boot health checks", "timeout", timeout)
|
|
|
|
status, err := checker.WaitForHealthy()
|
|
if err != nil {
|
|
fmt.Printf("Health check FAILED: %s\n", status.Message)
|
|
fmt.Printf(" containerd: %v\n", status.Containerd)
|
|
fmt.Printf(" apiserver: %v\n", status.APIServer)
|
|
fmt.Printf(" node_ready: %v\n", status.NodeReady)
|
|
fmt.Println("\nBoot NOT marked successful — system may roll back on next reboot")
|
|
return err
|
|
}
|
|
|
|
// Mark boot as successful
|
|
if err := env.MarkBootSuccess(); err != nil {
|
|
return fmt.Errorf("marking boot success: %w", err)
|
|
}
|
|
|
|
fmt.Println("Health check PASSED — boot marked successful")
|
|
fmt.Printf(" containerd: %v\n", status.Containerd)
|
|
fmt.Printf(" apiserver: %v\n", status.APIServer)
|
|
fmt.Printf(" node_ready: %v\n", status.NodeReady)
|
|
|
|
return nil
|
|
}
|