Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(config/server): Add option for TLS and mTLS server #508

Merged
merged 2 commits into from
Jun 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,17 @@ customfields: # custom fields are added to falco events, if the value starts wit
templatedfields: # templated fields are added to falco events and metrics, it uses Go template + output_fields values
# Dkey: '{{ or (index . "k8s.ns.labels.foo") "bar" }}'
# bracketreplacer: "_" # if not empty, replace the brackets in keys of Output Fields
mutualtlsfilespath: "/etc/certs" # folder which will used to store client.crt, client.key and ca.crt files for mutual tls (default: "/etc/certs")
mutualtlsfilespath: "/etc/certs" # folder which will used to store client.crt, client.key and ca.crt files for mutual tls for outputs, will be deprecated in the future (default: "/etc/certs")
mutualtlsclient: # takes priority over mutualtlsfilespath if not emtpy
certfile: "/etc/certs/client/client.crt" # client certification file
keyfile: "/etc/certs/client/client.key" # client key
cacertfile: "/etc/certs/client/ca.crt" # for server certification
tlsserver:
deploy: false # if true, TLS server will be deployed instead of HTTP
certfile: "/etc/certs/server/server.crt" # server certification file
keyfile: "/etc/certs/server/server.key" # server key
mutualtls: false # if true, mTLS server will be deployed instead of TLS, deploy also has to be true
cacertfile: "/etc/certs/server/ca.crt" # for client certification if mutualtls is true

slack:
webhookurl: "" # Slack WebhookURL (ex: https://hooks.slack.com/services/XXXX/YYYY/ZZZZ), if not empty, Slack output is enabled
Expand Down Expand Up @@ -642,7 +652,15 @@ care of lower/uppercases**) : `yaml: a.b --> envvar: A_B` :
events, syntax is "key:value,key:value"
- **TEMPLATEDFIELDS** : templated fields are added to falco events and metrics, it uses Go template + output_fields values
- **BRACKETREPLACER** : if not empty, the brackets in keys of Output Fields are replaced
- **MUTUALTLSFILESPATH**: path which will be used to stored certs and key for mutual tls authentication (default: "/etc/certs")
- **MUTUALTLSFILESPATH**: path which will be used to stored certs and key for mutual TLS authentication, will be deprecated in the future (default: "/etc/certs")
- **MUTUALTLSCLIENT_CERTFILE**: client certification file for mutual TLS client certification, takes priority over MUTUALTLSFILESPATH if not empty
- **MUTUALTLSCLIENT_KEYFILE**: client key file for mutual TLS client certification, takes priority over MUTUALTLSFILESPATH if not empty
- **MUTUALTLSCLIENT_CACERTFILE**: CA certification file for server certification for mutual TLS authentication, takes priority over MUTUALTLSFILESPATH if not empty
- **TLSSERVER_DEPLOY**: if _true_ TLS server will be deployed instead of HTTP
- **TLSSERVER_CERTFILE**: server certification file for TLS Server (default: "/etc/certs/server/server.crt")
- **TLSSERVER_KEYFILE**: server key file for TLS Server (default: "/etc/certs/server/server.key")
- **TLSSERVER_MUTUALTLS**: if _true_ mutual TLS server will be deployed instead of TLS, deploy also has to be true
- **TLSSERVER_CACERTFILE**: CA certification file for client certification if TLSSERVER_MUTUALTLS is _true_ (default: "/etc/certs/server/ca.crt")
- **SLACK_WEBHOOKURL** : Slack Webhook URL (ex: https://hooks.slack.com/services/XXXX/YYYY/ZZZZ)
- **SLACK_CHANNEL** : Slack Channel (optionnal)
- **SLACK_FOOTER** : Slack footer
Expand Down Expand Up @@ -1161,7 +1179,13 @@ All logs are sent to `stdout`.

## Mutual TLS ##

Outputs with `mutualtls` enabled in their configuration require *client.crt*, *client.key* and *ca.crt* files to be stored in the path configured in **mutualtlsfilespath** global parameter (**important**: file names must be preserved)
Outputs with `mutualtls` enabled in their configuration require the *client.crt*, *client.key* and *ca.crt* filepaths to be configured in the **mutualtlsclient_certfile**, **mutualtlsclient_keyfile** and **mutualtlsclient_cacertfile** global parameter.

```bash
docker run -d -p 2801:2801 -e MUTUALTLSCLIENT_CERTFILE=/etc/certs/client/client.crt -e MUTUALTLSCLIENT_KEYFILE=/etc/certs/client/client.key -e MUTUALTLSCLIENT_CACERTFILE=/etc/certs/client/ca.crt -e ALERTMANAGER_HOSTPORT=https://XXXX -e ALERTMANAGER_MUTUALTLS=true -e INFLUXDB_HOSTPORT=https://XXXX -e INFLUXDB_MUTUALTLS=true -e WEBHOOK_ADDRESS=XXXX -v /localpath/myclientcert.crt:/etc/certs/client/client.crt -v /localpath/myclientkey.key:/etc/certs/client/client.key -v /localpath/ca.crt:/etc/certs/client/ca.crt falcosecurity/falcosidekick
```

Alternately the path where the *client.crt*, *client.key* and *ca.crt* files are stored can be configured in **mutualtlsfilespath** global parameter. (**Important**: file names must be preserved)

```bash
docker run -d -p 2801:2801 -e MUTUALTLSFILESPATH=/etc/certs -e ALERTMANAGER_HOSTPORT=https://XXXX -e ALERTMANAGER_MUTUALTLS=true -e INFLUXDB_HOSTPORT=https://XXXX -e INFLUXDB_MUTUALTLS=true -e WEBHOOK_ADDRESS=XXXX -v /localpath/myclientcert.crt:/etc/certs/client.crt -v /localpath/myclientkey.key:/etc/certs/client.key -v /localpath/ca.crt:/etc/certs/ca.crt falcosecurity/falcosidekick
Expand Down
9 changes: 9 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ func getConfig() *types.Configuration {
v.SetDefault("Debug", false)
v.SetDefault("BracketReplacer", "")
v.SetDefault("MutualTlsFilesPath", "/etc/certs")
v.SetDefault("MutualTLSClient.CertFile", "")
v.SetDefault("MutualTLSClient.KeyFile", "")
v.SetDefault("MutualTLSClient.CaCertFile", "")

v.SetDefault("TLSServer.Deploy", false)
v.SetDefault("TLSServer.CertFile", "/etc/certs/server/server.crt")
v.SetDefault("TLSServer.KeyFile", "/etc/certs/server/server.key")
v.SetDefault("TLSServer.MutualTLS", false)
v.SetDefault("TLSServer.CaCertFile", "/etc/certs/server/ca.crt")

v.SetDefault("Slack.WebhookURL", "")
v.SetDefault("Slack.Footer", "https://github.com/falcosecurity/falcosidekick")
Expand Down
12 changes: 11 additions & 1 deletion config_example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@ customfields: # custom fields are added to falco events and metrics, if the valu
templatedfields: # templated fields are added to falco events and metrics, it uses Go template + output_fields values
# Dkey: '{{ or (index . "k8s.ns.labels.foo") "bar" }}'
# bracketreplacer: "_" # if not empty, the brackets in keys of Output Fields are replaced
mutualtlsfilespath: "/etc/certs" # folder which will used to store client.crt, client.key and ca.crt files for mutual tls (default: "/etc/certs")
mutualtlsfilespath: "/etc/certs" # folder which will used to store client.crt, client.key and ca.crt files for mutual tls for outputs, will be deprecated in the future (default: "/etc/certs")
mutualtlsclient: # takes priority over mutualtlsfilespath if not emtpy
certfile: "/etc/certs/client/client.crt" # client certification file
keyfile: "/etc/certs/client/client.key" # client key
cacertfile: "/etc/certs/client/ca.crt" # for server certification
tlsserver:
deploy: false # if true, TLS server will be deployed instead of HTTP
certfile: "/etc/certs/server/server.crt" # server certification file
keyfile: "/etc/certs/server/server.key" # server key
mutualtls: false # if true, mTLS server will be deployed instead of TLS, deploy also has to be true
cacertfile: "/etc/certs/server/ca.crt" # for client certification if mutualtls is true


slack:
Expand Down
44 changes: 42 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package main

import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
Expand Down Expand Up @@ -729,7 +732,44 @@ func main() {
IdleTimeout: 60 * time.Second,
}

if err := server.ListenAndServe(); err != nil {
log.Fatalf("[ERROR] : %v", err.Error())
if config.TLSServer.Deploy {
if config.TLSServer.MutualTLS {
if config.Debug {
log.Printf("[DEBUG] : running mTLS server")
}

caCert, err := ioutil.ReadFile(config.TLSServer.CaCertFile)
if err != nil {
log.Printf("[ERROR] : %v\n", err.Error())
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)

server.TLSConfig = &tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert,
RootCAs: caCertPool,
MinVersion: tls.VersionTLS12,
}
}

if config.Debug && !config.TLSServer.MutualTLS {
log.Printf("[DEBUG] : running TLS server")
}

if err := server.ListenAndServeTLS(config.TLSServer.CertFile, config.TLSServer.KeyFile); err != nil {
log.Fatalf("[ERROR] : %v", err.Error())
}
} else {
if config.Debug {
log.Printf("[DEBUG] : running HTTP server")
}

if config.TLSServer.MutualTLS {
log.Printf("[WARN] : tlsserver.deploy is false but tlsserver.mutualtls is true, change tlsserver.deploy to true to use mTLS")
}

if err := server.ListenAndServe(); err != nil {
log.Fatalf("[ERROR] : %v", err.Error())
}
}
}
20 changes: 18 additions & 2 deletions outputs/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,29 @@ func (c *Client) sendRequest(method string, payload interface{}) error {

if c.MutualTLSEnabled {
// Load client cert
cert, err := tls.LoadX509KeyPair(c.Config.MutualTLSFilesPath+MutualTLSClientCertFilename, c.Config.MutualTLSFilesPath+MutualTLSClientKeyFilename)
var MutualTLSClientCertPath, MutualTLSClientKeyPath, MutualTLSClientCaCertPath string
if c.Config.MutualTLSClient.CertFile != "" {
MutualTLSClientCertPath = c.Config.MutualTLSClient.CertFile
} else {
MutualTLSClientCertPath = c.Config.MutualTLSFilesPath + MutualTLSClientCertFilename
}
if c.Config.MutualTLSClient.KeyFile != "" {
MutualTLSClientKeyPath = c.Config.MutualTLSClient.KeyFile
} else {
MutualTLSClientKeyPath = c.Config.MutualTLSFilesPath + MutualTLSClientKeyFilename
}
if c.Config.MutualTLSClient.CaCertFile != "" {
MutualTLSClientCaCertPath = c.Config.MutualTLSClient.CaCertFile
} else {
MutualTLSClientCaCertPath = c.Config.MutualTLSFilesPath + MutualTLSCacertFilename
}
cert, err := tls.LoadX509KeyPair(MutualTLSClientCertPath, MutualTLSClientKeyPath)
if err != nil {
log.Printf("[ERROR] : %v - %v\n", c.OutputType, err.Error())
}

// Load CA cert
caCert, err := ioutil.ReadFile(c.Config.MutualTLSFilesPath + MutualTLSCacertFilename)
caCert, err := ioutil.ReadFile(MutualTLSClientCaCertPath)
if err != nil {
log.Printf("[ERROR] : %v - %v\n", c.OutputType, err.Error())
}
Expand Down
13 changes: 8 additions & 5 deletions outputs/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,10 @@ func TestHeadersResetAfterReq(t *testing.T) {

func TestMutualTlsPost(t *testing.T) {
config := &types.Configuration{}
config.MutualTLSFilesPath = "/tmp/falcosidekicktests"
config.MutualTLSFilesPath = "/tmp/falcosidekicktests/client"
config.MutualTLSClient.CertFile = "/tmp/falcosidekicktests/client/client.crt"
config.MutualTLSClient.KeyFile = "/tmp/falcosidekicktests/client/client.key"
config.MutualTLSClient.CaCertFile = "/tmp/falcosidekicktests/client/ca.crt"
// delete folder to avoid makedir failure
os.RemoveAll(config.MutualTLSFilesPath)

Expand Down Expand Up @@ -212,7 +215,7 @@ func TestMutualTlsPost(t *testing.T) {
}

func certsetup(config *types.Configuration) (serverTLSConf *tls.Config, err error) {
err = os.Mkdir(config.MutualTLSFilesPath, 0755)
err = os.MkdirAll(config.MutualTLSFilesPath, 0755)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -256,7 +259,7 @@ func certsetup(config *types.Configuration) (serverTLSConf *tls.Config, err erro
})

// save ca to ca.crt file (it will be used by Client)
err = ioutil.WriteFile(config.MutualTLSFilesPath+"/ca.crt", caPEM.Bytes(), 0600)
err = ioutil.WriteFile(config.MutualTLSClient.CaCertFile, caPEM.Bytes(), 0600)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -356,7 +359,7 @@ func certsetup(config *types.Configuration) (serverTLSConf *tls.Config, err erro
})

// save client cert and key to client.crt and client.key
err = ioutil.WriteFile(config.MutualTLSFilesPath+"/client.crt", clientCertPEM.Bytes(), 0600)
err = ioutil.WriteFile(config.MutualTLSClient.CertFile, clientCertPEM.Bytes(), 0600)
if err != nil {
return nil, err
}
Expand All @@ -365,7 +368,7 @@ func certsetup(config *types.Configuration) (serverTLSConf *tls.Config, err erro
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(clientCertPrivKey),
})
err = ioutil.WriteFile(config.MutualTLSFilesPath+"/client.key", clientCertPrivKeyPEM.Bytes(), 0600)
err = ioutil.WriteFile(config.MutualTLSClient.KeyFile, clientCertPrivKeyPEM.Bytes(), 0600)
if err != nil {
return nil, err
}
Expand Down
18 changes: 18 additions & 0 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ func (f FalcoPayload) Check() bool {
// Configuration is a struct to store configuration
type Configuration struct {
MutualTLSFilesPath string
MutualTLSClient MutualTLSClient
TLSServer TLSServer
Debug bool
ListenAddress string
ListenPort int
Expand Down Expand Up @@ -104,6 +106,22 @@ type Configuration struct {
N8N N8NConfig
}

// MutualTLSClient represents parameters for mutual TLS as client
type MutualTLSClient struct {
CertFile string
KeyFile string
CaCertFile string
}

// TLSServer represents parameters for TLS Server
type TLSServer struct {
Deploy bool
CertFile string
KeyFile string
MutualTLS bool
CaCertFile string
}

// SlackOutputConfig represents parameters for Slack
type SlackOutputConfig struct {
WebhookURL string
Expand Down
Loading