diff --git a/Dockerfile b/Dockerfile index f6e39cc80..297388c91 100644 --- a/Dockerfile +++ b/Dockerfile @@ -68,17 +68,17 @@ ENV AGENT_PASSWORD= # TLS setup ----------------------------------- # ENV USE_TLS=false +ENV INSECURE_SKIP_VERIFY= + +ENV CACERT_FILE= -ENV LAPI_CACERT_FILE= ENV LAPI_CERT_FILE= ENV LAPI_KEY_FILE= -ENV CLIENT_CACERT_FILE= ENV CLIENT_CERT_FILE= ENV CLIENT_KEY_FILE= # deprecated in favor of LAPI_* -ENV CACERT_FILE= ENV CERT_FILE= ENV KEY_FILE= diff --git a/Dockerfile.debian b/Dockerfile.debian index cb80551bd..7d1a245b9 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -82,17 +82,17 @@ ENV AGENT_PASSWORD= # TLS setup ----------------------------------- # ENV USE_TLS=false +ENV INSECURE_SKIP_VERIFY= + +ENV CACERT_FILE= -ENV LAPI_CACERT_FILE= ENV LAPI_CERT_FILE= ENV LAPI_KEY_FILE= -ENV CLIENT_CACERT_FILE= ENV CLIENT_CERT_FILE= ENV CLIENT_KEY_FILE= # deprecated in favor of LAPI_* -ENV CACERT_FILE= ENV CERT_FILE= ENV KEY_FILE= diff --git a/docker/README.md b/docker/README.md index 6d31e7b7b..495dca2d9 100644 --- a/docker/README.md +++ b/docker/README.md @@ -226,12 +226,12 @@ Using binds rather than named volumes ([complete explanation here](https://docs. | | | | | __TLS Auth/encryption | | | | `USE_TLS` | false | Enable TLS on the LAPI | -| `CLIENT_CERT_FILE` | /etc/ssl/cert.pem | Client TLS Certificate path | -| `CLIENT_KEY_FILE` | /etc/ssl/key.pem | Client TLS Key path | -| `CLIENT_CACERT_FILE` | | Client CA certificate bundle | -| `LAPI_CERT_FILE` | /etc/ssl/cert.pem | LAPI TLS Certificate path | -| `LAPI_KEY_FILE` | /etc/ssl/key.pem | LAPI TLS Key path | -| `LAPI_CACERT_FILE` | | LAPI CA certificate bundle | +| `CACERT_FILE` | | CA certificate bundle (optional) | +| `INSECURE_SKIP_VERIFY` | | Skip LAPI certificate validation | +| `CLIENT_CERT_FILE` | | Client TLS Certificate path (enables TLS auth) | +| `CLIENT_KEY_FILE` | | Client TLS Key path | +| `LAPI_CERT_FILE` | | LAPI TLS Certificate path (required if USE_TLS) | +| `LAPI_KEY_FILE` | | LAPI TLS Key path (required if USE_TLS) | | `AGENTS_ALLOWED_OU` | agent-ou | OU values allowed for agents, separated by comma | | `BOUNCERS_ALLOWED_OU` | bouncer-ou | OU values allowed for bouncers, separated by comma | | | | | diff --git a/docker/docker_start.sh b/docker/docker_start.sh index d9c375114..c00b508a7 100755 --- a/docker/docker_start.sh +++ b/docker/docker_start.sh @@ -90,15 +90,14 @@ cscli_if_clean() { #-----------------------------------# -if [ -n "$CERT_FILE" ] || [ -n "$KEY_FILE" ] || [ -n "$CACERT_FILE" ]; then +if [ -n "$CERT_FILE" ] || [ -n "$KEY_FILE" ] ; then printf '%b' '\033[0;33m' - echo "Warning: the variables CERT_FILE, KEY_FILE and CACERT_FILE have been deprecated." >&2 - echo "Please use LAPI_CERT_FILE, LAPI_KEY_FILE and LAPI_CACERT_FILE insted." >&2 + echo "Warning: the variables CERT_FILE and KEY_FILE have been deprecated." >&2 + echo "Please use LAPI_CERT_FILE and LAPI_KEY_FILE insted." >&2 echo "The old variables will be removed in a future release." >&2 printf '%b' '\033[0m' LAPI_CERT_FILE=${LAPI_CERT_FILE:-$CERT_FILE} LAPI_KEY_FILE=${LAPI_KEY_FILE:-$KEY_FILE} - LAPI_CACERT_FILE=${LAPI_CACERT_FILE:-$CACERT_FILE} fi # Check and prestage databases @@ -141,8 +140,24 @@ if isfalse "$DISABLE_LOCAL_API" && isfalse "$USE_TLS"; then cscli machines add "$CUSTOM_HOSTNAME" --auto --url "$LOCAL_API_URL" fi +if isfalse "$DISABLE_LOCAL_API"; then + echo "Check if lapi needs to automatically register an agent" + + # pre-registration is not needed with TLS authentication, but we can have TLS transport with user/pw + if [ "$AGENT_USERNAME" != "" ] && [ "$AGENT_PASSWORD" != "" ] ; then + # re-register because pw may have been changed + # doing this generates local_api_credentials.yaml from scratch, removing any tls setting + cscli machines add "$AGENT_USERNAME" --password "$AGENT_PASSWORD" --url "$LOCAL_API_URL" --force + echo "Agent registered to lapi" + elif isfalse "$USE_TLS"; then + echo "TLS is disabled, the AGENT_USERNAME and AGENT_PASSWORD must be set" >&2 + fi +fi + lapi_credentials_path=$(conf_get '.api.client.credentials_path') +conf_set 'with(select(strenv(INSECURE_SKIP_VERIFY)!=""); .api.client.insecure_skip_verify = env(INSECURE_SKIP_VERIFY))' + # we only use the envvars that are actually defined # in case of persistent configuration conf_set ' @@ -153,12 +168,9 @@ conf_set ' if istrue "$USE_TLS"; then conf_set ' - with(select(strenv(CLIENT_CACERT_FILE)!=""); .ca_cert_path = strenv(CLIENT_CACERT_FILE)) | - with(select(.ca_cert_path=="" or .ca_cert_path==null); .ca_cert_path = "/etc/ssl/crowdsec-client/ca.pem") | + with(select(strenv(CACERT_FILE)!=""); .ca_cert_path = strenv(CACERT_FILE)) | with(select(strenv(CLIENT_KEY_FILE)!=""); .key_path = strenv(CLIENT_KEY_FILE)) | - with(select(.key_path=="" or .key_path==null); .key_path = "/etc/ssl/crowdsec-client/key.pem") | - with(select(strenv(CLIENT_CERT_FILE)!=""); .cert_path = strenv(CLIENT_CERT_FILE)) | - with(select(.cert_path=="" or .cert_path==null); .cert_path = "/etc/ssl/crowdsec-client/cert.pem") + with(select(strenv(CLIENT_CERT_FILE)!=""); .cert_path = strenv(CLIENT_CERT_FILE)) ' "$lapi_credentials_path" else conf_set ' @@ -168,17 +180,6 @@ else ' "$lapi_credentials_path" fi -if isfalse "$DISABLE_LOCAL_API"; then - echo "Check if lapi needs to automatically register an agent" - - # pre-registration is not needed with TLS - if isfalse "$USE_TLS" && [ "$AGENT_USERNAME" != "" ] && [ "$AGENT_PASSWORD" != "" ] ; then - # re-register because pw may have been changed - cscli machines add "$AGENT_USERNAME" --password "$AGENT_PASSWORD" --url "$LOCAL_API_URL" --force - echo "Agent registered to lapi" - fi -fi - # registration to online API for signal push if isfalse "$DISABLE_ONLINE_API" && [ "$CONFIG_FILE" == "/etc/crowdsec/config.yaml" ] ; then config_exists=$(conf_get '.api.server.online_client | has("credentials_path")') @@ -217,12 +218,9 @@ if istrue "$USE_TLS"; then agents_allowed_yaml=$(csv2yaml "$AGENTS_ALLOWED_OU") \ bouncers_allowed_yaml=$(csv2yaml "$BOUNCERS_ALLOWED_OU") \ conf_set ' - with(select(strenv(LAPI_CACERT_FILE)!=""); .api.server.tls.ca_cert_path = strenv(LAPI_CACERT_FILE)) | - with(select(.api.server.tls.ca_cert_path=="" or .api.server.tls.ca_cert_path==null); .api.server.tls.ca_cert_path = "/etc/ssl/crowdsec-lapi/ca.pem") | + with(select(strenv(CACERT_FILE)!=""); .api.server.tls.ca_cert_path = strenv(CACERT_FILE)) | with(select(strenv(LAPI_CERT_FILE)!=""); .api.server.tls.cert_file = strenv(LAPI_CERT_FILE)) | - with(select(.api.server.tls.cert_file=="" or .api.server.tls.cert_file==null); .api.server.tls.cert_file = "/etc/ssl/crowdsec-lapi/cert.pem") | with(select(strenv(LAPI_KEY_FILE)!=""); .api.server.tls.key_file = strenv(LAPI_KEY_FILE)) | - with(select(.api.server.tls.key_file=="" or .api.server.tls.key_file==null); .api.server.tls.key_file = "/etc/ssl/crowdsec-lapi/key.pem") | with(select(strenv(BOUNCERS_ALLOWED_OU)!=""); .api.server.tls.bouncers_allowed_ou = env(bouncers_allowed_yaml)) | with(select(strenv(AGENTS_ALLOWED_OU)!=""); .api.server.tls.agents_allowed_ou = env(agents_allowed_yaml)) | ... comments="" diff --git a/pkg/apiclient/client.go b/pkg/apiclient/client.go index 3229d29b5..4cead4ec2 100644 --- a/pkg/apiclient/client.go +++ b/pkg/apiclient/client.go @@ -54,8 +54,8 @@ func NewClient(config *Config) (*ApiClient, error) { NbRetry: 0, } tlsconfig := tls.Config{InsecureSkipVerify: InsecureSkipVerify} + tlsconfig.RootCAs = CaCertPool if Cert != nil { - tlsconfig.RootCAs = CaCertPool tlsconfig.Certificates = []tls.Certificate{*Cert} } http.DefaultTransport.(*http.Transport).TLSClientConfig = &tlsconfig @@ -76,8 +76,8 @@ func NewDefaultClient(URL *url.URL, prefix string, userAgent string, client *htt client = &http.Client{} if ht, ok := http.DefaultTransport.(*http.Transport); ok { tlsconfig := tls.Config{InsecureSkipVerify: InsecureSkipVerify} + tlsconfig.RootCAs = CaCertPool if Cert != nil { - tlsconfig.RootCAs = CaCertPool tlsconfig.Certificates = []tls.Certificate{*Cert} } ht.TLSClientConfig = &tlsconfig diff --git a/pkg/csconfig/api.go b/pkg/csconfig/api.go index 1b4efa68c..5574d75aa 100644 --- a/pkg/csconfig/api.go +++ b/pkg/csconfig/api.go @@ -82,7 +82,7 @@ func (l *LocalApiClientCfg) Load() error { } } - if l.Credentials.Login != "" && (l.Credentials.CACertPath != "" || l.Credentials.CertPath != "" || l.Credentials.KeyPath != "") { + if l.Credentials.Login != "" && (l.Credentials.CertPath != "" || l.Credentials.KeyPath != "") { return fmt.Errorf("user/password authentication and TLS authentication are mutually exclusive") } @@ -92,12 +92,7 @@ func (l *LocalApiClientCfg) Load() error { apiclient.InsecureSkipVerify = *l.InsecureSkipVerify } - if l.Credentials.CACertPath != "" && l.Credentials.CertPath != "" && l.Credentials.KeyPath != "" { - cert, err := tls.LoadX509KeyPair(l.Credentials.CertPath, l.Credentials.KeyPath) - if err != nil { - return errors.Wrapf(err, "failed to load api client certificate") - } - + if l.Credentials.CACertPath != "" { caCert, err := os.ReadFile(l.Credentials.CACertPath) if err != nil { return errors.Wrapf(err, "failed to load cacert") @@ -105,10 +100,18 @@ func (l *LocalApiClientCfg) Load() error { caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) - - apiclient.Cert = &cert apiclient.CaCertPool = caCertPool } + + if l.Credentials.CertPath != "" && l.Credentials.KeyPath != "" { + cert, err := tls.LoadX509KeyPair(l.Credentials.CertPath, l.Credentials.KeyPath) + if err != nil { + return errors.Wrapf(err, "failed to load api client certificate") + } + + apiclient.Cert = &cert + } + return nil }