Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat secrets #9

Merged
merged 2 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BUILD_DIR = build
APP = deployer
CMD= cmd/main.go
CMD= cmd/deployer/main.go
MC_DIR = build/bin
LOG_DIR= build/log
GIT_VER=$(shell git rev-parse HEAD)
Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ a json object which contains all used varables for the template

``` arrayjoin(array []interface{}, separator string, addLast bool) string ``` makes string out of an array, using a given separator

``` secret(string encrypted, keyFile string) string ``` decrypts a encypted string with a given key file

Example:
Add , to all except the last entry
```
Expand All @@ -63,6 +65,24 @@ Add , to all except the last entry
}
```

### Secret Function
Uses a AES256 encryption for storing secrets in data json.
Use the secret sealer tool to generate key files and encrypt secrets

````
Data:
{
"secretFile" : "examples/secret.key",
"hello": "7cf65678ecda9c427fb80acb54f44e9d6eb9b0ae9ebdea6d9d73687a7642019477108f85fe45dee55f01720e94ee5aa7d48a15ce184d"
}

Template:
"text":[
"This is my secret text",
"{{secret $.textVariable $.secretFile}}"
]
```


## Output file
just parses the given config and data file to the output file.
Expand Down
File renamed without changes.
73 changes: 73 additions & 0 deletions cmd/secretSealer/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package main

import (
"flag"
"fmt"
"io"
"math/rand"
"os"

"github.com/sebastianRau/deployer/pkg/templating"
)

var (
version = "1.0.0 abcdef"
)

func main() {
var (
text = flag.String("t", "", "Text to Encrypt") //toDo remove default
keyFile = flag.String("k", "", "Key file")
generateKey = flag.Bool("g", false, "generate Key file")
)
flag.Parse()

var (
key []byte
)

if *generateKey {
f, err := os.OpenFile(*keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
panic(err)
}
defer f.Close()

key = GenerateKey()
f.Write(key)

} else {
f, err := os.Open(*keyFile)
if err != nil {
panic(err)
}
defer f.Close()

key, err = io.ReadAll(f)
if err != nil {
panic(err)
}
}

enc := templating.Encrypt(*text, key)
dec := templating.Decrypt(enc, key)

fmt.Println(dec + ":")
fmt.Println(enc)

}

func GenerateKey() []byte {
n := 32
digits := "0123456789"
capLetters := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
letters := "abcdefghijklmnopqrstuvwxyz"

letterRunes := digits + capLetters + letters

b := make([]byte, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return b
}
5 changes: 5 additions & 0 deletions examples/secret.data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"version":"1.0.0",
"secretFile" : "examples/secret.key",
"hello": "7cf65678ecda9c427fb80acb54f44e9d6eb9b0ae9ebdea6d9d73687a7642019477108f85fe45dee55f01720e94ee5aa7d48a15ce184d"
}
16 changes: 16 additions & 0 deletions examples/secret.json.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"steps": [
{
"description": "Write secret file",
"type" : "fileWriter",
"ignoreError": false,
"parameter" : {
"filename": "examples/secret.txt",
"text":[
"This is my secret text",
"{{secret $.hello $.secretFile}}"
]
}
}
]
}
1 change: 1 addition & 0 deletions examples/secret.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hYByMbBuBGSgEBb3BZFzUHBbwpV1tlUv
2 changes: 2 additions & 0 deletions examples/secret.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This is my secret text
Hello World this is secret
3 changes: 1 addition & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
67 changes: 67 additions & 0 deletions pkg/templating/secrets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package templating

import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
)

func Encrypt(plaintext string, secretKey []byte) string {

aes, err := aes.NewCipher([]byte(secretKey))
if err != nil {
panic(err)
}

gcm, err := cipher.NewGCM(aes)
if err != nil {
panic(err)
}

// We need a 12-byte nonce for GCM (modifiable if you use cipher.NewGCMWithNonceSize())
// A nonce should always be randomly generated for every encryption.
nonce := make([]byte, gcm.NonceSize())
_, err = rand.Read(nonce)
if err != nil {
panic(err)
}

// ciphertext here is actually nonce+ciphertext
// So that when we decrypt, just knowing the nonce size
// is enough to separate it from the ciphertext.
ciphertext := gcm.Seal(nonce, nonce, []byte(plaintext), nil)

return hex.EncodeToString(ciphertext)
}

func Decrypt(ciphertext string, secretKey []byte) string {

decode, err := hex.DecodeString(ciphertext)
if err != nil {
panic(err)
}
ciphertext = string(decode)

aes, err := aes.NewCipher([]byte(secretKey))
if err != nil {
panic(err)
}

gcm, err := cipher.NewGCM(aes)
if err != nil {
panic(err)
}

// Since we know the ciphertext is actually nonce+ciphertext
// And len(nonce) == NonceSize(). We can separate the two.
nonceSize := gcm.NonceSize()
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]

plaintext, err := gcm.Open(nil, []byte(nonce), []byte(ciphertext), nil)
if err != nil {
panic(err)
}

return string(plaintext)
}
12 changes: 12 additions & 0 deletions pkg/templating/templating.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ func arrayJoin(array []interface{}, separator string, addLast bool) string {
return buf.String()
}

func secret(secretText string, keyFile string) string {
secretFile, err := os.Open(keyFile)
if err != nil {
return ""
}
defer secretFile.Close()

keyBytes, _ := io.ReadAll(secretFile)
return Decrypt(secretText, keyBytes)
}

func ParseTemplateJsonData(templ string, data string) ([]byte, error) {
m := map[string]interface{}{}

Expand Down Expand Up @@ -73,6 +84,7 @@ func ParseTemplateJsonData(templ string, data string) ([]byte, error) {
"isLast": isLast,
"arrayjoin": arrayJoin,
"join": strings.Join,
"secret": secret,
}

t, err := template.New("").Funcs(funcMap).Parse(string(templateBytes))
Expand Down