mirror of
https://github.com/semaphoreui/semaphore.git
synced 2025-01-20 15:29:28 +01:00
feat(be): add access key encryption
This commit is contained in:
parent
ab098b8b82
commit
7443671059
@ -152,8 +152,14 @@ func UpdateKey(w http.ResponseWriter, r *http.Request) {
|
||||
// override secret
|
||||
key.Secret = oldKey.Secret
|
||||
} else {
|
||||
secret := *key.Secret + "\n"
|
||||
key.Secret = &secret
|
||||
*key.Secret += "\n"
|
||||
|
||||
err := key.EncryptSecret()
|
||||
|
||||
if err != nil {
|
||||
helpers.WriteError(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := helpers.Store(r).UpdateAccessKey(key); err != nil {
|
||||
|
@ -345,7 +345,13 @@ func (t *task) installKey(key db.AccessKey) error {
|
||||
}
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(path, []byte(*key.Secret), 0600)
|
||||
secret, err := key.DecryptSecret()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(path, []byte(secret), 0600)
|
||||
}
|
||||
|
||||
func (t *task) updateRepository() error {
|
||||
|
@ -29,7 +29,7 @@ func doSetup() int {
|
||||
var config *util.ConfigType
|
||||
for {
|
||||
config = &util.ConfigType{}
|
||||
config.GenerateCookieSecrets()
|
||||
config.GenerateSecrets()
|
||||
setup.InteractiveSetup(config)
|
||||
|
||||
if setup.AskConfigConfirmation(config) {
|
||||
|
@ -1,6 +1,12 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"github.com/ansible-semaphore/semaphore/util"
|
||||
@ -30,3 +36,88 @@ type AccessKey struct {
|
||||
func (key AccessKey) GetPath() string {
|
||||
return util.Config.TmpPath + "/access_key_" + strconv.Itoa(key.ID)
|
||||
}
|
||||
|
||||
func (key *AccessKey) EncryptSecret() error {
|
||||
if key.Secret == nil || *key.Secret == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if util.Config.AccessKeyEncryption == "" { // do not encrypt if secret key not specified
|
||||
return nil
|
||||
}
|
||||
|
||||
plaintext := []byte(*key.Secret)
|
||||
|
||||
encryption, err := base64.StdEncoding.DecodeString(util.Config.CookieEncryption)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c, err := aes.NewCipher(encryption)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret := string(gcm.Seal(nonce, nonce, plaintext, nil))
|
||||
|
||||
key.Secret = &secret
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (key AccessKey) DecryptSecret() (string, error) {
|
||||
if key.Secret == nil || *key.Secret == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
ciphertext := []byte(*key.Secret)
|
||||
|
||||
if ciphertext[len(ciphertext) - 1] == '\n' { // not encrypted string
|
||||
return *key.Secret, nil
|
||||
}
|
||||
|
||||
if util.Config.AccessKeyEncryption == "" { // do not decrypt if secret key not specified
|
||||
return *key.Secret, nil
|
||||
}
|
||||
|
||||
encryption, err := base64.StdEncoding.DecodeString(util.Config.CookieEncryption)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
c, err := aes.NewCipher(encryption)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
nonceSize := gcm.NonceSize()
|
||||
if len(ciphertext) < nonceSize {
|
||||
return "", fmt.Errorf("ciphertext too short")
|
||||
}
|
||||
|
||||
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
|
||||
|
||||
encrypted, err := gcm.Open(nil, nonce, ciphertext, nil)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(encrypted), nil
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ type ConfigType struct {
|
||||
// cookie hashing & encryption
|
||||
CookieHash string `json:"cookie_hash"`
|
||||
CookieEncryption string `json:"cookie_encryption"`
|
||||
AccessKeyEncryption string `json:"access_key_encryption"`
|
||||
|
||||
// email alerting
|
||||
EmailSender string `json:"email_sender"`
|
||||
@ -292,11 +293,13 @@ func (conf *ConfigType) GetDBConfig() (dbConfig DbConfig, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
//GenerateCookieSecrets generates cookie secret during setup
|
||||
func (conf *ConfigType) GenerateCookieSecrets() {
|
||||
//GenerateSecrets generates cookie secret during setup
|
||||
func (conf *ConfigType) GenerateSecrets() {
|
||||
hash := securecookie.GenerateRandomKey(32)
|
||||
encryption := securecookie.GenerateRandomKey(32)
|
||||
accessKeyEncryption := securecookie.GenerateRandomKey(32)
|
||||
|
||||
conf.CookieHash = base64.StdEncoding.EncodeToString(hash)
|
||||
conf.CookieEncryption = base64.StdEncoding.EncodeToString(encryption)
|
||||
conf.AccessKeyEncryption = base64.StdEncoding.EncodeToString(accessKeyEncryption)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user