feat: support tls configuration
This commit is contained in:
parent
44d57f9d88
commit
c81b4df0f1
42
README.md
42
README.md
|
@ -70,6 +70,48 @@ then it's up and healthy. If the value is 0, then it's down.
|
||||||
`uptime_latency_seconds` indicates the time it took to do a HTTP request to that specified `endpoint_address`
|
`uptime_latency_seconds` indicates the time it took to do a HTTP request to that specified `endpoint_address`
|
||||||
field in second.
|
field in second.
|
||||||
|
|
||||||
|
## Configuration file schema
|
||||||
|
|
||||||
|
If you want to do config.json.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"name": "string",
|
||||||
|
"address": "https://url",
|
||||||
|
"method": "GET",
|
||||||
|
"timeout": 123,
|
||||||
|
"successful_status_code": "2xx",
|
||||||
|
"inverse_status": false,
|
||||||
|
"tls_configuration": {
|
||||||
|
"certificate_authority_path": "/path/to/certificate_authority.pem",
|
||||||
|
"client_certificate_path": "/path/to/client_certificate.pem",
|
||||||
|
"client_key_path": "/path/to/client_key.pem",
|
||||||
|
"insecure_skip_verify": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to do config.yaml (or .yml if you prefer).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
endpoints:
|
||||||
|
- name: "string"
|
||||||
|
address: "https://url"
|
||||||
|
method: "GET"
|
||||||
|
timeout: 123
|
||||||
|
successful_status_code: 2xx
|
||||||
|
inverse_status: false
|
||||||
|
tls_configuration:
|
||||||
|
certificate_authority_path: "/path/to/certificate_authority.pem",
|
||||||
|
client_certificate_path: "/path/to/client_certificate.pem",
|
||||||
|
client_key_path: "/path/to/client_key.pem",
|
||||||
|
insecure_skip_verify: true
|
||||||
|
```
|
||||||
|
|
||||||
## Build from source
|
## Build from source
|
||||||
|
|
||||||
Install [Go](https://go.dev/dl).
|
Install [Go](https://go.dev/dl).
|
||||||
|
|
102
config.go
102
config.go
|
@ -22,15 +22,105 @@
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
Endpoints []Endpoint `required:"true"`
|
Endpoints []Endpoint `required:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Endpoint struct {
|
type Endpoint struct {
|
||||||
Name string `required:"true"`
|
Name string `required:"true"`
|
||||||
Address string `required:"true"`
|
Address string `required:"true"`
|
||||||
Method string `required:"false" default:"GET"`
|
Method string `required:"false" default:"GET"`
|
||||||
Timeout uint16 `required:"false" default:"30"`
|
Timeout uint16 `required:"false" default:"30"`
|
||||||
SuccessfulStatusCode string `required:"false" default:"2xx"`
|
SuccessfulStatusCode string `required:"false" default:"2xx" yaml:"successful_status_code" json:"successful_status_code" toml:"successful_status_code"`
|
||||||
InverseStatus bool `required:"false" default:"false"`
|
InverseStatus bool `required:"false" default:"false" yaml:"inverse_status" json:"inverse_status" toml:"inverse_status"`
|
||||||
|
TLSConfiguration TLSConfiguration `required:"false" yaml:"tls_configuration" json:"tls_configuration" toml:"tls_configuration"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TLSConfiguration struct {
|
||||||
|
CertificateAuthorityPath string `required:"false" yaml:"certificate_authority_path" json:"certificate_authority_path" toml:"certificate_authority_path"`
|
||||||
|
ClientCertificatePath string `required:"false" yaml:"client_certificate_path" json:"client_certificate_path" toml:"client_certificate_path"`
|
||||||
|
ClientKeyPath string `required:"false" yaml:"client_key_path" json:"client_key_path" toml:"client_key_path"`
|
||||||
|
InsecureSkipVerify bool `required:"false" default:"false" yaml:"insecure_skip_verify" json:"insecure_skip_verify" toml:"insecure_skip_verify"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PreprocessedEndpoint struct {
|
||||||
|
Name string
|
||||||
|
Address string
|
||||||
|
Method string
|
||||||
|
Timeout uint16
|
||||||
|
SuccessfulStatusCode string
|
||||||
|
InverseStatus bool
|
||||||
|
TLSConfiguration PreproccessedTLSConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
type PreproccessedTLSConfiguration struct {
|
||||||
|
Certificates []tls.Certificate
|
||||||
|
RootCA *x509.CertPool
|
||||||
|
InsecureSkipVerify bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func processConfiguration(endpoints []Endpoint) ([]PreprocessedEndpoint, error) {
|
||||||
|
var preprocessedEndpoints []PreprocessedEndpoint
|
||||||
|
|
||||||
|
for _, endpoint := range endpoints {
|
||||||
|
var certificates []tls.Certificate = nil
|
||||||
|
var rootCA *x509.CertPool = nil
|
||||||
|
|
||||||
|
if endpoint.TLSConfiguration.CertificateAuthorityPath != "" {
|
||||||
|
// Read CA file
|
||||||
|
file, err := os.ReadFile(endpoint.TLSConfiguration.CertificateAuthorityPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("reading certificate authority file: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
rootCA = x509.NewCertPool()
|
||||||
|
ok := rootCA.AppendCertsFromPEM(file)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("invalid pem format for certificate authority")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if endpoint.TLSConfiguration.ClientCertificatePath != "" && endpoint.TLSConfiguration.ClientKeyPath != "" {
|
||||||
|
// Read certificate file
|
||||||
|
certificateFile, err := os.ReadFile(endpoint.TLSConfiguration.ClientCertificatePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("reading certificate file: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
keyFile, err := os.ReadFile(endpoint.TLSConfiguration.ClientKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("reading key file: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
certificate, err := tls.X509KeyPair(certificateFile, keyFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("creating x509 key pair: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
certificates = append(certificates, certificate)
|
||||||
|
}
|
||||||
|
|
||||||
|
preprocessedEndpoints = append(preprocessedEndpoints, PreprocessedEndpoint{
|
||||||
|
Name: endpoint.Name,
|
||||||
|
Address: endpoint.Address,
|
||||||
|
Method: endpoint.Method,
|
||||||
|
Timeout: endpoint.Timeout,
|
||||||
|
SuccessfulStatusCode: endpoint.SuccessfulStatusCode,
|
||||||
|
InverseStatus: endpoint.InverseStatus,
|
||||||
|
TLSConfiguration: PreproccessedTLSConfiguration{
|
||||||
|
Certificates: certificates,
|
||||||
|
RootCA: rootCA,
|
||||||
|
InsecureSkipVerify: endpoint.TLSConfiguration.InsecureSkipVerify,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return preprocessedEndpoints, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,9 @@
|
||||||
endpoints:
|
endpoints:
|
||||||
- name: "GitHub"
|
- name: "GitHub"
|
||||||
address: https://github.com/healthz
|
address: https://github.com/healthz
|
||||||
|
tls_configuration:
|
||||||
|
insecure_skip_verify: true
|
||||||
|
|
||||||
- name: "Reinaldy"
|
- name: "Reinaldy"
|
||||||
address: https://code.reinaldyrafli.com
|
address: https://code.reinaldyrafli.com
|
||||||
timeout: 60
|
timeout: 60
|
||||||
|
|
12
exporter.go
12
exporter.go
|
@ -24,6 +24,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -54,7 +55,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Exporter struct {
|
type Exporter struct {
|
||||||
Endpoints []Endpoint
|
Endpoints []PreprocessedEndpoint
|
||||||
Logger *onelog.Logger
|
Logger *onelog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +107,7 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
||||||
wg.Add(len(e.Endpoints))
|
wg.Add(len(e.Endpoints))
|
||||||
|
|
||||||
for _, endpoint := range e.Endpoints {
|
for _, endpoint := range e.Endpoints {
|
||||||
go func(endpoint Endpoint) {
|
go func(endpoint PreprocessedEndpoint) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
// Create HTTP calls
|
// Create HTTP calls
|
||||||
|
@ -118,6 +119,13 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
|
||||||
httpClient := http.Client{
|
httpClient := http.Client{
|
||||||
Timeout: time.Duration(uint64(endpoint.Timeout) * 1e+9),
|
Timeout: time.Duration(uint64(endpoint.Timeout) * 1e+9),
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
Certificates: endpoint.TLSConfiguration.Certificates,
|
||||||
|
RootCAs: endpoint.TLSConfiguration.RootCA,
|
||||||
|
InsecureSkipVerify: endpoint.TLSConfiguration.InsecureSkipVerify,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := httpClient.Do(request)
|
response, err := httpClient.Do(request)
|
||||||
|
|
11
main.go
11
main.go
|
@ -49,14 +49,21 @@ func main() {
|
||||||
var config Configuration
|
var config Configuration
|
||||||
err := configor.Load(&config, *configFile)
|
err := configor.Load(&config, *configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preprocessedConfig, err := processConfiguration(config.Endpoints)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("%+v", preprocessedConfig)
|
||||||
|
|
||||||
// Initiate the logger instance. It should be zero-allocated, so we'll use onelog
|
// Initiate the logger instance. It should be zero-allocated, so we'll use onelog
|
||||||
logger := onelog.New(os.Stdout, onelog.ALL)
|
logger := onelog.New(os.Stdout, onelog.ALL)
|
||||||
|
|
||||||
exporter := &Exporter{
|
exporter := &Exporter{
|
||||||
Endpoints: config.Endpoints,
|
Endpoints: preprocessedConfig,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue