Skip to content

Commit ec5ffe5

Browse files
committed
Add tls conn in datasource
1 parent 38308ab commit ec5ffe5

File tree

5 files changed

+106
-14
lines changed

5 files changed

+106
-14
lines changed

pkg/models/settings.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@ type PluginSettings struct {
1515
Username string `json:"username"`
1616
ConnectionStringScheme string `json:"connectionStringScheme"`
1717
ConnectionParameters string `json:"connectionParameters"`
18+
CaCertPath string `json:"caCertPath"`
19+
ClientCertPath string `json:"clientCertPath"` // public client certificate
20+
ClientKeyPath string `json:"clientKeyPath"` // private client key
1821
Secrets *SecretPluginSettings `json:"-"`
1922
}
2023

2124
type SecretPluginSettings struct {
22-
Password string `json:"password"`
25+
Password string `json:"password"`
26+
ClientKeyPassword string `json:"clientKeyPassword"`
2327
}
2428

2529
func LoadPluginSettings(source backend.DataSourceInstanceSettings) (*PluginSettings, error) {
@@ -36,6 +40,7 @@ func LoadPluginSettings(source backend.DataSourceInstanceSettings) (*PluginSetti
3640

3741
func loadSecretPluginSettings(source map[string]string) *SecretPluginSettings {
3842
return &SecretPluginSettings{
39-
Password: source["password"],
43+
Password: source["password"],
44+
ClientKeyPassword: source["clientKeyPassword"],
4045
}
4146
}

pkg/plugin/datasource.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ package plugin
22

33
import (
44
"context"
5+
"crypto/tls"
6+
"crypto/x509"
57
"encoding/json"
8+
"errors"
69
"fmt"
10+
"os"
711
"strings"
812
"time"
913

@@ -44,6 +48,16 @@ func NewDatasource(ctx context.Context, source backend.DataSourceInstanceSetting
4448

4549
opts := options.Client().ApplyURI(uri)
4650

51+
if config.AuthMethod == "auth-tls-ssl" {
52+
// TLS setup
53+
tlsConfig, err := tlsSetup(config)
54+
if err != nil {
55+
backend.Logger.Error("Failed to setup TLS", "error", err)
56+
return nil, err
57+
}
58+
opts.SetTLSConfig(tlsConfig)
59+
}
60+
4761
client, err := mongo.Connect(ctx, opts)
4862
if err != nil {
4963
backend.Logger.Error(fmt.Sprintf("Failed to connect to db: %s", err.Error()))
@@ -63,6 +77,35 @@ func (d *Datasource) Dispose() {
6377
d.client.Disconnect(context.TODO())
6478
}
6579

80+
func tlsSetup(config *models.PluginSettings) (*tls.Config, error) {
81+
caFile := config.CaCertPath
82+
certFile := config.ClientCertPath
83+
keyFile := config.ClientKeyPath
84+
85+
// Loads CA certificate file
86+
caCert, err := os.ReadFile(caFile)
87+
if err != nil {
88+
return nil, err
89+
}
90+
caCertPool := x509.NewCertPool()
91+
if ok := caCertPool.AppendCertsFromPEM(caCert); !ok {
92+
return nil, errors.New("CA file must be in PEM format")
93+
}
94+
// Loads client certificate files
95+
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
96+
97+
if err != nil {
98+
return nil, err
99+
}
100+
101+
tlsConfig := &tls.Config{
102+
RootCAs: caCertPool,
103+
Certificates: []tls.Certificate{cert},
104+
}
105+
106+
return tlsConfig, nil
107+
}
108+
66109
// QueryData handles multiple queries and returns multiple responses.
67110
// req contains the queries []DataQuery (where each query contains RefID as a unique identifier).
68111
// The QueryDataResponse contains a map of RefID to the response for each query, and each response

pkg/plugin/utils.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ func MongoUri(config *models.PluginSettings) (string, error) {
8787
params = "?" + config.ConnectionParameters
8888
}
8989

90+
// TLS passphrase
91+
if config.AuthMethod == "auth-tls-ssl" && config.Secrets.ClientKeyPassword != "" {
92+
params += "&sslClientCertificateKeyPassword=" + config.Secrets.ClientKeyPassword
93+
}
94+
9095
if config.ConnectionStringScheme == "dns_seed_list" {
9196
uri = fmt.Sprintf("mongodb+srv://%s%s/%s", creds, config.Host, params)
9297
} else {

src/components/ConfigEditor.tsx

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ import {
88
Input,
99
RadioButtonGroup,
1010
SecretInput,
11-
FileUpload,
12-
FileDropzone,
13-
InlineLabel,
14-
Label,
1511
Checkbox,
1612
} from '@grafana/ui';
1713
import { DataSourcePluginOptionsEditorProps, SelectableValue } from '@grafana/data';
@@ -22,7 +18,7 @@ import {
2218
ConnectionStringScheme,
2319
} from '../types';
2420

25-
interface Props extends DataSourcePluginOptionsEditorProps<MongoDataSourceOptions, MongoDataSourceSecureJsonData> {}
21+
interface Props extends DataSourcePluginOptionsEditorProps<MongoDataSourceOptions, MongoDataSourceSecureJsonData> { }
2622

2723
const mongoDBAuthMethods: SelectableValue[] = [
2824
{ label: 'None', value: MongoDBAuthMethod.NONE },
@@ -231,10 +227,50 @@ export function ConfigEditor(props: Props) {
231227

232228
{jsonData.authType === MongoDBAuthMethod.TLS_SSL && (
233229
<>
234-
<Label>Certificate Authority (.pem)</Label>
235-
<FileDropzone options={{ multiple: false }} onLoad={(result) => console.log(result)} />
236-
<Label>Client Certificate and Key (.pem)</Label>
237-
<FileDropzone options={{ multiple: false }} onLoad={(result) => console.log(result)} />
230+
<Field label="Certificate Authority">
231+
<Input
232+
required
233+
id="config-editor-tls-ca"
234+
value={jsonData.caCertPath}
235+
onChange={(evt: ChangeEvent<HTMLInputElement>) => onOptionsChange({
236+
...options,
237+
jsonData: {
238+
...jsonData,
239+
caCertPath: evt.target.value,
240+
},
241+
})}
242+
243+
></Input>
244+
</Field>
245+
<Field label="Client Certificate" description="Path to public client certificate (.pem)">
246+
<Input
247+
required
248+
id="config-editor-tls-cc"
249+
value={jsonData.clientCertPath}
250+
onChange={(evt: ChangeEvent<HTMLInputElement>) => onOptionsChange({
251+
...options,
252+
jsonData: {
253+
...jsonData,
254+
clientCertPath: evt.target.value,
255+
},
256+
})}
257+
258+
></Input>
259+
</Field>
260+
<Field label="Client Key" description="Path to private client key (.pem)">
261+
<Input
262+
required
263+
id="config-editor-tls-ck"
264+
value={jsonData.clientKeyPath}
265+
onChange={(evt: ChangeEvent<HTMLInputElement>) => onOptionsChange({
266+
...options,
267+
jsonData: {
268+
...jsonData,
269+
clientKeyPath: evt.target.value,
270+
},
271+
})}
272+
></Input>
273+
</Field>
238274
<Field label="Client Key Password">
239275
<SecretInput
240276
required
@@ -286,7 +322,8 @@ export function ConfigEditor(props: Props) {
286322
description="Disable the validation of the server certificates."
287323
/>
288324
</>
289-
)}
325+
)
326+
}
290327
</>
291328
);
292329
}

src/types.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,22 +50,24 @@ export interface JsQueryResult {
5050
export const MongoDBAuthMethod = {
5151
NONE: 'auth-none',
5252
USERNAME_PASSWORD: 'auth-username-password',
53-
TLS_SSL: 'auto-tls-ssl'
53+
TLS_SSL: 'auth-tls-ssl',
5454
};
5555

5656
export const ConnectionStringScheme = {
5757
STANDARD: 'standard',
5858
DNS_SEED_LIST: 'dns_seed_list',
5959
};
6060

61-
6261
export interface MongoDataSourceOptions extends DataSourceJsonData {
6362
connectionStringScheme?: string;
6463
host?: string;
6564
port?: number;
6665
database?: string;
6766
username?: string;
6867
connectionParameters?: string;
68+
caCertPath?: string;
69+
clientCertPath?: string;
70+
clientKeyPath?: string;
6971
}
7072

7173
export interface MongoDataSourceSecureJsonData {

0 commit comments

Comments
 (0)