Skip to content

Commit 7e7b506

Browse files
committed
feat: support self signed certificates
1 parent 798543b commit 7e7b506

File tree

8 files changed

+164
-12
lines changed

8 files changed

+164
-12
lines changed

README.md

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ Supported Splunk Cloud Platform and Splunk Enterprise versions:
1818

1919
## Configuration
2020

21-
| Environment Variable | Helm value | Meaning | Required | Default |
22-
|-----------------------------------------------------------|----------------------|--------------------------------------------------------------------------------------------------------------------------------------|----------|---------|
23-
| `STEADYBIT_EXTENSION_ACCESS_TOKEN` | `splunk.accessToken` | The token required to access the Splunk Cloud Platform or Splunk Enterprise. | Yes | |
24-
| `STEADYBIT_EXTENSION_API_BASE_URL` | `splunk.apiBaseUrl` | The API URL of the Splunk Cloud Platform or Splunk Enterprise instance, for example `https://<deployment-name>.splunkcloud.com:8089` | Yes | |
25-
| `STEADYBIT_EXTENSION_DISABLE_CERTIFICATE_VALIDATION` | | Disable TLS certificate validation. | No | False |
26-
| `STEADYBIT_EXTENSION_DISCOVERY_ATTRIBUTES_EXCLUDES_ALERT` | | List of Alert Attributes which will be excluded during discovery. Checked by key equality and supporting trailing "*" | No | |
21+
| Environment Variable | Helm value | Meaning | Required | Default |
22+
|-----------------------------------------------------------|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------|----------|---------|
23+
| `STEADYBIT_EXTENSION_ACCESS_TOKEN` | `splunk.accessToken` | The token required to access the Splunk Cloud Platform or Splunk Enterprise. | Yes | |
24+
| `STEADYBIT_EXTENSION_API_BASE_URL` | `splunk.apiBaseUrl` | The API URL of the Splunk Cloud Platform or Splunk Enterprise instance, for example `https://<deployment-name>.splunkcloud.com:8089` | Yes | |
25+
| `STEADYBIT_EXTENSION_INSECURE_SKIP_VERIFY` | `splunk.insecureSkipVerify` | Disable TLS certificate validation. | No | False |
26+
| `STEADYBIT_EXTENSION_DISCOVERY_ATTRIBUTES_EXCLUDES_ALERT` | | List of Alert Attributes which will be excluded during discovery. Checked by key equality and supporting trailing "*" | No | |
2727

2828
The extension supports all environment variables provided by [steadybit/extension-kit](https://github.com/steadybit/extension-kit#environment-variables).
2929

@@ -80,6 +80,45 @@ Make sure that the extension is registered with the agent. In most cases this is
8080
the [documentation](https://docs.steadybit.com/install-and-configure/install-agent/extension-registration) for more
8181
information about extension registration and how to verify.
8282

83+
84+
## Importing your own certificates
85+
86+
You may want to import your own certificates for connecting to Jenkins instances with self-signed certificates. This can be done in two ways:
87+
88+
### Option 1: Using InsecureSkipVerify
89+
90+
The extension provides the `insecureSkipVerify` option which disables TLS certificate verification. This is suitable for testing but not recommended for production environments.
91+
92+
```yaml
93+
splunk:
94+
insecureSkipVerify: true
95+
```
96+
97+
### Option 2: Mounting custom certificates
98+
99+
Mount a volume with your custom certificates and reference it in `extraVolumeMounts` and `extraVolumes` in the helm chart.
100+
101+
This example uses a config map to store the `*.crt`-files:
102+
103+
```shell
104+
kubectl create configmap -n steadybit-agent splunk-self-signed-ca --from-file=./self-signed-ca.crt
105+
```
106+
107+
```yaml
108+
extraVolumeMounts:
109+
- name: extra-certs
110+
mountPath: /etc/ssl/extra-certs
111+
readOnly: true
112+
extraVolumes:
113+
- name: extra-certs
114+
configMap:
115+
name: splunk-self-signed-ca
116+
extraEnv:
117+
- name: SSL_CERT_DIR
118+
value: /etc/ssl/extra-certs:/etc/ssl/certs
119+
```
120+
121+
83122
## Version and Revision
84123

85124
The version and revision of the extension:

charts/steadybit-extension-splunk-platform/templates/deployment.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ spec:
6969
secretKeyRef:
7070
name: {{ include "splunk.secret.name" . }}
7171
key: api-base-url
72+
- name: STEADYBIT_EXTENSION_INSECURE_SKIP_VERIFY
73+
value: "{{ .Values.splunk.insecureSkipVerify }}"
7274
{{- include "extensionlib.deployment.env" (list .) | nindent 12 }}
7375
{{- with .Values.extraEnv }}
7476
{{- toYaml . | nindent 12 }}
@@ -79,6 +81,9 @@ spec:
7981
{{- end }}
8082
volumeMounts:
8183
{{- include "extensionlib.deployment.volumeMounts" (list .) | nindent 12 }}
84+
{{- with .Values.extraVolumeMounts }}
85+
{{- toYaml . | nindent 12 }}
86+
{{- end }}
8287
livenessProbe:
8388
initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}
8489
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
@@ -103,6 +108,9 @@ spec:
103108
{{- end }}
104109
volumes:
105110
{{- include "extensionlib.deployment.volumes" (list .) | nindent 8 }}
111+
{{- with .Values.extraVolumes }}
112+
{{- toYaml . | nindent 8 }}
113+
{{- end }}
106114
serviceAccountName: {{ .Values.serviceAccount.name }}
107115
{{- with .Values.nodeSelector }}
108116
nodeSelector:

charts/steadybit-extension-splunk-platform/values.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ splunk:
55
apiBaseUrl: ""
66
# splunk.existingSecret -- If defined, will skip secret creation and instead assume that the referenced secret contains the keys api-base-url and access-token.
77
existingSecret: null
8+
# splunk.disableCertificateValidation -- If true, the extension will skip TLS verification when connecting to Splunk (for self-signed certificates)
9+
insecureSkipVerify: false
810

911
image:
1012
# image.name -- The container image to use.
@@ -133,6 +135,22 @@ extraEnv: []
133135
# name: env-secrets
134136
extraEnvFrom: []
135137

138+
# extraVolumeMounts -- Additional volumeMounts to add to the container
139+
# e.g:
140+
# extraVolumeMounts:
141+
# - name: extra-certs
142+
# mountPath: /etc/ssl/extra-certs
143+
# readOnly: true
144+
extraVolumeMounts: []
145+
146+
# extraVolumes -- Additional volumes to add to the pod
147+
# e.g:
148+
# extraVolumes:
149+
# - name: extra-certs
150+
# configMap:
151+
# name: splunk-self-signed-ca
152+
extraVolumes: []
153+
136154
discovery:
137155
attributes:
138156
excludes:

config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type Specification struct {
1212
AccessToken string `json:"accessToken" split_words:"true" required:"true"`
1313
ApiBaseUrl string `json:"apiBaseUrl" split_words:"true" required:"true"`
1414
DiscoveryAttributesExcludesAlert []string `json:"discoveryAttributesExcludesAlert" split_words:"true" required:"false"`
15-
DisableCertificateValidation bool `json:"disableCertificateValidation" split_words:"true" default:"false"`
15+
InsecureSkipVerify bool `json:"insecureSkipVerify" split_words:"true" default:"false"`
1616
}
1717

1818
var (

e2e/cert_generator_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2025 steadybit GmbH. All rights reserved.
3+
*/
4+
5+
package e2e
6+
7+
import (
8+
"crypto/rand"
9+
"crypto/rsa"
10+
"crypto/tls"
11+
"crypto/x509"
12+
"crypto/x509/pkix"
13+
"encoding/pem"
14+
"fmt"
15+
"math/big"
16+
"net"
17+
"time"
18+
)
19+
20+
// generateSelfSignedCert creates a self-signed certificate and private key
21+
func generateSelfSignedCert() (tls.Certificate, error) {
22+
// Generate a private key
23+
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
24+
if err != nil {
25+
return tls.Certificate{}, fmt.Errorf("failed to generate private key: %w", err)
26+
}
27+
28+
// Create a certificate template
29+
serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
30+
if err != nil {
31+
return tls.Certificate{}, fmt.Errorf("failed to generate serial number: %w", err)
32+
}
33+
34+
notBefore := time.Now()
35+
notAfter := notBefore.Add(365 * 24 * time.Hour) // Valid for 1 year
36+
37+
template := x509.Certificate{
38+
SerialNumber: serialNumber,
39+
Subject: pkix.Name{
40+
Organization: []string{"Steadybit Test"},
41+
CommonName: "localhost",
42+
},
43+
NotBefore: notBefore,
44+
NotAfter: notAfter,
45+
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
46+
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
47+
BasicConstraintsValid: true,
48+
DNSNames: []string{"localhost", "host.minikube.internal"},
49+
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
50+
}
51+
52+
// Create the certificate
53+
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
54+
if err != nil {
55+
return tls.Certificate{}, fmt.Errorf("failed to create certificate: %w", err)
56+
}
57+
58+
// Encode certificate and private key to PEM format
59+
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
60+
privateKeyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)})
61+
62+
// Parse the certificate and private key
63+
cert, err := tls.X509KeyPair(certPEM, privateKeyPEM)
64+
if err != nil {
65+
return tls.Certificate{}, fmt.Errorf("failed to parse certificate: %w", err)
66+
}
67+
68+
return cert, nil
69+
}

e2e/integration_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ func TestWithMinikube(t *testing.T) {
3232
Port: 8083,
3333
ExtraArgs: func(m *e2e.Minikube) []string {
3434
return []string{
35-
"--set", fmt.Sprintf("splunk.apiBaseUrl=http://host.minikube.internal:%s", port),
35+
"--set", fmt.Sprintf("splunk.apiBaseUrl=https://host.minikube.internal:%s", port),
3636
"--set", "logging.level=trace",
37+
"--set", "splunk.insecureSkipVerify=true", // Enable skipping TLS verification
3738
}
3839
},
3940
}

e2e/mock_splunk_api_test.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package e2e
55

66
import (
7+
"crypto/tls"
78
"fmt"
89
"github.com/rs/zerolog/log"
910
"github.com/steadybit/extension-kit/exthttp"
@@ -18,15 +19,31 @@ type mockServer struct {
1819
}
1920

2021
func createMockSplunkApiServer() *mockServer {
22+
// Generate self-signed certificate for TLS
23+
cert, err := generateSelfSignedCert()
24+
if err != nil {
25+
panic(fmt.Sprintf("httptest: failed to generate self-signed certificate: %v", err))
26+
}
27+
2128
listener, err := net.Listen("tcp", "0.0.0.0:0")
2229
if err != nil {
2330
panic(fmt.Sprintf("httptest: failed to listen: %v", err))
2431
}
2532
mux := http.NewServeMux()
2633

27-
server := httptest.Server{Listener: listener, Config: &http.Server{Handler: mux}}
28-
server.Start()
29-
log.Info().Str("url", server.URL).Msg("Started Mock-Server")
34+
server := httptest.Server{
35+
Listener: listener,
36+
Config: &http.Server{
37+
Handler: mux,
38+
TLSConfig: &tls.Config{},
39+
},
40+
TLS: &tls.Config{
41+
Certificates: []tls.Certificate{cert},
42+
},
43+
}
44+
45+
server.StartTLS()
46+
log.Info().Str("url", server.URL).Msg("Started Secure Mock-Server with self-signed certificate")
3047

3148
mock := &mockServer{http: &server}
3249
mux.Handle("GET /services/saved/searches", handler(mock.getSavedSearches))

extalert/common.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type SplunkClient struct {
3737

3838
func NewSplunkClient() *SplunkClient {
3939
client := resty.New()
40-
if config.Config.DisableCertificateValidation {
40+
if config.Config.InsecureSkipVerify {
4141
client.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) //NOSONAR explicit choice
4242
}
4343
client.SetBaseURL(strings.TrimRight(config.Config.ApiBaseUrl, "/"))

0 commit comments

Comments
 (0)