Добавлена поддержка wrap

This commit is contained in:
Калинин Сергей Валерьевич
2024-10-17 15:04:35 +03:00
parent ee921f6ae3
commit 897bb3de01
4 changed files with 159 additions and 28 deletions

127
vault.go
View File

@@ -1,3 +1,10 @@
// -------------------------------------------
// Hashicorp Vault wrap/unwrap web service
// Distributed under GNU Public License
// Author: Sergey Kalinin svk@nuk-svk.ru
// Home page: https://nuk-svk.ru https://git.nuk-svk.ru
// -------------------------------------------
package main
import (
@@ -10,6 +17,8 @@ import (
"regexp"
"bytes"
"strconv"
"strings"
"time"
"encoding/json"
"crypto/tls"
"net/http"
@@ -41,15 +50,19 @@ var (
TemplateFile string
ActionAddress string
VaultAddress string
VaultToken string
Data string
ListenPort string
TlsEnable bool
TlsCertFile string
TlsKeyFile string
MaxTextLength int
TokenTTL string
)
type TemplateData struct {
URL string
TEXT string
MAXTEXTLENGTH int
}
type UnwrappedData struct {
Rerquest_id string `json: "request_id"`
@@ -57,24 +70,41 @@ type UnwrappedData struct {
Renewable bool `json: "renewable"`
Lease_daration int `json:"lease_duration"`
Data map[string]string `json: "data"`
Wrap_info string `json: "wrap_info"`
Wrap_info *WrapInfo `json: "wrap_info"`
Warnings string `json: "warnings"`
Auth string `json: "auth"`
Mount_type string `json: "mount_type"`
Error string `json: "errors"`
Errors string `json: "errors"`
}
func vaultDataWrap(vaultAddr string, vaultToken string, vaultSecretName string) string {
type WrapInfo struct {
Token string `json:"token"`
Ttl int `json:"ttl"`
CreationTime time.Time `json:"creation_time"`
CreationPath string `json:"creation_path"`
}
// const MaxTextLength = 100
func vaultDataWrap(vaultAddr string, text string) string {
secret := make(map[string]string)
secret["wrapped_data"] = text
postBody, err := json.Marshal(secret)
if err != nil {
log.Println("Errored marshaling the text:", text)
}
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, _ := http.NewRequest("POST", vaultAddr, bytes.NewBuffer(postBody))
req.Header.Add("Accept", "application/json")
req.Header.Add("X-Vault-Token", vaultToken)
req.Header.Add("X-Vault-Token", VaultToken)
req.Header.Add("X-Vault-Wrap-TTL", TokenTTL)
resp, err := client.Do(req)
@@ -82,11 +112,16 @@ func vaultDataWrap(vaultAddr string, vaultToken string, vaultSecretName string)
log.Println("Errored when sending request to the Vault server")
}
var result map[string]interface{}
var result UnwrappedData
json.NewDecoder(resp.Body).Decode(&result)
secret := result["data"].(map[string]interface{})["data"].(map[string]interface{})[vaultSecretName]
log.Println(result)
return fmt.Sprint(secret)
// wrappedToken := result.Data
if Debug {
log.Println(resp)
log.Println("result", result)
log.Println("token", result.Wrap_info.Token)
}
return result.Wrap_info.Token
}
func vaultDataUnWrap(vaultAddr string, vaultWrapToken string) map[string]string {
@@ -115,9 +150,13 @@ func vaultDataUnWrap(vaultAddr string, vaultWrapToken string) map[string]string
json.NewDecoder(resp.Body).Decode(&result)
secret := result.Data
if Debug {
log.Println(result)
log.Println(secret)
log.Println("result", result)
log.Println("secret", secret)
}
// log.Println("Length=", len(secret))
// if len(secret) == 0 {
// log.Println("Error:", result.Errors)
// }
// fmt.Sprint(secret)
// for v, k := range secret {
// log.Println(k, v)
@@ -151,8 +190,8 @@ func getStaticPage(w http.ResponseWriter, r *http.Request) {
// templateData.UUID = uuid
templateData.URL = ActionAddress
templateData.TEXT = Data
templateData.MAXTEXTLENGTH = MaxTextLength
// templateData.URL = FishingUrl + "/" + arrUsers[i].messageUUID
if body, err := ParseTemplate(template, templateData); err == nil {
@@ -163,7 +202,7 @@ func getStaticPage(w http.ResponseWriter, r *http.Request) {
// hvs.CAES - 95
// s.Dj7kZS - 26
func getDataFromHtmlForm(w http.ResponseWriter, r *http.Request) {
func unwrapDataFromHtmlForm(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
token := r.FormValue("input_token")
@@ -173,7 +212,7 @@ func getDataFromHtmlForm(w http.ResponseWriter, r *http.Request) {
// fmt.Fprintln(w, r.URL.RawQuery)
// log.Println(w, r.URL.RawQuery)
if Debug {
log.Printf("Текст для расшифровки: %s ", token)
log.Printf("Текст для шифровки: %s ", token)
log.Printf("Адрес сервера Hashicorp Vault: %s ", vaultPath)
}
// Проверка текста на соответствие шаблону
@@ -181,15 +220,26 @@ func getDataFromHtmlForm(w http.ResponseWriter, r *http.Request) {
if Debug {
fmt.Println(re.Match([]byte(token)))
}
token = strings.ReplaceAll(token, "\r", "")
token = strings.ReplaceAll(token, "\n", "")
token = strings.ReplaceAll(token, " ", "")
token = strings.TrimSpace(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 Data == "" {
Data = "Ошибка! Токен не найден."
}
if Debug {
log.Println(Data)
}
} else if token != "" {
Data = "Введенные данные не соответствуют формату. Введите корректный токен."
}
getStaticPage(w, r)
// http.Redirect(w, r, "http://"+r.Host, http.StatusMovedPermanently)
@@ -209,7 +259,7 @@ func genPassword(w http.ResponseWriter, r *http.Request) {
}
// w.Write([]byte("Длина пароля " + passLength + "/n"))
passwordLength, err := strconv.Atoi(passLength)
if passwordLength > 1024 {
if passwordLength > MaxTextLength {
log.Printf("Oversized password length")
Data = "Превышена длина пароля"
getStaticPage(w, r)
@@ -242,6 +292,33 @@ func genPasswordDefault(w http.ResponseWriter, r *http.Request) {
getStaticPage(w, r)
}
func wrapDataFromHtmlForm(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
secret := r.FormValue("input_token")
if len([]rune(secret)) > MaxTextLength {
log.Println("Длина текста превышает заданные ограничения:", MaxTextLength)
Data = fmt.Sprintf("Длина текста превышает заданные ограничения: %s > %s", strconv.Itoa(len([]rune(secret))), strconv.Itoa(MaxTextLength))
} else {
vaultPath := VaultAddress + "/v1/sys/wrapping/wrap"
Data = ""
if Debug {
fmt.Println("Введен текст:", secret)
}
if secret != "" {
Data = vaultDataWrap(vaultPath, secret)
if Data == "" {
Data = "Ошибка! Токен не найден."
}
if Debug {
log.Println(Data)
}
} else if secret != "" {
Data = "Введите текст для шифровки."
}
}
getStaticPage(w, r)
}
func main() {
var (
logFile string
@@ -256,6 +333,8 @@ func main() {
flag.StringVar(&TlsCertFile, "tls-cert", "", "TLS сертификат (файл)")
flag.StringVar(&TlsKeyFile, "tls-key", "", "TLS ключ (файл)")
flag.BoolVar(&TlsEnable, "tls", false, "Использовать SSL/TLS")
flag.IntVar(&MaxTextLength, "max-text-length", 100 , "Максимальная длина текста для шифрования и длина пароля для генератора")
flag.StringVar(&TokenTTL, "token-ttl", "3600", "Время жизни wrap-токена в секундах")
flag.Parse()
@@ -281,17 +360,30 @@ func main() {
VaultAddress = os.Getenv("VAULT_ADDRESS")
}
if os.Getenv("VAULT_TOKEN") == "" && VaultToken == "" {
log.Println("Send error: make sure environment variables `VAULT_TOKEN` was set")
} else if os.Getenv("VAULT_TOKEN") != "" && VaultToken == "" {
VaultToken = os.Getenv("VAULT_TOKEN")
}
if os.Getenv("MAX_TEXT_LENGTH") != "" && MaxTextLength == 100 {
MaxTextLength, err = strconv.Atoi(os.Getenv("MAX_TEXT_LENGTH"))
if err != nil {
log.Printf("Ошибка преобразования значения ", os.Getenv("MAX_TEXT_LENGTH"))
}
}
if Debug {
log.Printf("Адрес сервера Hashicorp Vault: %s ", VaultAddress)
}
rtr := mux.NewRouter()
rtr.HandleFunc("/unwrap", getDataFromHtmlForm)
rtr.HandleFunc("/unwrap", unwrapDataFromHtmlForm)
rtr.HandleFunc("/wrap", wrapDataFromHtmlForm)
rtr.HandleFunc("/genpassword/{passLength:[0-9]+}", genPassword)
rtr.HandleFunc("/genpassword", genPassword)
rtr.HandleFunc("/", getDataFromHtmlForm)
rtr.HandleFunc("/", unwrapDataFromHtmlForm)
rtr.PathPrefix("/").Handler(http.FileServer(http.Dir("./static")))
http.Handle("/", rtr)
@@ -316,4 +408,3 @@ func main() {
http.ListenAndServe(listenAddr, nil)
}
}