vault-unwrap/vault.go

320 lines
8.9 KiB
Go
Raw Normal View History

package main
import (
// "context"
"log"
// "time"
"os"
"fmt"
"flag"
"regexp"
"bytes"
"strconv"
"encoding/json"
"crypto/tls"
"net/http"
"html/template"
"path/filepath"
"github.com/gorilla/mux"
"github.com/sethvargo/go-password/password"
)
// {
// "request_id": "540486b5-80b6-4250-1ba3-ec562984c58c",
// "lease_id": "",
// "renewable": false,
// "lease_duration": 0,
// "data": {
// "user": "password"
// },
// "wrap_info": null,
// "warnings": null,
// "auth": null,
// "mount_type": "system"
// }
//
var (
Debug bool
TemplateDir string
TemplateFile string
ActionAddress string
VaultAddress string
Data string
ListenPort string
TlsEnable bool
TlsCertFile string
TlsKeyFile string
)
type TemplateData struct {
URL string
TEXT string
}
type UnwrappedData struct {
Rerquest_id string `json: "request_id"`
Lease_id string `json: "lease_id"`
Renewable bool `json: "renewable"`
Lease_daration int `json:"lease_duration"`
Data map[string]string `json: "data"`
Wrap_info string `json: "wrap_info"`
Warnings string `json: "warnings"`
Auth string `json: "auth"`
Mount_type string `json: "mount_type"`
Error string `json: "errors"`
}
func vaultDataWrap(vaultAddr string, vaultToken string, vaultSecretName string) string {
customTransport := &(*http.DefaultTransport.(*http.Transport))
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
client := &http.Client{Transport: customTransport}
// client := &http.Client{}
req, _ := http.NewRequest("POST", vaultAddr, nil)
req.Header.Add("Accept", "application/json")
req.Header.Add("X-Vault-Token", vaultToken)
resp, err := client.Do(req)
if err != nil {
log.Println("Errored when sending request to the Vault server")
}
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
secret := result["data"].(map[string]interface{})["data"].(map[string]interface{})[vaultSecretName]
log.Println(result)
return fmt.Sprint(secret)
}
func vaultDataUnWrap(vaultAddr string, vaultWrapToken string) map[string]string {
log.Printf("Vault address: %s ", vaultAddr)
customTransport := &(*http.DefaultTransport.(*http.Transport))
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
client := &http.Client{Transport: customTransport}
// client := &http.Client{}
log.Println(vaultAddr, vaultWrapToken)
req, _ := http.NewRequest("POST", vaultAddr, nil)
req.Header.Add("Accept", "application/json")
req.Header.Add("X-Vault-Token", vaultWrapToken)
resp, err := client.Do(req)
if err != nil {
log.Println("Errored when sending request to the Vault server", err)
}
2024-07-11 12:06:57 +03:00
if Debug {
log.Println(resp)
}
var result UnwrappedData
json.NewDecoder(resp.Body).Decode(&result)
secret := result.Data
if Debug {
log.Println(result)
log.Println(secret)
}
// fmt.Sprint(secret)
2024-07-11 12:06:57 +03:00
// for v, k := range secret {
// log.Println(k, v)
// }
return secret
}
func ParseTemplate(templateFileName string, data interface{}) (body string, err error) {
body = ""
t, err := template.ParseFiles(templateFileName)
if err != nil {
log.Println("Ошибка преобразования html шаблона", templateFileName, err)
return
}
buf := new(bytes.Buffer)
if err = t.Execute(buf, data); err != nil {
log.Println("Ошибка преобразования html шаблона", templateFileName, err)
body = ""
} else {
body = buf.String()
}
return
}
func getStaticPage(w http.ResponseWriter, r *http.Request) {
var (
templateData TemplateData
)
template := filepath.Join(TemplateDir, TemplateFile)
// templateData.UUID = uuid
templateData.URL = ActionAddress
templateData.TEXT = Data
// templateData.URL = FishingUrl + "/" + arrUsers[i].messageUUID
if body, err := ParseTemplate(template, templateData); err == nil {
w.Write([]byte(body))
}
}
// hvs.CAES - 95
// s.Dj7kZS - 26
func getDataFromHtmlForm(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
token := r.FormValue("input_token")
vaultPath := VaultAddress + "/v1/sys/wrapping/unwrap"
Data = ""
// fmt.Fprintln(w, r.URL.RawQuery)
// log.Println(w, r.URL.RawQuery)
if Debug {
log.Printf("Текст для расшифровки: %s ", token)
log.Printf("Адрес сервера Hashicorp Vault: %s ", vaultPath)
}
// Проверка текста на соответствие шаблону
re := regexp.MustCompile(`^(hvs|s)\.[\w\-\_]+`)
if Debug {
fmt.Println(re.Match([]byte(token)))
}
if token != "" && re.Match([]byte(token)) {
b := new(bytes.Buffer)
for key, value := range vaultDataUnWrap(vaultPath, token) {
fmt.Fprintf(b, "%s: %s\n", key, value)
}
Data = b.String()
if Debug {
log.Println(Data)
}
}
getStaticPage(w, r)
// http.Redirect(w, r, "http://"+r.Host, http.StatusMovedPermanently)
}
func genPassword(w http.ResponseWriter, r *http.Request) {
// params := mux.Vars(r)
// passLength := params["passLength"]
Data = ""
r.ParseForm()
passLength := r.FormValue("passlength")
if Debug {
log.Printf(r.FormValue("passlength"), passLength)
}
if len(passLength) == 0 {
passLength = "32"
}
// w.Write([]byte("Длина пароля " + passLength + "/n"))
passwordLength, err := strconv.Atoi(passLength)
if passwordLength > 1024 {
log.Printf("Oversized password length")
Data = "Превышена длина пароля"
getStaticPage(w, r)
return
}
if err != nil {
log.Println(err)
}
res, err := password.Generate(passwordLength, 10, 5, false, true)
if err != nil {
log.Println(err)
}
if Debug {
log.Printf(res)
}
Data = res
// w.Write([]byte(res))
getStaticPage(w, r)
}
func genPasswordDefault(w http.ResponseWriter, r *http.Request) {
res, err := password.Generate(64, 10, 5, false, false)
if err != nil {
log.Fatal(err)
}
log.Printf(res)
// w.Write([]byte(res))
Data = res
// w.Write([]byte(res))
getStaticPage(w, r)
}
func main() {
var (
logFile string
)
flag.BoolVar(&Debug, "debug", false, "Вывод отладочных сообщений в консоль")
flag.StringVar(&logFile, "log-file", "vault-unwrap.log", "Путь до лог-файла ")
flag.StringVar(&TemplateDir, "template-dir", "html-template", "Каталог с шаблонами")
flag.StringVar(&TemplateFile, "template-file", "index.html", "Файл-шаблон для ВЭБ-странцы")
flag.StringVar(&VaultAddress, "vault-url", "", "Адрес сервера Hashicorp Vault (https://host.name:8200)")
flag.StringVar(&ActionAddress, "action-address", "", "Адрес данного сервиса (https://host.name)")
flag.StringVar(&ListenPort, "listen-port", "8080", "Номер порта сервиса")
flag.StringVar(&TlsCertFile, "tls-cert", "", "TLS сертификат (файл)")
flag.StringVar(&TlsKeyFile, "tls-key", "", "TLS ключ (файл)")
flag.BoolVar(&TlsEnable, "tls", false, "Использовать SSL/TLS")
flag.Parse()
if os.Getenv("logFile") != "" {
logFile = os.Getenv("logFile")
}
fLog, err := os.OpenFile(logFile, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
defer fLog.Close()
if Debug {
log.SetOutput(os.Stdout)
} else {
log.SetOutput(fLog)
}
if os.Getenv("VAULT_ADDRESS") == "" && VaultAddress == "" {
log.Println("Send error: make sure environment variables `VAULT_ADDRESS` was set")
} else if os.Getenv("VAULT_ADDRESS") != "" && VaultAddress == "" {
VaultAddress = os.Getenv("VAULT_ADDRESS")
}
if Debug {
log.Printf("Адрес сервера Hashicorp Vault: %s ", VaultAddress)
}
rtr := mux.NewRouter()
rtr.HandleFunc("/unwrap", getDataFromHtmlForm)
rtr.HandleFunc("/genpassword/{passLength:[0-9]+}", genPassword)
rtr.HandleFunc("/genpassword", genPassword)
rtr.HandleFunc("/", getDataFromHtmlForm)
rtr.PathPrefix("/").Handler(http.FileServer(http.Dir("./static")))
http.Handle("/", rtr)
if os.Getenv("LISTEN_PORT") != "" {
ListenPort = os.Getenv("LISTEN_PORT")
} else {
if TlsEnable && ListenPort == ""{
ListenPort = "8443"
}
}
listenAddr := ":" + ListenPort
// ActionAddress = "https://" + ActionAddress
if Debug {
log.Printf("Адрес сервиса: %s%s ", ActionAddress, listenAddr)
}
log.Println("Listening...")
if TlsEnable {
log.Fatal(http.ListenAndServeTLS(listenAddr, TlsCertFile, TlsKeyFile, nil))
} else {
http.ListenAndServe(listenAddr, nil)
}
}