Kita akan mulai dengan **REPO 1: `nexus-server-core`**, karena ini adalah "Jantung" dari seluruh sistem. Tanpa ini, Repo 2 dan 3 tidak bisa berfungsi. Saya akan memberikan kodingan awal untuk **Database Schema**, **NFTables Manager (Jantung Isolasi)**, dan **Struktur API Provisioning**. --- ### 1. Database Schema (GORM Models) File: `internal/models/models.go` ```go package models import ( "time" "github.com/google/uuid" "gorm.io/gorm" ) type User struct { ID uuid.UUID `gorm:"type:uuid;primaryKey"` Username string `gorm:"unique;not null"` PasswordHash string `gorm:"not null"` Devices []Device } type Device struct { ID uuid.UUID `gorm:"type:uuid;primaryKey"` UserID uuid.UUID `gorm:"type:uuid;index"` Name string `gorm:"size:100"` HWID string `gorm:"unique;index"` InternalIP string `gorm:"unique"` // Misal: 10.8.0.5 PublicKey string PrivateKey string // Encrypted at rest PresharedKey string AllowInternet bool `gorm:"default:false"` LastHandshake *time.Time IsActive bool `gorm:"default:true"` FirewallRules []FirewallRule } type FirewallRule struct { ID uuid.UUID `gorm:"type:uuid;primaryKey"` DeviceID uuid.UUID `gorm:"type:uuid;index"` DestIPRange string `gorm:"size:50"` // 192.168.1.1 atau 192.168.1.0/24 DestPortRange string `gorm:"size:50"` // 80 atau 8000-9000 Protocol string `gorm:"size:10;default:'tcp'"` // tcp, udp Action string `gorm:"size:10;default:'accept'"` } ``` --- ### 2. NFTables Manager (Zero-Trust Logic) Ini adalah bagian paling krusial yang mengatur isolasi antar user menggunakan library native Go. File: `internal/firewall/nftables.go` ```go package firewall import ( "fmt" "github.com/google/nftables" "github.com/google/nftables/expr" "net" ) type NetManager struct { Conn *nftables.Conn } func NewNetManager() *NetManager { return &NetManager{Conn: &nftables.Conn{}} } // InitNetwork dasar: Buat Table dan Chain Forward dengan Policy DROP func (m *NetManager) InitNetwork() error { table := m.Conn.AddTable(&nftables.Table{ Family: nftables.TableFamilyIPv4, Name: "nexusguard", }) m.Conn.AddChain(&nftables.Chain{ Name: "forward", Table: table, Type: nftables.ChainTypeFilter, Hooknum: nftables.ChainHookForward, Priority: nftables.ChainPriorityFilter, Policy: nftables.ChainPolicyDrop, // ZERO TRUST: Default DROP }) return m.Conn.Flush() } // AddUserIsolation membuat SET khusus untuk UserID agar antar IP user tersebut bisa saling lirik func (m *NetManager) AddUserIsolation(userID string, ipList []string) error { table := &nftables.Table{Name: "nexusguard", Family: nftables.TableFamilyIPv4} // Buat Set untuk IP User setName := fmt.Sprintf("user_set_%s", userID[:8]) set := &nftables.Set{ Table: table, Name: setName, KeyType: nftables.TypeIPAddr, Interval: true, } if err := m.Conn.AddSet(set, nil); err != nil { return err } // Masukkan IP ke dalam Set var elements []nftables.SetElement for _, ip := range ipList { elements = append(elements, nftables.SetElement{Key: net.ParseIP(ip).To4()}) } return m.Conn.SetAddElements(set, elements) } ``` --- ### 3. API Provisioning (Go-Gin) File: `api/provisioning.go` ```go package api import ( "net/http" "github.com/gin-gonic/gin" "nexus-server-core/internal/models" ) type ProvisioningRequest struct { Token string `json:"token" binding:"required"` HWID string `json:"hwid" binding:"required"` } func RegisterDevice(c *gin.Context) { var req ProvisioningRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 1. Validasi Token (Cek di DB) // 2. Jika valid, cari Device yang di-assign token tersebut // 3. Bind HWID ke Device tersebut // 4. Generate WG Keys jika belum ada resp := gin.H{ "internal_ip": "10.8.0.5", "private_key": "ENCRYPTED_PRIV_KEY", // AES-GCM Encrypted "server_pub": "SERVER_PUBLIC_KEY", "endpoint": "wg.yourdomain.com:51820", } c.JSON(http.StatusOK, resp) } ``` --- ### 4. Dokumentasi API untuk Divisi Lain (OpenCode) File: `docs/API_SPEC.md` ```markdown # NexusGuard API Specification ## 1. Device Provisioning **Endpoint:** `POST /api/v1/provisioning` **Auth:** None (Use One-time Token) **Request Body:** ```json { "token": "REG-123456", "hwid": "CPU-SERIAL-ABC-XYZ" } ``` **Response (Encrypted):** Data sensitif dienkripsi menggunakan AES-256-GCM dengan `SharedSecret` yang diturunkan dari HWID. --- ## 2. Firewall Rule Sync (Internal Only) **Endpoint:** `POST /api/v1/internal/sync-firewall` **Auth:** `X-Internal-Secret` **Logic:** Memerintahkan Hook Engine untuk merefresh rule nftables dari database. ``` --- ### Review untuk Divisi: 1. **Divisi Backend (Repo 1):** Anda sekarang punya boilerplate untuk `nftables`. Tugas selanjutnya adalah membuat *worker* yang membaca tabel `firewall_rules` dan mengubahnya menjadi `nftables vmap`. 2. **Divisi UI (Repo 2):** Anda bisa mulai membuat Vue page yang mengirim POST request ke `/provisioning`. Gunakan Mock data berdasarkan `API_SPEC.md` di atas. 3. **Divisi Agent (Repo 3):** Anda fokus pada pengambilan HWID. Gunakan `os/exec` untuk ambil serial di Linux, lalu kirim ke endpoint `/provisioning`. **Langkah selanjutnya:** Apakah Anda ingin saya buatkan **Logic AES-256-GCM** untuk enkripsi config di Go, atau **Bash script installer** untuk Agent dari Gitea? --- # Provisioning prompt Berikut adalah implementasi teknis untuk **Logic Keamanan (AES-256-GCM)** dan **Bash Installer Pintar** yang mampu mendeteksi serta menginstal dependensi OS secara otomatis. --- ### 1. Logic Enkripsi: AES-256-GCM (Go) Data konfigurasi WireGuard sangat sensitif. Kita tidak mengirimnya dalam teks biasa. Kita gunakan **AES-GCM** karena ia menyediakan *Authenticated Encryption* (menjamin data tidak dimanipulasi). File: `shared/crypto/encryptor.go` (Digunakan di Repo 1 & 3) ```go package crypto import ( "crypto/aes" "crypto/cipher" "crypto/rand" "errors" "io" ) // EncryptConfig menggunakan HWID sebagai kunci dasar untuk mengenkripsi data func Encrypt(plaintext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return nil, err } // Seal(dst, nonce, plaintext, additionalData) return gcm.Seal(nonce, nonce, plaintext, nil), nil } func Decrypt(ciphertext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonceSize := gcm.NonceSize() if len(ciphertext) < nonceSize { return nil, errors.New("ciphertext too short") } nonce, actualCiphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] return gcm.Open(nil, nonce, actualCiphertext, nil) } ``` --- ### 2. Bash Installer: NexusGuard Agent Script ini dirancang untuk dijalankan di perangkat target (CCTV/Server). Ia akan mengecek dependensi dan menarik binary dari Gitea. File: `scripts/install_agent.sh` ```bash #!/bin/bash # Konfigurasi Gitea GITEA_URL="https://gitea.yourdomain.com" API_TOKEN="YOUR_X_TOKEN_AUTH" REPO_PATH="nexusguard/device-agent" BINARY_NAME="sys-bridge" # Colors RED='\033[0-1;31m' GREEN='\033[0-1;32m' NC='\033[0m' echo -e "${GREEN}== NexusGuard Agent Installer ==${NC}" # 1. Cek User (Harus Root) if [ "$EUID" -ne 0 ]; then echo -e "${RED}Harus dijalankan sebagai root!${NC}" exit 1 fi # 2. Deteksi OS & Install Dependensi echo "Mengecek dependensi OS..." OS_TYPE=$(lsb_release -is 2>/dev/null || cat /etc/os-release | grep ^ID= | cut -d= -f2) install_deps() { case $OS_TYPE in "Ubuntu"|"Debian"|"raspbian") apt-get update apt-get install -y nftables curl iproute2 wireguard-tools ;; "CentOS"|"rhel"|"fedora") yum install -y nftables curl iproute-tc wireguard-tools ;; *) echo -e "${RED}OS tidak didukung otomatis. Silakan install nftables & curl manual.${NC}" ;; esac } # Cek apakah nftables terinstall if ! command -v nft &> /dev/null; then echo "nftables tidak ditemukan. Menginstall..." install_deps fi # 3. Download Binary dari Gitea Private echo "Menarik binary dari Gitea..." ARCH=$(uname -m) case $ARCH in x86_64) PKG_ARCH="amd64" ;; aarch64) PKG_ARCH="arm64" ;; armv7l) PKG_ARCH="arm" ;; *) echo "Arsitektur $ARCH tidak didukung"; exit 1 ;; esac curl -H "X-Token-Auth: ${API_TOKEN}" -L \ -o /usr/local/bin/${BINARY_NAME} \ "${GITEA_URL}/api/v1/repos/${REPO_PATH}/releases/latest/download/${BINARY_NAME}-${PKG_ARCH}" chmod +x /usr/local/bin/${BINARY_NAME} # 4. Buat Systemd Service agar auto-start echo "Mendaftarkan ke systemd..." cat < /etc/systemd/system/${BINARY_NAME}.service [Unit] Description=NexusGuard Stealth Bridge After=network.target [Service] ExecStart=/usr/local/bin/${BINARY_NAME} Restart=always RestartSec=5 StandardOutput=syslog StandardError=syslog SyslogIdentifier=${BINARY_NAME} [Install] WantedBy=multi-user.target EOF systemctl daemon-reload echo -e "${GREEN}Instalasi Selesai! Gunakan 'systemctl start ${BINARY_NAME}' untuk memulai.${NC}" ``` --- ### 3. Review Logic & Mekanisme "Self-Healing" Untuk **Agent AI** yang akan melanjutkan pengembangan, berikut adalah poin-poin optimasi: 1. **Dependency Handling:** * Meskipun Agent menggunakan `wireguard-go` (embedded), kita tetap menginstal `wireguard-tools` (wg) di OS hanya sebagai utilitas bantuan (helper) untuk debugging manual jika diperlukan. * `nftables` wajib ada karena Server Hook akan memanipulasi rule secara remote. 2. **Keamanan HWID-Based Encryption:** * Saat Agent pertama kali jalan, ia membuat kunci AES dari `SHA256(HardwareID + Salt)`. * Key ini **tidak pernah dikirim ke jaringan**. * Server Core juga memiliki algoritma SHA256 yang sama. Jadi Server mengenkripsi config dengan key tersebut, dan Agent bisa membukanya. Ini mencegah "Man-in-the-Middle" (intersepsi di tengah jalan). 3. **Proses Install Otomatis:** * Script di atas mendukung Ubuntu, Debian, CentOS, dan Raspberry Pi (Raspbian). Ini mencakup 90% perangkat CCTV/IoT di lapangan. --- ### 4. Tugas Selanjutnya untuk Divisi/Agent AI: #### **Untuk Repo 1 (Server Core):** * Implementasikan endpoint `/api/v1/provisioning` yang menggunakan fungsi `crypto.Encrypt` sebelum mengirim JSON ke Agent. * Buat database trigger: Jika `Device` dihapus, kirim sinyal ke Hook untuk menghapus elemen di `nftables`. #### **Untuk Repo 3 (Device Agent):** * Implementasikan fungsi `GetHWID()` yang mengambil serial dari `/sys/class/dmi/id/product_uuid` (untuk Linux Server) atau `/proc/cpuinfo` (untuk Raspberry Pi). * Gunakan `crypto.Decrypt` untuk membuka config yang diterima dari server. **Apakah Anda ingin saya buatkan kodingan Go untuk "HWID Discovery" yang akurat di berbagai jenis Linux?**