mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-29 05:35:43 +01:00
encrypt passwords and secret
This commit is contained in:
parent
06519bb3f2
commit
390f89ee0a
@ -25,9 +25,9 @@ env:
|
|||||||
HARBOR_ADMIN_PASSWD: Harbor12345
|
HARBOR_ADMIN_PASSWD: Harbor12345
|
||||||
UI_SECRET: tempString
|
UI_SECRET: tempString
|
||||||
MAX_JOB_WORKERS: 3
|
MAX_JOB_WORKERS: 3
|
||||||
SECRET_KEY: 1234567890123456
|
|
||||||
AUTH_MODE: db_auth
|
AUTH_MODE: db_auth
|
||||||
SELF_REGISTRATION: on
|
SELF_REGISTRATION: on
|
||||||
|
KEY_PATH: /data/secretkey
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- sudo ./tests/hostcfg.sh
|
- sudo ./tests/hostcfg.sh
|
||||||
|
@ -49,6 +49,7 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- /data/config/:/etc/harbor/
|
- /data/config/:/etc/harbor/
|
||||||
|
- /data/secretkey:/harbor/secretkey
|
||||||
depends_on:
|
depends_on:
|
||||||
- log
|
- log
|
||||||
logging:
|
logging:
|
||||||
@ -66,6 +67,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ../common/config/ui/app.conf:/etc/ui/app.conf
|
- ../common/config/ui/app.conf:/etc/ui/app.conf
|
||||||
- ../common/config/ui/private_key.pem:/etc/ui/private_key.pem
|
- ../common/config/ui/private_key.pem:/etc/ui/private_key.pem
|
||||||
|
- /data/secretkey:/harbor/secretkey
|
||||||
depends_on:
|
depends_on:
|
||||||
- log
|
- log
|
||||||
- adminserver
|
- adminserver
|
||||||
@ -85,6 +87,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- /data/job_logs:/var/log/jobs
|
- /data/job_logs:/var/log/jobs
|
||||||
- ../common/config/jobservice/app.conf:/etc/jobservice/app.conf
|
- ../common/config/jobservice/app.conf:/etc/jobservice/app.conf
|
||||||
|
- /data/secretkey:/harbor/secretkey
|
||||||
depends_on:
|
depends_on:
|
||||||
- ui
|
- ui
|
||||||
- adminserver
|
- adminserver
|
||||||
|
@ -49,6 +49,7 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- /data/config/:/etc/harbor/
|
- /data/config/:/etc/harbor/
|
||||||
|
- /data/secretkey:/harbor/secretkey
|
||||||
depends_on:
|
depends_on:
|
||||||
- log
|
- log
|
||||||
logging:
|
logging:
|
||||||
@ -66,6 +67,7 @@ services:
|
|||||||
- ./common/config/ui/app.conf:/etc/ui/app.conf
|
- ./common/config/ui/app.conf:/etc/ui/app.conf
|
||||||
- ./common/config/ui/private_key.pem:/etc/ui/private_key.pem
|
- ./common/config/ui/private_key.pem:/etc/ui/private_key.pem
|
||||||
- /data:/harbor_storage
|
- /data:/harbor_storage
|
||||||
|
- /data/secretkey:/harbor/secretkey
|
||||||
depends_on:
|
depends_on:
|
||||||
- log
|
- log
|
||||||
- adminserver
|
- adminserver
|
||||||
@ -84,6 +86,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- /data/job_logs:/var/log/jobs
|
- /data/job_logs:/var/log/jobs
|
||||||
- ./common/config/jobservice/app.conf:/etc/jobservice/app.conf
|
- ./common/config/jobservice/app.conf:/etc/jobservice/app.conf
|
||||||
|
- /data/secretkey:/harbor/secretkey
|
||||||
depends_on:
|
depends_on:
|
||||||
- ui
|
- ui
|
||||||
- adminserver
|
- adminserver
|
||||||
|
@ -10,6 +10,9 @@ import argparse
|
|||||||
import subprocess
|
import subprocess
|
||||||
import shutil
|
import shutil
|
||||||
from io import open
|
from io import open
|
||||||
|
import base64
|
||||||
|
from Crypto import Random
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
|
||||||
if sys.version_info[:3][0] == 2:
|
if sys.version_info[:3][0] == 2:
|
||||||
import ConfigParser as ConfigParser
|
import ConfigParser as ConfigParser
|
||||||
@ -54,6 +57,11 @@ def get_secret_key(path):
|
|||||||
print("generated and saved secret key")
|
print("generated and saved secret key")
|
||||||
return key
|
return key
|
||||||
|
|
||||||
|
def aesEncrypt(key, raw):
|
||||||
|
iv = Random.new().read(AES.block_size)
|
||||||
|
cipher = AES.new(key, AES.MODE_CFB, iv)
|
||||||
|
return base64.b64encode(iv + cipher.encrypt(raw))
|
||||||
|
|
||||||
base_dir = os.path.dirname(__file__)
|
base_dir = os.path.dirname(__file__)
|
||||||
config_dir = os.path.join(base_dir, "common/config")
|
config_dir = os.path.join(base_dir, "common/config")
|
||||||
templates_dir = os.path.join(base_dir, "common/templates")
|
templates_dir = os.path.join(base_dir, "common/templates")
|
||||||
@ -125,6 +133,7 @@ secret_key = get_secret_key(secretkey_path)
|
|||||||
########
|
########
|
||||||
|
|
||||||
ui_secret = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(16))
|
ui_secret = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(16))
|
||||||
|
#ui_secret = aesEncrypt(secret_key, ui_secret_raw)
|
||||||
|
|
||||||
adminserver_config_dir = os.path.join(config_dir,"adminserver")
|
adminserver_config_dir = os.path.join(config_dir,"adminserver")
|
||||||
if not os.path.exists(adminserver_config_dir):
|
if not os.path.exists(adminserver_config_dir):
|
||||||
|
@ -19,14 +19,13 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
|
|
||||||
|
"github.com/vmware/harbor/src/adminserver/config"
|
||||||
cfg "github.com/vmware/harbor/src/adminserver/systemcfg"
|
cfg "github.com/vmware/harbor/src/adminserver/systemcfg"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func isAuthenticated(r *http.Request) (bool, error) {
|
func isAuthenticated(r *http.Request) (bool, error) {
|
||||||
secret := os.Getenv("UI_SECRET")
|
|
||||||
c, err := r.Cookie("secret")
|
c, err := r.Cookie("secret")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == http.ErrNoCookie {
|
if err == http.ErrNoCookie {
|
||||||
@ -34,7 +33,7 @@ func isAuthenticated(r *http.Request) (bool, error) {
|
|||||||
}
|
}
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return c != nil && c.Value == secret, nil
|
return c != nil && c.Value == config.Secret(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListCfgs lists configurations
|
// ListCfgs lists configurations
|
||||||
|
@ -25,16 +25,36 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/vmware/harbor/src/adminserver/config"
|
||||||
"github.com/vmware/harbor/src/adminserver/systemcfg"
|
"github.com/vmware/harbor/src/adminserver/systemcfg"
|
||||||
"github.com/vmware/harbor/src/common/config"
|
comcfg "github.com/vmware/harbor/src/common/config"
|
||||||
|
"github.com/vmware/harbor/src/common/utils/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfigAPI(t *testing.T) {
|
func TestConfigAPI(t *testing.T) {
|
||||||
path := "/tmp/config.json"
|
configPath := "/tmp/config.json"
|
||||||
secret := "secret"
|
secretKeyPath := "/tmp/secretkey"
|
||||||
|
|
||||||
|
_, err := test.GenerateKey(secretKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to generate secret key: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer os.Remove(secretKeyPath)
|
||||||
|
|
||||||
|
secret := "secret"
|
||||||
|
/*
|
||||||
|
secretPlaintext := "secret"
|
||||||
|
secretCiphertext, err := utils.ReversibleEncrypt(secretPlaintext, string(data))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to encrypt secret: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
envs := map[string]string{
|
envs := map[string]string{
|
||||||
"JSON_STORE_PATH": path,
|
|
||||||
|
"JSON_STORE_PATH": configPath,
|
||||||
|
"KEY_PATH": secretKeyPath,
|
||||||
"UI_SECRET": secret,
|
"UI_SECRET": secret,
|
||||||
"MYSQL_PORT": "3306",
|
"MYSQL_PORT": "3306",
|
||||||
"TOKEN_EXPIRATION": "30",
|
"TOKEN_EXPIRATION": "30",
|
||||||
@ -43,6 +63,10 @@ func TestConfigAPI(t *testing.T) {
|
|||||||
"LDAP_SCOPE": "3",
|
"LDAP_SCOPE": "3",
|
||||||
"LDAP_TIMEOUT": "30",
|
"LDAP_TIMEOUT": "30",
|
||||||
"EMAIL_PORT": "25",
|
"EMAIL_PORT": "25",
|
||||||
|
"MYSQL_PWD": "",
|
||||||
|
"LDAP_SEARCH_PWD": "",
|
||||||
|
"EMAIL_PWD": "",
|
||||||
|
"HARBOR_ADMIN_PASSWORD": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range envs {
|
for k, v := range envs {
|
||||||
@ -50,7 +74,12 @@ func TestConfigAPI(t *testing.T) {
|
|||||||
t.Fatalf("failed to set env %s: %v", k, err)
|
t.Fatalf("failed to set env %s: %v", k, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer os.Remove(path)
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
if err := config.Init(); err != nil {
|
||||||
|
t.Errorf("failed to load configurations of adminserver: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := systemcfg.Init(); err != nil {
|
if err := systemcfg.Init(); err != nil {
|
||||||
t.Errorf("failed to initialize system configurations: %v", err)
|
t.Errorf("failed to initialize system configurations: %v", err)
|
||||||
@ -88,7 +117,7 @@ func TestConfigAPI(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
scope := int(m[config.LDAPScope].(float64))
|
scope := int(m[comcfg.LDAPScope].(float64))
|
||||||
if scope != 3 {
|
if scope != 3 {
|
||||||
t.Errorf("unexpected ldap scope: %d != %d", scope, 3)
|
t.Errorf("unexpected ldap scope: %d != %d", scope, 3)
|
||||||
return
|
return
|
||||||
@ -96,7 +125,7 @@ func TestConfigAPI(t *testing.T) {
|
|||||||
|
|
||||||
// modify configurations
|
// modify configurations
|
||||||
c := map[string]interface{}{
|
c := map[string]interface{}{
|
||||||
config.AUTHMode: config.LDAPAuth,
|
comcfg.AUTHMode: comcfg.LDAPAuth,
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := json.Marshal(c)
|
b, err := json.Marshal(c)
|
||||||
@ -146,9 +175,9 @@ func TestConfigAPI(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
mode := m[config.AUTHMode].(string)
|
mode := m[comcfg.AUTHMode].(string)
|
||||||
if mode != config.LDAPAuth {
|
if mode != comcfg.LDAPAuth {
|
||||||
t.Errorf("unexpected ldap scope: %s != %s", mode, config.LDAPAuth)
|
t.Errorf("unexpected ldap scope: %s != %s", mode, comcfg.LDAPAuth)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
66
src/adminserver/config/config.go
Normal file
66
src/adminserver/config/config.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
//"github.com/vmware/harbor/src/common/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultKeyPath string = "/harbor/secretkey"
|
||||||
|
|
||||||
|
var (
|
||||||
|
secret string
|
||||||
|
secretKey string
|
||||||
|
)
|
||||||
|
|
||||||
|
// Init configurations used by adminserver
|
||||||
|
func Init() error {
|
||||||
|
path := os.Getenv("KEY_PATH")
|
||||||
|
if len(path) == 0 {
|
||||||
|
path = defaultKeyPath
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
secretKey = string(b)
|
||||||
|
|
||||||
|
secret = os.Getenv("UI_SECRET")
|
||||||
|
|
||||||
|
/*
|
||||||
|
secretCipherText := os.Getenv("UI_SECRET")
|
||||||
|
|
||||||
|
secret, err = utils.ReversibleDecrypt(secretCipherText, secretKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Secret is used by API to authenticate requests
|
||||||
|
func Secret() string {
|
||||||
|
return secret
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretKey is used to encrypt or decrypt
|
||||||
|
func SecretKey() string {
|
||||||
|
return secretKey
|
||||||
|
}
|
67
src/adminserver/config/config_test.go
Normal file
67
src/adminserver/config/config_test.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/vmware/harbor/src/common/utils/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConfig(t *testing.T) {
|
||||||
|
secretKeyPath := "/tmp/secretkey"
|
||||||
|
|
||||||
|
secretKey, err := test.GenerateKey(secretKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to generate secret key: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer os.Remove(secretKeyPath)
|
||||||
|
|
||||||
|
secret := "secret"
|
||||||
|
/*
|
||||||
|
secretPlaintext := "secret"
|
||||||
|
secretCiphertext, err := utils.ReversibleEncrypt(secretPlaintext, string(data))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to encrypt secret: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
envs := map[string]string{
|
||||||
|
"KEY_PATH": secretKeyPath,
|
||||||
|
"UI_SECRET": secret,
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range envs {
|
||||||
|
if err := os.Setenv(k, v); err != nil {
|
||||||
|
t.Fatalf("failed to set env %s: %v", k, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := Init(); err != nil {
|
||||||
|
t.Errorf("failed to load configurations of adminserver: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if SecretKey() != secretKey {
|
||||||
|
t.Errorf("unexpected secret key: %s != %s", SecretKey(), secretKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if Secret() != secret {
|
||||||
|
t.Errorf("unexpected secret: %s != %s", Secret(), secret)
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
cfg "github.com/vmware/harbor/src/adminserver/systemcfg"
|
"github.com/vmware/harbor/src/adminserver/config"
|
||||||
|
syscfg "github.com/vmware/harbor/src/adminserver/systemcfg"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,8 +41,15 @@ func (s *Server) Serve() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
|
log.Info("loading configurations of adminserver...")
|
||||||
|
if err := config.Init(); err != nil {
|
||||||
|
log.Fatalf("failed to load configurations of adminserver: %v", err)
|
||||||
|
}
|
||||||
|
log.Info("load completed")
|
||||||
|
|
||||||
log.Info("initializing system configurations...")
|
log.Info("initializing system configurations...")
|
||||||
if err := cfg.Init(); err != nil {
|
if err := syscfg.Init(); err != nil {
|
||||||
log.Fatalf("failed to initialize the system: %v", err)
|
log.Fatalf("failed to initialize the system: %v", err)
|
||||||
}
|
}
|
||||||
log.Info("system initialization completed")
|
log.Info("system initialization completed")
|
||||||
|
@ -20,12 +20,22 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/vmware/harbor/src/adminserver/config"
|
||||||
"github.com/vmware/harbor/src/adminserver/systemcfg/store"
|
"github.com/vmware/harbor/src/adminserver/systemcfg/store"
|
||||||
"github.com/vmware/harbor/src/adminserver/systemcfg/store/json"
|
"github.com/vmware/harbor/src/adminserver/systemcfg/store/json"
|
||||||
comcfg "github.com/vmware/harbor/src/common/config"
|
comcfg "github.com/vmware/harbor/src/common/config"
|
||||||
|
"github.com/vmware/harbor/src/common/utils"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Keys need to be encrypted or decrypted
|
||||||
|
var Keys = []string{
|
||||||
|
comcfg.EmailPassword,
|
||||||
|
comcfg.LDAPSearchPwd,
|
||||||
|
comcfg.MySQLPassword,
|
||||||
|
comcfg.AdminInitialPassword,
|
||||||
|
}
|
||||||
|
|
||||||
var cfgStore store.Driver
|
var cfgStore store.Driver
|
||||||
|
|
||||||
// Init system configurations. Read from config store first, if null read from env
|
// Init system configurations. Read from config store first, if null read from env
|
||||||
@ -43,7 +53,7 @@ func Init() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("configuration store driver: %s", cfgStore.Name())
|
log.Infof("configuration store driver: %s", cfgStore.Name())
|
||||||
cfg, err := cfgStore.Read()
|
cfg, err := GetSystemCfg()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -61,7 +71,7 @@ func Init() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//sync configurations into cfg store
|
//sync configurations into cfg store
|
||||||
if err = cfgStore.Write(cfg); err != nil {
|
if err = UpdateSystemCfg(cfg); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +112,6 @@ func readFromEnv(cfg map[string]interface{}) error {
|
|||||||
cfg[comcfg.JobLogDir] = os.Getenv("LOG_DIR")
|
cfg[comcfg.JobLogDir] = os.Getenv("LOG_DIR")
|
||||||
//TODO remove
|
//TODO remove
|
||||||
cfg[comcfg.UseCompressedJS] = os.Getenv("USE_COMPRESSED_JS") == "on"
|
cfg[comcfg.UseCompressedJS] = os.Getenv("USE_COMPRESSED_JS") == "on"
|
||||||
cfg[comcfg.SecretKey] = os.Getenv("SECRET_KEY")
|
|
||||||
cfgExpi, err := strconv.Atoi(os.Getenv("CFG_EXPIRATION"))
|
cfgExpi, err := strconv.Atoi(os.Getenv("CFG_EXPIRATION"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -162,10 +171,64 @@ func initFromEnv() (map[string]interface{}, error) {
|
|||||||
|
|
||||||
// GetSystemCfg returns the system configurations
|
// GetSystemCfg returns the system configurations
|
||||||
func GetSystemCfg() (map[string]interface{}, error) {
|
func GetSystemCfg() (map[string]interface{}, error) {
|
||||||
return cfgStore.Read()
|
m, err := cfgStore.Read()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = decrypt(m, Keys, config.SecretKey()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateSystemCfg updates the system configurations
|
// UpdateSystemCfg updates the system configurations
|
||||||
func UpdateSystemCfg(cfg map[string]interface{}) error {
|
func UpdateSystemCfg(cfg map[string]interface{}) error {
|
||||||
|
|
||||||
|
if err := encrypt(cfg, Keys, config.SecretKey()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return cfgStore.Write(cfg)
|
return cfgStore.Write(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func encrypt(m map[string]interface{}, keys []string, secretKey string) error {
|
||||||
|
for _, key := range keys {
|
||||||
|
v, ok := m[key]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(v.(string)) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cipherText, err := utils.ReversibleEncrypt(v.(string), secretKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m[key] = cipherText
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decrypt(m map[string]interface{}, keys []string, secretKey string) error {
|
||||||
|
for _, key := range keys {
|
||||||
|
v, ok := m[key]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(v.(string)) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
text, err := utils.ReversibleDecrypt(v.(string), secretKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m[key] = text
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -47,6 +47,10 @@ func TestSystemcfg(t *testing.T) {
|
|||||||
"TOKEN_EXPIRATION": "30",
|
"TOKEN_EXPIRATION": "30",
|
||||||
"CFG_EXPIRATION": "5",
|
"CFG_EXPIRATION": "5",
|
||||||
"EMAIL_PORT": "25",
|
"EMAIL_PORT": "25",
|
||||||
|
"MYSQL_PWD": "",
|
||||||
|
"LDAP_SEARCH_PWD": "",
|
||||||
|
"EMAIL_PWD": "",
|
||||||
|
"HARBOR_ADMIN_PASSWORD": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
|
@ -74,7 +74,6 @@ const (
|
|||||||
CfgExpiration = "cfg_expiration"
|
CfgExpiration = "cfg_expiration"
|
||||||
JobLogDir = "job_log_dir"
|
JobLogDir = "job_log_dir"
|
||||||
UseCompressedJS = "use_compressed_js"
|
UseCompressedJS = "use_compressed_js"
|
||||||
SecretKey = "secret_key"
|
|
||||||
AdminInitialPassword = "admin_initial_password"
|
AdminInitialPassword = "admin_initial_password"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -58,7 +58,6 @@ var adminServerDefaultConfig = map[string]interface{}{
|
|||||||
config.CfgExpiration: 5,
|
config.CfgExpiration: 5,
|
||||||
config.JobLogDir: "/var/log/jobs",
|
config.JobLogDir: "/var/log/jobs",
|
||||||
config.UseCompressedJS: true,
|
config.UseCompressedJS: true,
|
||||||
config.SecretKey: "secret",
|
|
||||||
config.AdminInitialPassword: "password",
|
config.AdminInitialPassword: "password",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
41
src/common/utils/test/key.go
Normal file
41
src/common/utils/test/key.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenerateKey generates aes key
|
||||||
|
func GenerateKey(path string) (string, error) {
|
||||||
|
data := make([]byte, aes.BlockSize)
|
||||||
|
n, err := rand.Read(data)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to generate random bytes: %v", err)
|
||||||
|
}
|
||||||
|
if n != aes.BlockSize {
|
||||||
|
return "", fmt.Errorf("the length of random bytes %d != %d", n, aes.BlockSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = ioutil.WriteFile(path, data, 0777); err != nil {
|
||||||
|
return "", fmt.Errorf("failed write secret key to file %s: %v", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(data), nil
|
||||||
|
}
|
@ -16,16 +16,55 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
comcfg "github.com/vmware/harbor/src/common/config"
|
comcfg "github.com/vmware/harbor/src/common/config"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
|
//"github.com/vmware/harbor/src/common/utils"
|
||||||
|
//"github.com/vmware/harbor/src/common/utils/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const defaultKeyPath string = "/harbor/secretkey"
|
||||||
|
|
||||||
var mg *comcfg.Manager
|
var mg *comcfg.Manager
|
||||||
|
|
||||||
|
var (
|
||||||
|
secret string
|
||||||
|
secretKey string
|
||||||
|
)
|
||||||
|
|
||||||
|
func initSecretAndKey() error {
|
||||||
|
path := os.Getenv("KEY_PATH")
|
||||||
|
if len(path) == 0 {
|
||||||
|
path = defaultKeyPath
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
secretKey = string(b)
|
||||||
|
|
||||||
|
secret = os.Getenv("UI_SECRET")
|
||||||
|
|
||||||
|
/*
|
||||||
|
secretCipherText := os.Getenv("UI_SECRET")
|
||||||
|
|
||||||
|
secret, err = utils.ReversibleDecrypt(secretCipherText, secretKey)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to decrypt secret: %v", err)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Init configurations
|
// Init configurations
|
||||||
func Init() error {
|
func Init() error {
|
||||||
|
if err := initSecretAndKey(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
adminServerURL := os.Getenv("ADMIN_SERVER_URL")
|
adminServerURL := os.Getenv("ADMIN_SERVER_URL")
|
||||||
if len(adminServerURL) == 0 {
|
if len(adminServerURL) == 0 {
|
||||||
adminServerURL = "http://adminserver"
|
adminServerURL = "http://adminserver"
|
||||||
@ -108,17 +147,13 @@ func LogDir() (string, error) {
|
|||||||
|
|
||||||
// SecretKey will return the secret key for encryption/decryption password in target.
|
// SecretKey will return the secret key for encryption/decryption password in target.
|
||||||
func SecretKey() (string, error) {
|
func SecretKey() (string, error) {
|
||||||
cfg, err := mg.Get()
|
return secretKey, nil
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return cfg[comcfg.SecretKey].(string), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UISecret returns the value of UI secret cookie, used for communication between UI and JobService
|
// UISecret returns a secret used for communication of UI, JobService
|
||||||
// TODO
|
// and Adminserver
|
||||||
func UISecret() string {
|
func UISecret() string {
|
||||||
return os.Getenv("UI_SECRET")
|
return secret
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtEndpoint ...
|
// ExtEndpoint ...
|
||||||
|
@ -30,13 +30,22 @@ func TestConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
url := os.Getenv("ADMIN_SERVER_URL")
|
|
||||||
defer os.Setenv("ADMIN_SERVER_URL", url)
|
|
||||||
|
|
||||||
if err := os.Setenv("ADMIN_SERVER_URL", server.URL); err != nil {
|
if err := os.Setenv("ADMIN_SERVER_URL", server.URL); err != nil {
|
||||||
t.Fatalf("failed to set env %s: %v", "ADMIN_SERVER_URL", err)
|
t.Fatalf("failed to set env %s: %v", "ADMIN_SERVER_URL", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
secretKeyPath := "/tmp/secretkey"
|
||||||
|
_, err = test.GenerateKey(secretKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to generate secret key: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer os.Remove(secretKeyPath)
|
||||||
|
|
||||||
|
if err := os.Setenv("KEY_PATH", secretKeyPath); err != nil {
|
||||||
|
t.Fatalf("failed to set env %s: %v", "KEY_PATH", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := Init(); err != nil {
|
if err := Init(); err != nil {
|
||||||
t.Fatalf("failed to initialize configurations: %v", err)
|
t.Fatalf("failed to initialize configurations: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -215,8 +215,6 @@ func validateCfg(c map[string]string) (bool, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("===========%v", c)
|
|
||||||
|
|
||||||
if ldapURL, ok := c[comcfg.LDAPURL]; ok && len(ldapURL) == 0 {
|
if ldapURL, ok := c[comcfg.LDAPURL]; ok && len(ldapURL) == 0 {
|
||||||
return isSysErr, fmt.Errorf("%s is empty", comcfg.LDAPURL)
|
return isSysErr, fmt.Errorf("%s is empty", comcfg.LDAPURL)
|
||||||
}
|
}
|
||||||
@ -325,8 +323,7 @@ func convertForGet(cfg map[string]interface{}) (map[string]*value, error) {
|
|||||||
comcfg.AdminInitialPassword,
|
comcfg.AdminInitialPassword,
|
||||||
comcfg.EmailPassword,
|
comcfg.EmailPassword,
|
||||||
comcfg.LDAPSearchPwd,
|
comcfg.LDAPSearchPwd,
|
||||||
comcfg.MySQLPassword,
|
comcfg.MySQLPassword}
|
||||||
comcfg.SecretKey}
|
|
||||||
for _, del := range dels {
|
for _, del := range dels {
|
||||||
if _, ok := cfg[del]; ok {
|
if _, ok := cfg[del]; ok {
|
||||||
delete(cfg, del)
|
delete(cfg, del)
|
||||||
|
@ -17,17 +17,53 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
comcfg "github.com/vmware/harbor/src/common/config"
|
comcfg "github.com/vmware/harbor/src/common/config"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
|
//"github.com/vmware/harbor/src/common/utils"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const defaultKeyPath string = "/harbor/secretkey"
|
||||||
|
|
||||||
var mg *comcfg.Manager
|
var mg *comcfg.Manager
|
||||||
|
|
||||||
|
var (
|
||||||
|
secret string
|
||||||
|
secretKey string
|
||||||
|
)
|
||||||
|
|
||||||
|
func initSecretAndKey() error {
|
||||||
|
path := os.Getenv("KEY_PATH")
|
||||||
|
if len(path) == 0 {
|
||||||
|
path = defaultKeyPath
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
secretKey = string(b)
|
||||||
|
|
||||||
|
secret = os.Getenv("UI_SECRET")
|
||||||
|
/*
|
||||||
|
secretCipherText := os.Getenv("UI_SECRET")
|
||||||
|
secret, err = utils.ReversibleDecrypt(secretCipherText, secretKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Init configurations
|
// Init configurations
|
||||||
func Init() error {
|
func Init() error {
|
||||||
|
if err := initSecretAndKey(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
adminServerURL := os.Getenv("ADMIN_SERVER_URL")
|
adminServerURL := os.Getenv("ADMIN_SERVER_URL")
|
||||||
if len(adminServerURL) == 0 {
|
if len(adminServerURL) == 0 {
|
||||||
adminServerURL = "http://adminserver"
|
adminServerURL = "http://adminserver"
|
||||||
@ -125,11 +161,7 @@ func ExtEndpoint() (string, error) {
|
|||||||
|
|
||||||
// SecretKey returns the secret key to encrypt the password of target
|
// SecretKey returns the secret key to encrypt the password of target
|
||||||
func SecretKey() (string, error) {
|
func SecretKey() (string, error) {
|
||||||
cfg, err := mg.Get()
|
return secretKey, nil
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return cfg[comcfg.SecretKey].(string), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelfRegistration returns the enablement of self registration
|
// SelfRegistration returns the enablement of self registration
|
||||||
@ -228,8 +260,8 @@ func Database() (*models.Database, error) {
|
|||||||
return database, nil
|
return database, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UISecret returns the value of UI secret cookie, used for communication between UI and JobService
|
// UISecret returns a secret used for communication of UI, JobService
|
||||||
// TODO
|
// and Adminserver
|
||||||
func UISecret() string {
|
func UISecret() string {
|
||||||
return os.Getenv("UI_SECRET")
|
return secret
|
||||||
}
|
}
|
||||||
|
@ -29,13 +29,22 @@ func TestConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
url := os.Getenv("ADMIN_SERVER_URL")
|
|
||||||
defer os.Setenv("ADMIN_SERVER_URL", url)
|
|
||||||
|
|
||||||
if err := os.Setenv("ADMIN_SERVER_URL", server.URL); err != nil {
|
if err := os.Setenv("ADMIN_SERVER_URL", server.URL); err != nil {
|
||||||
t.Fatalf("failed to set env %s: %v", "ADMIN_SERVER_URL", err)
|
t.Fatalf("failed to set env %s: %v", "ADMIN_SERVER_URL", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
secretKeyPath := "/tmp/secretkey"
|
||||||
|
_, err = test.GenerateKey(secretKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to generate secret key: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer os.Remove(secretKeyPath)
|
||||||
|
|
||||||
|
if err := os.Setenv("KEY_PATH", secretKeyPath); err != nil {
|
||||||
|
t.Fatalf("failed to set env %s: %v", "KEY_PATH", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := Init(); err != nil {
|
if err := Init(); err != nil {
|
||||||
t.Fatalf("failed to initialize configurations: %v", err)
|
t.Fatalf("failed to initialize configurations: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- /data/config/:/etc/harbor/
|
- /data/config/:/etc/harbor/
|
||||||
|
- /data/secretkey:/harbor/secretkey
|
||||||
ports:
|
ports:
|
||||||
- 8888:80
|
- 8888:80
|
||||||
ldap:
|
ldap:
|
||||||
|
@ -11,3 +11,5 @@ cp make/common/config/ui/app.conf conf/.
|
|||||||
sed -i -r "s/MYSQL_HOST=mysql/MYSQL_HOST=127.0.0.1/" make/common/config/adminserver/env
|
sed -i -r "s/MYSQL_HOST=mysql/MYSQL_HOST=127.0.0.1/" make/common/config/adminserver/env
|
||||||
sed -i -r "s|REGISTRY_URL=http://registry:5000|REGISTRY_URL=http://127.0.0.1:5000|" make/common/config/adminserver/env
|
sed -i -r "s|REGISTRY_URL=http://registry:5000|REGISTRY_URL=http://127.0.0.1:5000|" make/common/config/adminserver/env
|
||||||
sed -i -r "s/UI_SECRET=.*/UI_SECRET=$UI_SECRET/" make/common/config/adminserver/env
|
sed -i -r "s/UI_SECRET=.*/UI_SECRET=$UI_SECRET/" make/common/config/adminserver/env
|
||||||
|
|
||||||
|
chmod 777 /data/
|
Loading…
Reference in New Issue
Block a user