Postgres: allow providing TLS/SSL certificates as text in addition to file paths (#30353)

* postgres SSL certification

* add back the UI to configure SSL Authentication files by file path

* add backend logic

* correct unittest

* mini changes

* Update public/app/plugins/datasource/postgres/config_ctrl.ts

Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>

* Update public/app/plugins/datasource/postgres/partials/config.html

Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>

* mutex

* check file exist before remove

* change permission

* change default configuremethod to file-path

* Update public/app/plugins/datasource/postgres/partials/config.html

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* Update public/app/plugins/datasource/postgres/partials/config.html

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* Update public/app/plugins/datasource/postgres/partials/config.html

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* Update public/app/plugins/datasource/postgres/partials/config.html

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* rename sslconfiguremethod to sslconfigurationmethod

* frontend update

* solve comments

* Postgres: Convert tests to stdlib

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Postgres: Be consistent about TLS/SSL terminology

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* fix init inconsistancy

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* naming convention

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Undo change

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix TLS issue

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* change permissions

* Fix data source field names

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Clean up HTML

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Improve popover text

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix SSL input bug

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Undo unnecessary change

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Clean up backend code

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix build

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* More consistent naming

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Clean up code

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Enforce certificate file permissions

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* add settings

* Undo changes

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* fix windows file path

* PostgresDataSource: Fix mutex usage

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Update pkg/tsdb/postgres/postgres.go

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* Apply suggestions from code review

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* fix compilation

* fix unittest

* Apply suggestions from code review

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* Apply suggestions from code review

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* mock function

* change kmutex package

* add kmutex into middleware

* lock connection file per datasource

* add unittest regarding concurrency

* version should be equal

* adding unittest

* fix the loop

* fix unitest

* fix postgres unittst

* remove comments

* move dataPath from arg to tlsManager struct field

* Use DecryptedValues method

Use cached decrypted values instead of
using secure json data decrypt which will
decrypt unchanged values over and over again.

* remove unneeded mutex in tests and cleanup tests

* fix the lint

Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
This commit is contained in:
ying-jeanne
2021-02-23 22:10:55 +01:00
committed by GitHub
parent 19c12b5451
commit c57047a420
10 changed files with 883 additions and 116 deletions

View File

@ -16,6 +16,7 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/sqlutil"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/tsdb/sqleng"
"github.com/stretchr/testify/assert"
@ -27,84 +28,110 @@ import (
// Test generateConnectionString.
func TestGenerateConnectionString(t *testing.T) {
logger := log.New("tsdb.postgres")
cfg := setting.NewCfg()
cfg.DataPath = t.TempDir()
testCases := []struct {
desc string
host string
user string
password string
database string
tlsMode string
expConnStr string
expErr string
desc string
host string
user string
password string
database string
tlsSettings tlsSettings
expConnStr string
expErr string
uid string
}{
{
desc: "Unix socket host",
host: "/var/run/postgresql",
user: "user",
password: "password",
database: "database",
expConnStr: "user='user' password='password' host='/var/run/postgresql' dbname='database' sslmode='verify-full'",
desc: "Unix socket host",
host: "/var/run/postgresql",
user: "user",
password: "password",
database: "database",
tlsSettings: tlsSettings{Mode: "verify-full"},
expConnStr: "user='user' password='password' host='/var/run/postgresql' dbname='database' sslmode='verify-full'",
},
{
desc: "TCP host",
host: "host",
user: "user",
password: "password",
database: "database",
expConnStr: "user='user' password='password' host='host' dbname='database' sslmode='verify-full'",
desc: "TCP host",
host: "host",
user: "user",
password: "password",
database: "database",
tlsSettings: tlsSettings{Mode: "verify-full"},
expConnStr: "user='user' password='password' host='host' dbname='database' sslmode='verify-full'",
},
{
desc: "TCP/port host",
host: "host:1234",
user: "user",
password: "password",
database: "database",
expConnStr: "user='user' password='password' host='host' dbname='database' sslmode='verify-full' port=1234",
desc: "TCP/port host",
host: "host:1234",
user: "user",
password: "password",
database: "database",
tlsSettings: tlsSettings{Mode: "verify-full"},
expConnStr: "user='user' password='password' host='host' dbname='database' port=1234 sslmode='verify-full'",
},
{
desc: "Invalid port",
host: "host:invalid",
desc: "Invalid port",
host: "host:invalid",
user: "user",
database: "database",
tlsSettings: tlsSettings{},
expErr: "invalid port in host specifier",
},
{
desc: "Password with single quote and backslash",
host: "host",
user: "user",
password: `p'\assword`,
database: "database",
tlsSettings: tlsSettings{Mode: "verify-full"},
expConnStr: `user='user' password='p\'\\assword' host='host' dbname='database' sslmode='verify-full'`,
},
{
desc: "Custom TLS mode disabled",
host: "host",
user: "user",
password: "password",
database: "database",
tlsSettings: tlsSettings{Mode: "disable"},
expConnStr: "user='user' password='password' host='host' dbname='database' sslmode='disable'",
},
{
desc: "Custom TLS mode verify-full with certificate files",
host: "host",
user: "user",
password: "password",
database: "database",
expErr: "invalid port in host specifier",
},
{
desc: "Password with single quote and backslash",
host: "host",
user: "user",
password: `p'\assword`,
database: "database",
expConnStr: `user='user' password='p\'\\assword' host='host' dbname='database' sslmode='verify-full'`,
},
{
desc: "Custom TLS/SSL mode",
host: "host",
user: "user",
password: "password",
database: "database",
tlsMode: "disable",
expConnStr: "user='user' password='password' host='host' dbname='database' sslmode='disable'",
tlsSettings: tlsSettings{
Mode: "verify-full",
RootCertFile: "i/am/coding/ca.crt",
CertFile: "i/am/coding/client.crt",
CertKeyFile: "i/am/coding/client.key",
},
expConnStr: "user='user' password='password' host='host' dbname='database' sslmode='verify-full' " +
"sslrootcert='i/am/coding/ca.crt' sslcert='i/am/coding/client.crt' sslkey='i/am/coding/client.key'",
},
}
for _, tt := range testCases {
t.Run(tt.desc, func(t *testing.T) {
data := map[string]interface{}{}
if tt.tlsMode != "" {
data["sslmode"] = tt.tlsMode
svc := postgresService{
Cfg: cfg,
logger: log.New("tsdb.postgres"),
tlsManager: &tlsTestManager{settings: tt.tlsSettings},
}
ds := &models.DataSource{
Url: tt.host,
User: tt.user,
Password: tt.password,
Database: tt.database,
JsonData: simplejson.NewFromAny(data),
Uid: tt.uid,
}
connStr, err := generateConnectionString(ds, logger)
connStr, err := svc.generateConnectionString(ds)
if tt.expErr == "" {
require.NoError(t, err, tt.desc)
assert.Equal(t, tt.expConnStr, connStr, tt.desc)
assert.Equal(t, tt.expConnStr, connStr)
} else {
require.Error(t, err, tt.desc)
assert.True(t, strings.HasPrefix(err.Error(), tt.expErr),
@ -127,7 +154,7 @@ func TestPostgres(t *testing.T) {
runPostgresTests := false
// runPostgresTests := true
if !(sqlstore.IsTestDbPostgres() || runPostgresTests) {
if !sqlstore.IsTestDbPostgres() && !runPostgresTests {
t.Skip()
}
@ -146,7 +173,15 @@ func TestPostgres(t *testing.T) {
return sql, nil
}
endpoint, err := newPostgresQueryEndpoint(&models.DataSource{
cfg := setting.NewCfg()
cfg.DataPath = t.TempDir()
svc := postgresService{
Cfg: cfg,
logger: log.New("tsdb.postgres"),
tlsManager: &tlsTestManager{settings: tlsSettings{Mode: "disable"}},
}
endpoint, err := svc.newPostgresQueryEndpoint(&models.DataSource{
JsonData: simplejson.New(),
SecureJsonData: securejsondata.SecureJsonData{},
})
@ -483,9 +518,9 @@ func TestPostgres(t *testing.T) {
ValueTwo int64 `xorm:"integer 'valueTwo'"`
}
if exist, err := sess.IsTableExist(metric_values{}); err != nil || exist {
if exists, err := sess.IsTableExist(metric_values{}); err != nil || exists {
require.NoError(t, err)
err = sess.DropTable(metric_values{})
err := sess.DropTable(metric_values{})
require.NoError(t, err)
}
err := sess.CreateTable(metric_values{})
@ -1084,9 +1119,7 @@ func InitPostgresTestDB(t *testing.T) *xorm.Engine {
testDB := sqlutil.PostgresTestDB()
x, err := xorm.NewEngine(testDB.DriverName, strings.Replace(testDB.ConnStr, "dbname=grafanatest",
"dbname=grafanadstest", 1))
if err != nil {
t.Fatalf("Failed to init postgres DB %v", err)
}
require.NoError(t, err, "Failed to init postgres DB")
x.DatabaseTZ = time.UTC
x.TZLocation = time.UTC
@ -1108,3 +1141,11 @@ func genTimeRangeByInterval(from time.Time, duration time.Duration, interval tim
return timeRange
}
type tlsTestManager struct {
settings tlsSettings
}
func (m *tlsTestManager) getTLSSettings(datasource *models.DataSource) (tlsSettings, error) {
return m.settings, nil
}