vault-wrap: Добавлена расшифровка, генератора паролей. INF-1541
This commit is contained in:
parent
8d69b22903
commit
aae70a77ab
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
*.key
|
||||
*.cert
|
||||
*.pem
|
||||
*.log
|
||||
|
19
Dockerfile
Normal file
19
Dockerfile
Normal file
|
@ -0,0 +1,19 @@
|
|||
FROM golang:alpine AS build
|
||||
RUN apk --no-cache add gcc g++ make git
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
COPY . .
|
||||
RUN go get ./...
|
||||
RUN GOOS=linux go build -ldflags="-s -w" -o ./bin/vault-wrap ./vault.go
|
||||
FROM alpine:3.20
|
||||
RUN apk add tzdata
|
||||
#RUN apk --no-cache add ca-certificates
|
||||
WORKDIR /usr/bin
|
||||
COPY --from=build /go/src/app/bin /go/bin
|
||||
|
||||
# COPY cronjobs /etc/crontabs/root
|
||||
|
||||
./bin/vault-wrap -action-address "${ADDRESS}" -vault-url "${VAULT_ADDRESS}" -tls-cert "${TLS_CERT}" -tls-key "${TLS_KEY}"
|
||||
# start crond with log level 8 in foreground, output to stderr
|
||||
# CMD ["crond", "-f", "-d", "8"]
|
20
go.mod
Normal file
20
go.mod
Normal file
|
@ -0,0 +1,20 @@
|
|||
module main
|
||||
|
||||
go 1.21
|
||||
|
||||
toolchain go1.22.0
|
||||
|
||||
require github.com/hashicorp/vault-client-go v0.4.3
|
||||
|
||||
require (
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||
github.com/sethvargo/go-password v0.3.1 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
)
|
39
go.sum
Normal file
39
go.sum
Normal file
|
@ -0,0 +1,39 @@
|
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=
|
||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
|
||||
github.com/hashicorp/vault-client-go v0.4.3 h1:zG7STGVgn/VK6rnZc0k8PGbfv2x/sJExRKHSUg3ljWc=
|
||||
github.com/hashicorp/vault-client-go v0.4.3/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
||||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||
github.com/sethvargo/go-password v0.3.1 h1:WqrLTjo7X6AcVYfC6R7GtSyuUQR9hGyAj/f1PYQZCJU=
|
||||
github.com/sethvargo/go-password v0.3.1/go.mod h1:rXofC1zT54N7R8K/h1WDUdkf9BOx5OptoxrMBcrXzvs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
32
html-template/index.html
Normal file
32
html-template/index.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Data Unwrap Form</title>
|
||||
<!-- <link rel="stylesheet" href="css/normalize.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
|
||||
<link rel="stylesheet" href="css/main.css"> -->
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tr><td>
|
||||
<a href={{.URL}}/unwrap>Расшифровать</a> |
|
||||
<a href={{.URL}}/genpassword>Сгенерировать пароль</a>
|
||||
<tr><td><p></p></td></tr>
|
||||
<tr><td>
|
||||
<form method="post" action="{{.URL}}/unwrap">
|
||||
<table>
|
||||
<tr><td>
|
||||
<textarea id="wrapped_token" name="input_token" cols=50 rows=10>{{ .TEXT }}</textarea>
|
||||
</td></tr>
|
||||
<tr><td align=right>
|
||||
<button type="submit">Расшифровать</button>
|
||||
</td></tr>
|
||||
</form>
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
292
vault.go
Normal file
292
vault.go
Normal file
|
@ -0,0 +1,292 @@
|
|||
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"
|
||||
// "io"
|
||||
// "io/ioutil"
|
||||
|
||||
// "github.com/hashicorp/vault-client-go"
|
||||
// "github.com/hashicorp/vault-client-go/schema"
|
||||
)
|
||||
|
||||
// {
|
||||
// "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
|
||||
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)
|
||||
}
|
||||
|
||||
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 + ":" + ListenPort
|
||||
|
||||
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"
|
||||
|
||||
// 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)
|
||||
}
|
||||
} else {
|
||||
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"]
|
||||
// w.Write([]byte("Длина пароля " + passLength + "/n"))
|
||||
passwordLength, err := strconv.Atoi(passLength)
|
||||
if passwordLength > 1024 {
|
||||
log.Printf("Oversized password length")
|
||||
w.Write([]byte("Oversized password length"))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
res, err := password.Generate(passwordLength, 10, 5, false, true)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf(res)
|
||||
w.Write([]byte(res))
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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", "8443", "Номер порта сервиса")
|
||||
flag.StringVar(&TlsCertFile, "tls-cert", "", "TLS сертификат (файл)")
|
||||
flag.StringVar(&TlsKeyFile, "tls-key", "", "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", genPasswordDefault)
|
||||
|
||||
rtr.HandleFunc("/", getDataFromHtmlForm)
|
||||
rtr.PathPrefix("/").Handler(http.FileServer(http.Dir("./static")))
|
||||
|
||||
http.Handle("/", rtr)
|
||||
if os.Getenv("LISTEN_PORT") != "" {
|
||||
ListenPort = os.Getenv("LISTEN_PORT")
|
||||
}
|
||||
listenAddr := ":" + ListenPort
|
||||
|
||||
log.Println("Listening...")
|
||||
// http.ListenAndServe(":8080", nil)
|
||||
log.Fatal(http.ListenAndServeTLS(listenAddr, TlsCertFile, TlsKeyFile, nil))
|
||||
}
|
Loading…
Reference in New Issue
Block a user