add firewall rules option

This commit is contained in:
2025-11-16 17:03:39 +07:00
parent 36fa9644b4
commit 1655151d29
3 changed files with 141 additions and 18 deletions

View File

@@ -10,7 +10,8 @@ Tool untuk membuat **template** di Proxmox menggunakan cloud image (Ubuntu, Debi
- Support konfigurasi via CLI flags atau YAML file
- Progress bar untuk download
- **QEMU Guest Agent support** (auto-enable)
- **Firewall configuration** (enable/disable)
- **Firewall configuration** (enable/disable + custom rules)
- **Batch mode** untuk create multiple templates sekaligus
## Requirements
@@ -113,6 +114,17 @@ proxmox_user: "root@pam"
proxmox_pass: ""
guest_agent: true
firewall: true
firewall_rules:
- type: in
action: accept
protocol: tcp
dport: "22"
comment: "SSH"
- type: in
action: accept
protocol: tcp
dport: "80,443"
comment: "HTTP/HTTPS"
```
### Batch mode (multiple templates):
@@ -185,7 +197,8 @@ proxmox-cloud-image -batch batch.txt
6. Setup cloud-init
7. **Enable QEMU Guest Agent** (jika di-enable)
8. **Enable Proxmox firewall** (jika di-enable)
9. **Convert VM menjadi template** dengan `qm template`
9. **Configure firewall rules** (jika ada rules yang di-define)
10. **Convert VM menjadi template** dengan `qm template`
## QEMU Guest Agent
@@ -207,6 +220,44 @@ Proxmox firewall bisa di-enable untuk template dengan flag `-firewall` atau di c
firewall: true
```
### Firewall Rules
Kamu juga bisa define firewall rules langsung di config file:
```yaml
firewall: true
firewall_rules:
- type: in
action: accept
protocol: tcp
dport: "22"
comment: "SSH"
- type: in
action: accept
protocol: tcp
dport: "80,443"
comment: "HTTP/HTTPS"
- type: in
action: accept
protocol: icmp
comment: "ICMP/Ping"
- type: in
action: drop
comment: "Drop all other incoming"
```
**Firewall Rule Fields:**
- `type`: `in` (incoming) atau `out` (outgoing)
- `action`: `accept`, `drop`, atau `reject`
- `protocol`: `tcp`, `udp`, `icmp`, dll (optional)
- `dport`: destination port atau port range, contoh: `22`, `80,443`, `8000:9000` (optional)
- `sport`: source port (optional)
- `source`: source IP/CIDR, contoh: `192.168.1.0/24` (optional)
- `dest`: destination IP/CIDR (optional)
- `comment`: komentar untuk rule (optional)
Rules akan ditulis ke `/etc/pve/firewall/<vmid>.fw` di Proxmox host.
Firewall akan di-enable di network interface VM.
## Clone Template

42
main.go
View File

@@ -6,22 +6,34 @@ import (
"os"
)
type FirewallRule struct {
Type string `yaml:"type"`
Action string `yaml:"action"`
Protocol string `yaml:"protocol"`
Dport string `yaml:"dport"`
Sport string `yaml:"sport"`
Source string `yaml:"source"`
Dest string `yaml:"dest"`
Comment string `yaml:"comment"`
}
type Config struct {
ImageURL string `yaml:"image_url"`
VMName string `yaml:"vm_name"`
VMID int `yaml:"vm_id"`
Storage string `yaml:"storage"`
Memory int `yaml:"memory"`
Cores int `yaml:"cores"`
DiskSize string `yaml:"disk_size"`
Bridge string `yaml:"bridge"`
VlanTag int `yaml:"vlan_tag"`
SSHKey string `yaml:"ssh_key"`
ProxmoxHost string `yaml:"proxmox_host"`
ProxmoxUser string `yaml:"proxmox_user"`
ProxmoxPass string `yaml:"proxmox_pass"`
GuestAgent bool `yaml:"guest_agent"`
Firewall bool `yaml:"firewall"`
ImageURL string `yaml:"image_url"`
VMName string `yaml:"vm_name"`
VMID int `yaml:"vm_id"`
Storage string `yaml:"storage"`
Memory int `yaml:"memory"`
Cores int `yaml:"cores"`
DiskSize string `yaml:"disk_size"`
Bridge string `yaml:"bridge"`
VlanTag int `yaml:"vlan_tag"`
SSHKey string `yaml:"ssh_key"`
ProxmoxHost string `yaml:"proxmox_host"`
ProxmoxUser string `yaml:"proxmox_user"`
ProxmoxPass string `yaml:"proxmox_pass"`
GuestAgent bool `yaml:"guest_agent"`
Firewall bool `yaml:"firewall"`
FirewallRules []FirewallRule `yaml:"firewall_rules"`
}
func main() {

View File

@@ -194,9 +194,16 @@ func createProxmoxVM(config *Config) error {
"--serial0", "socket",
"--vga", "serial0",
},
}
if config.Firewall {
commands = append(commands, []string{"qm", "set", fmt.Sprintf("%d", config.VMID), "--firewall", "1"})
}
commands = append(commands, [][]string{
{"qm", "template", fmt.Sprintf("%d", config.VMID)},
{"rm", "-f", remotePath},
}
}...)
for _, cmdArgs := range commands {
fmt.Printf("Running: %s\n", strings.Join(cmdArgs, " "))
@@ -232,12 +239,65 @@ func createProxmoxVM(config *Config) error {
}
}
if config.Firewall && len(config.FirewallRules) > 0 {
if err := configureFirewallRules(config, sshCmd); err != nil {
return fmt.Errorf("failed to configure firewall rules: %w", err)
}
}
fmt.Printf("\nTemplate %s (ID: %d) created successfully!\n", config.VMName, config.VMID)
fmt.Printf("You can clone it with: qm clone %d <new-vm-id> --name <new-vm-name>\n", config.VMID)
return nil
}
func configureFirewallRules(config *Config, sshCmd func(args ...string) *exec.Cmd) error {
fmt.Println("Configuring firewall rules...")
firewallConfig := "[OPTIONS]\nenable: 1\n\n[RULES]\n"
for _, rule := range config.FirewallRules {
ruleLine := fmt.Sprintf("%s %s", strings.ToUpper(rule.Type), strings.ToUpper(rule.Action))
if rule.Protocol != "" {
ruleLine += fmt.Sprintf(" -p %s", rule.Protocol)
}
if rule.Dport != "" {
ruleLine += fmt.Sprintf(" -dport %s", rule.Dport)
}
if rule.Sport != "" {
ruleLine += fmt.Sprintf(" -sport %s", rule.Sport)
}
if rule.Source != "" {
ruleLine += fmt.Sprintf(" -source %s", rule.Source)
}
if rule.Dest != "" {
ruleLine += fmt.Sprintf(" -dest %s", rule.Dest)
}
if rule.Comment != "" {
ruleLine += fmt.Sprintf(" -log nolog # %s", rule.Comment)
}
firewallConfig += ruleLine + "\n"
}
firewallPath := fmt.Sprintf("/etc/pve/firewall/%d.fw", config.VMID)
createCmd := sshCmd("bash", "-c", fmt.Sprintf("cat > %s << 'EOF'\n%sEOF", firewallPath, firewallConfig))
var stdout, stderr bytes.Buffer
createCmd.Stdout = &stdout
createCmd.Stderr = &stderr
if err := createCmd.Run(); err != nil {
fmt.Println(stdout.String())
fmt.Println(stderr.String())
return fmt.Errorf("failed to create firewall config: %w", err)
}
fmt.Printf("Firewall rules configured: %s\n", firewallPath)
return nil
}
func listAvailableStorage(config *Config) error {
fmt.Printf("Detecting available storage on %s...\n", config.ProxmoxHost)