mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
MSSQL: Configuration of certificate verification for TLS connection (#31865)
Fixes #24589 Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
This commit is contained in:
parent
50fabe8a87
commit
9e4aafa719
@ -255,6 +255,17 @@ datasources:
|
||||
secureJsonData:
|
||||
password: Password!
|
||||
|
||||
- name: gdev-mssql-tls
|
||||
type: mssql
|
||||
url: localhost:1434
|
||||
database: grafana
|
||||
user: grafana
|
||||
jsonData:
|
||||
encrypt: "true"
|
||||
tlsSkipVerify: true
|
||||
secureJsonData:
|
||||
password: Password!
|
||||
|
||||
- name: gdev-mssql-ds-tests
|
||||
type: mssql
|
||||
url: localhost:1433
|
||||
|
@ -220,6 +220,17 @@ datasources:
|
||||
secureJsonData:
|
||||
password: Password!
|
||||
|
||||
- name: gdev-mssql-tls
|
||||
type: mssql
|
||||
url: localhost:1434
|
||||
database: grafana
|
||||
user: grafana
|
||||
jsonData:
|
||||
encrypt: "true"
|
||||
tlsSkipVerify: true
|
||||
secureJsonData:
|
||||
password: Password!
|
||||
|
||||
- name: gdev-mssql-ds-tests
|
||||
type: mssql
|
||||
url: mssqltests:1433
|
||||
|
21
devenv/docker/blocks/mssql_tls/build/Dockerfile
Normal file
21
devenv/docker/blocks/mssql_tls/build/Dockerfile
Normal file
@ -0,0 +1,21 @@
|
||||
FROM mcr.microsoft.com/mssql/server:2019-CU8-ubuntu-18.04
|
||||
|
||||
WORKDIR /usr/setup
|
||||
COPY setup.sh setup.sql.template entrypoint.sh ./
|
||||
COPY mssql.conf /var/opt/mssql/mssql.conf
|
||||
|
||||
USER root
|
||||
|
||||
RUN chmod +x setup.sh
|
||||
RUN chown -R mssql ./
|
||||
RUN mkdir -p /home/mssql
|
||||
RUN chown -R mssql /home/mssql
|
||||
|
||||
USER mssql
|
||||
|
||||
RUN touch ~/.rnd
|
||||
RUN openssl req -x509 -nodes -newkey rsa:2048 -subj '/CN=mssql_tls' -keyout /var/opt/mssql/mssql.key -out /var/opt/mssql/mssql.pem -days 365
|
||||
RUN chmod 440 /var/opt/mssql/mssql.key
|
||||
RUN chmod 440 /var/opt/mssql/mssql.pem
|
||||
|
||||
CMD /bin/bash ./entrypoint.sh
|
2
devenv/docker/blocks/mssql_tls/build/entrypoint.sh
Normal file
2
devenv/docker/blocks/mssql_tls/build/entrypoint.sh
Normal file
@ -0,0 +1,2 @@
|
||||
#start SQL Server and run setup script
|
||||
/usr/setup/setup.sh & /opt/mssql/bin/sqlservr
|
5
devenv/docker/blocks/mssql_tls/build/mssql.conf
Normal file
5
devenv/docker/blocks/mssql_tls/build/mssql.conf
Normal file
@ -0,0 +1,5 @@
|
||||
[network]
|
||||
tlscert = /var/opt/mssql/mssql.pem
|
||||
tlskey = /var/opt/mssql/mssql.key
|
||||
tlsprotocols = 1.2
|
||||
forceencryption = 1
|
13
devenv/docker/blocks/mssql_tls/build/setup.sh
Normal file
13
devenv/docker/blocks/mssql_tls/build/setup.sh
Normal file
@ -0,0 +1,13 @@
|
||||
#/bin/bash
|
||||
set -eo pipefail
|
||||
|
||||
#wait for the SQL Server to come up
|
||||
sleep 15s
|
||||
|
||||
cat /usr/setup/setup.sql.template | awk '{
|
||||
gsub(/%%DB%%/,"'$MSSQL_DATABASE'");
|
||||
gsub(/%%USER%%/,"'$MSSQL_USER'");
|
||||
gsub(/%%PWD%%/,"'$MSSQL_PASSWORD'")
|
||||
}1' > /usr/setup/setup.sql
|
||||
|
||||
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $MSSQL_SA_PASSWORD -d master -i /usr/setup/setup.sql
|
26
devenv/docker/blocks/mssql_tls/build/setup.sql.template
Normal file
26
devenv/docker/blocks/mssql_tls/build/setup.sql.template
Normal file
@ -0,0 +1,26 @@
|
||||
CREATE LOGIN %%USER%% WITH PASSWORD = '%%PWD%%'
|
||||
GO
|
||||
|
||||
CREATE DATABASE %%DB%%
|
||||
ON
|
||||
( NAME = %%DB%%,
|
||||
FILENAME = '/var/opt/mssql/data/%%DB%%.mdf',
|
||||
SIZE = 500MB,
|
||||
MAXSIZE = 1000MB,
|
||||
FILEGROWTH = 100MB )
|
||||
LOG ON
|
||||
( NAME = %%DB%%_log,
|
||||
FILENAME = '/var/opt/mssql/data/%%DB%%_log.ldf',
|
||||
SIZE = 500MB,
|
||||
MAXSIZE = 1000MB,
|
||||
FILEGROWTH = 100MB );
|
||||
GO
|
||||
|
||||
USE %%DB%%;
|
||||
GO
|
||||
|
||||
CREATE USER %%USER%% FOR LOGIN %%USER%%;
|
||||
GO
|
||||
|
||||
EXEC sp_addrolemember 'db_owner', '%%USER%%';
|
||||
GO
|
18
devenv/docker/blocks/mssql_tls/docker-compose.yaml
Normal file
18
devenv/docker/blocks/mssql_tls/docker-compose.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
mssql_tls:
|
||||
build:
|
||||
context: docker/blocks/mssql_tls/build
|
||||
environment:
|
||||
ACCEPT_EULA: Y
|
||||
MSSQL_SA_PASSWORD: Password!
|
||||
MSSQL_PID: Developer
|
||||
MSSQL_DATABASE: grafana
|
||||
MSSQL_USER: grafana
|
||||
MSSQL_PASSWORD: Password!
|
||||
ports:
|
||||
- "1434:1433"
|
||||
|
||||
fake-mssql-tls-data:
|
||||
image: grafana/fake-data-gen
|
||||
environment:
|
||||
FD_DATASOURCE: mssql_tls
|
||||
FD_PORT: 1434
|
@ -147,8 +147,8 @@ Since not all datasources have the same configuration settings we only have the
|
||||
| -------------------------- | ------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| tlsAuth | boolean | _HTTP\*_, MySQL | Enable TLS authentication using client cert configured in secure json data |
|
||||
| tlsAuthWithCACert | boolean | _HTTP\*_, MySQL, PostgreSQL | Enable TLS authentication using CA cert |
|
||||
| tlsSkipVerify | boolean | _HTTP\*_, MySQL, PostgreSQL | Controls whether a client verifies the server's certificate chain and host name. |
|
||||
| serverName | string | _HTTP\*_ | Optional. Controls the server name used for certificate common name/subject alternative name verification. Defaults to using the data source URL. |
|
||||
| tlsSkipVerify | boolean | _HTTP\*_, MySQL, PostgreSQL, MSSQL | Controls whether a client verifies the server's certificate chain and host name. |
|
||||
| serverName | string | _HTTP\*_, MSSQL | Optional. Controls the server name used for certificate common name/subject alternative name verification. Defaults to using the data source URL. |
|
||||
| timeout | string | _HTTP\*_ | Request timeout in seconds. Overrides dataproxy.timeout option |
|
||||
| graphiteVersion | string | Graphite | Graphite version |
|
||||
| timeInterval | string | Prometheus, Elasticsearch, InfluxDB, MySQL, PostgreSQL and MSSQL | Lowest interval/step value that should be used for this data source. |
|
||||
@ -179,7 +179,7 @@ Since not all datasources have the same configuration settings we only have the
|
||||
| tsdbResolution | string | OpenTSDB | Resolution |
|
||||
| sslmode | string | PostgreSQL | SSLmode. 'disable', 'require', 'verify-ca' or 'verify-full' |
|
||||
| tlsConfigurationMethod | string | PostgreSQL | SSL Certificate configuration, either by 'file-path' or 'file-content' |
|
||||
| sslRootCertFile | string | PostgreSQL | SSL server root certificate file, must be readable by the Grafana user |
|
||||
| sslRootCertFile | string | PostgreSQL, MSSQL | SSL server root certificate file, must be readable by the Grafana user |
|
||||
| sslCertFile | string | PostgreSQL | SSL client certificate file, must be readable by the Grafana user |
|
||||
| sslKeyFile | string | PostgreSQL | SSL client key file, must be readable by _only_ the Grafana user |
|
||||
| encrypt | string | MSSQL | Connection SSL encryption handling. 'disable', 'false' or 'true' |
|
||||
|
@ -82,7 +82,6 @@ func newInstanceSettings(cfg *setting.Cfg) datasource.InstanceFactoryFunc {
|
||||
if cfg.Env == setting.Dev {
|
||||
logger.Debug("getEngine", "connection", cnnstr)
|
||||
}
|
||||
|
||||
config := sqleng.DataPluginConfiguration{
|
||||
DriverName: "mssql",
|
||||
ConnectionString: cnnstr,
|
||||
@ -145,8 +144,12 @@ func generateConnectionString(dsInfo sqleng.DataSourceInfo) (string, error) {
|
||||
if addr.Port != "0" {
|
||||
args = append(args, "port", addr.Port)
|
||||
}
|
||||
|
||||
logger.Debug("Generating connection string", args...)
|
||||
|
||||
encrypt := dsInfo.JsonData.Encrypt
|
||||
tlsSkipVerify := dsInfo.JsonData.TlsSkipVerify
|
||||
hostNameInCertificate := dsInfo.JsonData.Servername
|
||||
certificate := dsInfo.JsonData.RootCertFile
|
||||
connStr := fmt.Sprintf("server=%s;database=%s;user id=%s;password=%s;",
|
||||
addr.Host,
|
||||
dsInfo.Database,
|
||||
@ -157,13 +160,15 @@ func generateConnectionString(dsInfo sqleng.DataSourceInfo) (string, error) {
|
||||
if addr.Port != "0" {
|
||||
connStr += fmt.Sprintf("port=%s;", addr.Port)
|
||||
}
|
||||
|
||||
if dsInfo.JsonData.Encrypt == "" {
|
||||
dsInfo.JsonData.Encrypt = "false"
|
||||
if encrypt == "true" {
|
||||
connStr += fmt.Sprintf("encrypt=%s;TrustServerCertificate=%t;", encrypt, tlsSkipVerify)
|
||||
if hostNameInCertificate != "" {
|
||||
connStr += fmt.Sprintf("hostNameInCertificate=%s;", hostNameInCertificate)
|
||||
}
|
||||
|
||||
if dsInfo.JsonData.Encrypt != "false" {
|
||||
connStr += fmt.Sprintf("encrypt=%s;", dsInfo.JsonData.Encrypt)
|
||||
if certificate != "" {
|
||||
connStr += fmt.Sprintf("certificate=%s;", certificate)
|
||||
}
|
||||
}
|
||||
return connStr, nil
|
||||
}
|
||||
|
@ -56,11 +56,13 @@ type JsonData struct {
|
||||
Timescaledb bool `json:"timescaledb"`
|
||||
Mode string `json:"sslmode"`
|
||||
ConfigurationMethod string `json:"tlsConfigurationMethod"`
|
||||
TlsSkipVerify bool `json:"tlsSkipVerify"`
|
||||
RootCertFile string `json:"sslRootCertFile"`
|
||||
CertFile string `json:"sslCertFile"`
|
||||
CertKeyFile string `json:"sslKeyFile"`
|
||||
Timezone string `json:"timezone"`
|
||||
Encrypt string `json:"encrypt"`
|
||||
Servername string `json:"servername"`
|
||||
TimeInterval string `json:"timeInterval"`
|
||||
}
|
||||
|
||||
|
@ -12,16 +12,22 @@ export class MssqlConfigCtrl {
|
||||
|
||||
onPasswordReset: ReturnType<typeof createResetHandler>;
|
||||
onPasswordChange: ReturnType<typeof createChangeHandler>;
|
||||
showUserCredentials: boolean;
|
||||
showUserCredentials: boolean = false;
|
||||
showTlsConfig: boolean = false;
|
||||
showCertificateConfig: boolean = false;
|
||||
|
||||
/** @ngInject */
|
||||
constructor($scope: any) {
|
||||
this.current = $scope.ctrl.current;
|
||||
this.current.jsonData.encrypt = this.current.jsonData.encrypt || 'false';
|
||||
this.current.jsonData.sslRootCertFile = this.current.jsonData.sslRootCertFile || '';
|
||||
this.current.jsonData.tlsSkipVerify = this.current.jsonData.tlsSkipVerify || false;
|
||||
this.current.jsonData.serverName = this.current.jsonData.serverName || '';
|
||||
this.current.jsonData.authenticationType = this.current.jsonData.authenticationType || 'SQL Server Authentication';
|
||||
this.onPasswordReset = createResetHandler(this, PasswordFieldEnum.Password);
|
||||
this.onPasswordChange = createChangeHandler(this, PasswordFieldEnum.Password);
|
||||
this.showUserCredentials = this.current.jsonData.authenticationType !== 'Windows Authentication';
|
||||
this.onAuthenticationTypeChange();
|
||||
this.onEncryptChange();
|
||||
}
|
||||
|
||||
onAuthenticationTypeChange() {
|
||||
@ -33,4 +39,9 @@ export class MssqlConfigCtrl {
|
||||
|
||||
this.showUserCredentials = this.current.jsonData.authenticationType !== 'Windows Authentication';
|
||||
}
|
||||
|
||||
onEncryptChange() {
|
||||
this.showTlsConfig = this.current.jsonData.encrypt === 'true';
|
||||
this.showCertificateConfig = this.showTlsConfig && this.current.jsonData.tlsSkipVerify === false;
|
||||
}
|
||||
}
|
||||
|
@ -42,10 +42,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<h3 class="page-heading">TLS/SSL Auth</h3>
|
||||
|
||||
<div class="gf-form-group">
|
||||
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-7" for="encrypt-select">Encrypt</label>
|
||||
<label class="gf-form-label width-15" for="encrypt-select">Encrypt</label>
|
||||
<div class="gf-form-select-wrapper max-width-15 gf-form-select-wrapper--has-help-icon">
|
||||
<select id="encrypt-select" class="gf-form-input" ng-model="ctrl.current.jsonData.encrypt" ng-options="mode for mode in ['disable', 'false', 'true']" ng-init="ctrl.current.jsonData.encrypt" aria-labelledby="encrypt-label"></select>
|
||||
<select id="encrypt-select" class="gf-form-input" ng-model="ctrl.current.jsonData.encrypt" ng-options="mode for mode in ['disable', 'false', 'true']" ng-init="ctrl.current.jsonData.encrypt" ng-change="ctrl.onEncryptChange()" aria-labelledby="encrypt-label"></select>
|
||||
<info-popover mode="right-absolute">
|
||||
Determines whether or to which extent a secure SSL TCP/IP connection will be negotiated with the server.
|
||||
<ul>
|
||||
@ -57,6 +63,33 @@
|
||||
</info-popover>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form" ng-show="ctrl.showTlsConfig">
|
||||
<gf-form-switch class="gf-form" label="Skip TLS/SSL Verify" label-class="width-15"
|
||||
tooltip="Skip verifying Server Certificate for TLS/SSL. If this is enabled, any certificate presented by the server and any host name in that certificate will be accepted. In this mode, TLS is susceptible to man-in-the-middle attacks. This should be used only for testing."
|
||||
checked="ctrl.current.jsonData.tlsSkipVerify" switch-class="max-width-8"
|
||||
on-change="ctrl.onEncryptChange()"></gf-form-switch>
|
||||
</div>
|
||||
|
||||
<div class="gf-form max-width-30" ng-show="ctrl.showCertificateConfig">
|
||||
<span class="gf-form-label width-15">TLS/SSL Root Certificate</span>
|
||||
<input type="text" class="gf-form-input" style="width: 352px" ng-model='ctrl.current.jsonData.sslRootCertFile'
|
||||
placeholder="TLS/SSL root certificate file"></input>
|
||||
<info-popover mode="right-absolute">
|
||||
Path to file containing the public key certificate of the CA that signed the SQL Server certificate. Needed when
|
||||
the server certificate is self signed.
|
||||
</info-popover>
|
||||
</div>
|
||||
|
||||
<div class="gf-form max-width-30" ng-show="ctrl.showCertificateConfig">
|
||||
<span class="gf-form-label width-15">Hostname in server certificate</span>
|
||||
<input type="text" class="gf-form-input" style="width: 352px" ng-model='ctrl.current.jsonData.serverName'
|
||||
placeholder="Common Name (CN) in server certificate"></input>
|
||||
<info-popover mode="right-absolute">
|
||||
Specifies the Common Name (CN) in the server certificate. Default is the server host.
|
||||
</info-popover>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<h3 class="page-heading">Connection limits</h3>
|
||||
|
Loading…
Reference in New Issue
Block a user