Files
a13labs.infra/tools/open_volume/main.go
T

127 lines
3.0 KiB
Go

package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"os"
"os/exec"
"strings"
)
func usage() {
fmt.Printf("Usage: %s <keyserver> <image> <device>\n", os.Args[0])
fmt.Printf("Example: %s https://keyserver.example.com /path/to/image.img <device>\n", os.Args[0])
fmt.Printf("Example: %s https://keyserver.example.com /path/to/image.img /dev/mapper/crypt1\n", os.Args[0])
os.Exit(1)
}
func fileExists(path string) bool {
_, err := os.Stat(path)
return err == nil
}
func deviceExists(device string) bool {
_, err := os.Stat("/dev/mapper/" + device)
return err == nil
}
func keyserverReachable(url string) bool {
resp, err := http.Head(url)
if err != nil {
return false
}
resp.Body.Close()
return resp.StatusCode < 400
}
func getUUID() string {
// Get CPU model name
cpuinfo, _ := ioutil.ReadFile("/proc/cpuinfo")
var model string
for _, line := range strings.Split(string(cpuinfo), "\n") {
if strings.HasPrefix(line, "model name") {
model = line
break
}
}
// Get eth0 MAC address
iface, err := net.InterfaceByName("eth0")
mac := ""
if err == nil {
mac = iface.HardwareAddr.String()
}
// Get system UUID
out, _ := exec.Command("sudo", "dmidecode", "-s", "system-uuid").Output()
sysuuid := strings.TrimSpace(string(out))
uuid := model + mac + sysuuid
return uuid
}
func main() {
log.SetFlags(0)
if len(os.Args) != 4 {
usage()
}
keyserver := os.Args[1]
image := os.Args[2]
device := os.Args[3]
if !fileExists(image) {
log.Printf("open_volume: (%s) Image file not found", device)
os.Exit(1)
}
if !keyserverReachable(keyserver) {
log.Printf("open_volume: (%s) Key server not reachable, exiting.", device)
os.Exit(1)
}
if deviceExists(device) {
fmt.Printf("open_volume: (%s) Device already open, exiting.\n", device)
os.Exit(1)
}
uuid := getUUID()
h := md5.Sum([]byte(uuid))
keyid := hex.EncodeToString(h[:])
log.Printf("open_volume: (%s) Downloading key from key server,", device)
keyurl := fmt.Sprintf("%s/%s", keyserver, keyid)
resp, err := http.Get(keyurl)
if err != nil || resp.StatusCode != 200 {
log.Printf("open_volume: (%s) Failed to download key from key server", device)
os.Exit(1)
}
defer resp.Body.Close()
tmpfile, err := ioutil.TempFile("", "keyfile")
if err != nil {
log.Printf("open_volume: (%s) Failed to create temp file", device)
os.Exit(1)
}
defer os.Remove(tmpfile.Name())
_, err = io.Copy(tmpfile, resp.Body)
tmpfile.Close()
if err != nil {
log.Printf("open_volume: (%s) Failed to save key file", device)
os.Exit(1)
}
log.Printf("open_volume:'%s' Key downloaded successfully, opening volume", device)
cmd := exec.Command("/usr/sbin/cryptsetup", "luksOpen", image, device, "-d", tmpfile.Name())
out, err := cmd.CombinedOutput()
if err != nil {
log.Printf("open_volume: (%s) Failed to open volume: %s", device, string(out))
os.Exit(1)
}
log.Printf("open_volume: (%s) Volume opened successfully, removing key file", device)
os.Exit(0)
}