diff --git a/make/common/templates/ui/env b/make/common/templates/ui/env index 1f457e257..d87c93105 100644 --- a/make/common/templates/ui/env +++ b/make/common/templates/ui/env @@ -3,3 +3,4 @@ CONFIG_PATH=/etc/ui/app.conf UI_SECRET=$ui_secret JOBSERVICE_SECRET=$jobservice_secret GODEBUG=netdns=cgo +UAA_CA_ROOT=/etc/ui/certificates/uaa_ca.pem diff --git a/make/docker-compose.tpl b/make/docker-compose.tpl index fe7aaa147..2f907f91b 100644 --- a/make/docker-compose.tpl +++ b/make/docker-compose.tpl @@ -77,6 +77,7 @@ services: volumes: - ./common/config/ui/app.conf:/etc/ui/app.conf:z - ./common/config/ui/private_key.pem:/etc/ui/private_key.pem:z + - ./common/config/ui/certificates/:/etc/ui/certifates/ - /data/secretkey:/etc/ui/key:z - /data/ca_download/:/etc/ui/ca/:z - /data/psc/:/etc/ui/token/:z diff --git a/make/harbor.cfg b/make/harbor.cfg index 41c7ab147..4fea2b573 100644 --- a/make/harbor.cfg +++ b/make/harbor.cfg @@ -120,4 +120,5 @@ db_user = root uaa_endpoint = uaa.mydomain.org uaa_clientid= id uaa_clientsecret= secret +uaa_ca_root= /path/to/uaa_ca.pem ############# diff --git a/make/prepare b/make/prepare index 91bd6f3a5..8c6d23587 100755 --- a/make/prepare +++ b/make/prepare @@ -160,6 +160,7 @@ pg_password = rcp.get("configuration", "clair_db_password") uaa_endpoint = rcp.get("configuration", "uaa_endpoint") uaa_clientid = rcp.get("configuration", "uaa_clientid") uaa_clientsecret = rcp.get("configuration", "uaa_clientsecret") +uaa_ca_root = rcp.get("configuration", "uaa_ca_root") secret_key = get_secret_key(secretkey_path) log_rotate_days = rcp.get("configuration", "log_rotate_days") ######## @@ -172,6 +173,7 @@ if not os.path.exists(adminserver_config_dir): os.makedirs(os.path.join(config_dir, "adminserver")) ui_config_dir = prep_conf_dir(config_dir,"ui") +ui_certificates_dir = prep_conf_dir(ui_config_dir,"certificates") db_config_dir = prep_conf_dir(config_dir, "db") job_config_dir = prep_conf_dir(config_dir, "jobservice") registry_config_dir = prep_conf_dir(config_dir, "registry") @@ -204,6 +206,12 @@ if protocol == "https": else: render(os.path.join(templates_dir, "nginx", "nginx.http.conf"), nginx_conf) + +if auth_mode == "uaa_auth": + if os.path.isfile(uaa_ca_root): + shutil.copy2(uaa_ca_root, os.path.join(ui_certificates_dir, "uaa_ca.pem")) + else: + raise Exception("Error: Invalid path for uaa ca root: %s" % uaa_ca_root) render(os.path.join(templates_dir, "adminserver", "env"), adminserver_conf_env, diff --git a/src/common/models/uaa.go b/src/common/models/uaa.go index 9869cc47f..46469c94c 100644 --- a/src/common/models/uaa.go +++ b/src/common/models/uaa.go @@ -19,4 +19,5 @@ type UAASettings struct { Endpoint string ClientID string ClientSecret string + CARootPath string } diff --git a/src/common/utils/uaa/client.go b/src/common/utils/uaa/client.go index c5df061e9..d0f259bfa 100644 --- a/src/common/utils/uaa/client.go +++ b/src/common/utils/uaa/client.go @@ -17,9 +17,12 @@ package uaa import ( "context" "crypto/tls" + "crypto/x509" + "io/ioutil" "net/http" "strings" + "github.com/vmware/harbor/src/common/utils/log" "golang.org/x/oauth2" ) @@ -61,8 +64,18 @@ func NewDefaultClient(cfg *ClientConfig) (Client, error) { tc := &tls.Config{ InsecureSkipVerify: cfg.SkipTLSVerify, } - if len(cfg.CARootPath) > 0 { - //TODO + if !cfg.SkipTLSVerify && len(cfg.CARootPath) > 0 { + content, err := ioutil.ReadFile(cfg.CARootPath) + if err != nil { + return nil, err + } + pool := x509.NewCertPool() + //Do not throw error if the certificate is malformed, so we can put a place holder. + if ok := pool.AppendCertsFromPEM(content); !ok { + log.Warningf("Failed to append certificate to cert pool, cert path: %s", cfg.CARootPath) + } else { + tc.RootCAs = pool + } } hc := &http.Client{ Transport: &http.Transport{ diff --git a/src/common/utils/uaa/client_test.go b/src/common/utils/uaa/client_test.go index 65864919f..1a8081bb5 100644 --- a/src/common/utils/uaa/client_test.go +++ b/src/common/utils/uaa/client_test.go @@ -5,6 +5,8 @@ import ( "github.com/vmware/harbor/src/common/utils/uaa/test" "net/http/httptest" "os" + "path" + "runtime" "testing" ) @@ -40,3 +42,31 @@ func TestPasswordAuth(t *testing.T) { _, err = client.PasswordAuth("wrong", "wrong") assert.NotNil(err) } + +func currPath() string { + _, f, _, ok := runtime.Caller(0) + if !ok { + panic("Failed to get current directory") + } + return path.Dir(f) +} + +func TestNewClientWithCACert(t *testing.T) { + assert := assert.New(t) + cfg := &ClientConfig{ + ClientID: "uaa", + ClientSecret: "secret", + Endpoint: mockUAAServer.URL, + SkipTLSVerify: false, + CARootPath: "/notexist", + } + _, err := NewDefaultClient(cfg) + assert.NotNil(err) + //Skip if it's malformed. + cfg.CARootPath = path.Join(currPath(), "test", "non-ca.pem") + _, err = NewDefaultClient(cfg) + assert.Nil(err) + cfg.CARootPath = path.Join(currPath(), "test", "ca.pem") + _, err = NewDefaultClient(cfg) + assert.Nil(err) +} diff --git a/src/common/utils/uaa/test/ca.pem b/src/common/utils/uaa/test/ca.pem new file mode 100644 index 000000000..9807f27cd --- /dev/null +++ b/src/common/utils/uaa/test/ca.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC7TCCAdWgAwIBAgIJAKmFRnILlp3XMA0GCSqGSIb3DQEBCwUAMA0xCzAJBgNV +BAMMAmNhMB4XDTE3MDkyNDA3MDA1M1oXDTI3MDkyMjA3MDA1M1owDTELMAkGA1UE +AwwCY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCr4+HxXkY81j1p +5OD3htFkbJI+XulBgc7ja5YorU323VB7JfNBnau3rDZS8NdyvkLLEQT4rKw5Dd4p +phlmdKsmIq9ej1OlDjWnCOGr+HG2jG5POgPYRCf5WgCGoQ4eUIA+IXcVroG8f1YM +LDzZEBKlEP80W0zyh0ma/BYN8HG4Ica4q/iIjffJc7ob/tWFGt2HobI9wbTSyBgR +s7JSs6MBIISXGAuOE3cs7vJNzKtWhQSBw4j8FFUZSYCyONFYfOg2OtZG6z1XhpTC +rfVMm6cEsYla/mf9bJB2AqtRiUdUZwAOWQbalWPFKEO73Bj4/5sVNHKFCd/S6J1z +LHaWM0W7AgMBAAGjUDBOMB0GA1UdDgQWBBR0jFgTuL9K2iWE0wzU7r4RZT0k+zAf +BgNVHSMEGDAWgBR0jFgTuL9K2iWE0wzU7r4RZT0k+zAMBgNVHRMEBTADAQH/MA0G +CSqGSIb3DQEBCwUAA4IBAQCemrfEKHPe5ahb2III89+iuIDmbPgVESXqnf88UUdS +Iv+htE8hu9CkSemsErXcC0kUbPSM0vWN9IbHINq78cXucVyi+YTzaKJ8zsK01/zf +x0xYeK5bffYTQzs+BopTCwVqd9zHSs9a2zPnsBVHXCn25j30anQgQH9ODsspXZ3i +WUAkEOmZDnNuX7tGDesA+7h8BPcZ8zrz94kxsrdneMXuHdT1iHxS/hTxTEUUhOMF +FntwT6zx3fGL4cNG06d+pdjjp+CuUR+8GRxeASbYBWhXeiY1ykipiptxkp1zhZ3x +SNandCCdeMRntnNs/+xvRhsEGbhyrvzg2WFL2NrqiKtg +-----END CERTIFICATE----- diff --git a/src/common/utils/uaa/test/non-ca.pem b/src/common/utils/uaa/test/non-ca.pem new file mode 100644 index 000000000..0373d9336 --- /dev/null +++ b/src/common/utils/uaa/test/non-ca.pem @@ -0,0 +1 @@ +abcdef diff --git a/src/ui/auth/uaa/uaa.go b/src/ui/auth/uaa/uaa.go index 7e12b43fb..4ce8f2bae 100644 --- a/src/ui/auth/uaa/uaa.go +++ b/src/ui/auth/uaa/uaa.go @@ -42,8 +42,7 @@ func GetClient() (uaa.Client, error) { ClientID: UAASettings.ClientID, ClientSecret: UAASettings.ClientSecret, Endpoint: UAASettings.Endpoint, - //TODO: remove it - SkipTLSVerify: true, + CARootPath: UAASettings.CARootPath, } client, err = uaa.NewDefaultClient(cfg) return client, err diff --git a/src/ui/config/config.go b/src/ui/config/config.go index 3898895c4..9b0651902 100644 --- a/src/ui/config/config.go +++ b/src/ui/config/config.go @@ -434,5 +434,8 @@ func UAASettings() (*models.UAASettings, error) { ClientID: cfg[common.UAAClientID].(string), ClientSecret: cfg[common.UAAClientSecret].(string), } + if len(os.Getenv("UAA_CA_ROOT")) != 0 { + us.CARootPath = os.Getenv("UAA_CA_ROOT") + } return us, nil }