vault-unwrap/vault.go
2024-07-11 12:06:57 +03:00

320 lines
8.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}
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)
// 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)
}
}