-
Notifications
You must be signed in to change notification settings - Fork 204
Description
The Elastic Agent can receive porxy and TLS configuration for fleet-server thorough its CLI, during install/enroll, and the policy. The configurations from the policy take precedence over the CLI, however and empty configuration from the policy does not changes the current configuration.
If the Elastic Agent is installed with a proxy using mTLS and the policy has another proxy configured with simple/one way TLS, the agent will apply the new proxy and CA, but keep the old certificate, certificate key and key passphrase/key passphrase path. Letting the agent on an inconsistent state. Such state might even lead to a failure to start if the old certificate-related configurations are files and the files are removed. If it happens, on start up, the agent will try to load those files and fail, preventing the agent from starting.
The culprit is
elastic-agent/internal/pkg/agent/application/actions/handlers/handler_action_policy_change.go
Lines 201 to 264 in 0580e53
| func updateFleetConfig(log *logger.Logger, policyConfig remote.Config, agentConfig *remote.Config) { | |
| // Hosts is the only connectivity field sent Fleet, let's clear everything else aside from Hosts | |
| if len(policyConfig.Hosts) > 0 { | |
| agentConfig.Hosts = make([]string, len(policyConfig.Hosts)) | |
| copy(agentConfig.Hosts, policyConfig.Hosts) | |
| agentConfig.Host = "" | |
| agentConfig.Protocol = "" | |
| agentConfig.Path = "" | |
| } | |
| // Empty proxies from fleet are ignored. That way a proxy set by --proxy-url | |
| // it won't be overridden by an absent or empty proxy from fleet-server. | |
| // However, if there is a proxy sent by fleet-server, it'll take precedence. | |
| // Therefore, it's not possible to remove a proxy once it's set. | |
| if policyConfig.Transport.Proxy.URL == nil || | |
| policyConfig.Transport.Proxy.URL.String() == "" { | |
| log.Debugw("proxy from fleet is empty or null, the proxy will not be changed", "current_proxy", agentConfig.Transport.Proxy.URL) | |
| } else { | |
| log.Debugw("received proxy from fleet, applying it", "old_proxy", agentConfig.Transport.Proxy.URL, "new_proxy", policyConfig.Transport.Proxy.URL) | |
| // copy the proxy struct | |
| agentConfig.Transport.Proxy = policyConfig.Transport.Proxy | |
| // replace in agentConfig the attributes that are passed by reference within the proxy struct | |
| // Headers map | |
| agentConfig.Transport.Proxy.Headers = map[string]string{} | |
| for k, v := range policyConfig.Transport.Proxy.Headers { | |
| agentConfig.Transport.Proxy.Headers[k] = v | |
| } | |
| // Proxy URL | |
| urlCopy := *policyConfig.Transport.Proxy.URL | |
| agentConfig.Transport.Proxy.URL = &urlCopy | |
| } | |
| if policyConfig.Transport.TLS != nil { | |
| tlsCopy := tlscommon.Config{} | |
| if agentConfig.Transport.TLS != nil { | |
| // copy the TLS struct | |
| tlsCopy = *agentConfig.Transport.TLS | |
| } | |
| if policyConfig.Transport.TLS.Certificate == emptyCertificateConfig() { | |
| log.Debug("TLS certificates from fleet are empty or null, the TLS config will not be changed") | |
| } else { | |
| tlsCopy.Certificate = policyConfig.Transport.TLS.Certificate | |
| log.Debug("received TLS certificate/key from fleet, applying it") | |
| } | |
| if len(policyConfig.Transport.TLS.CAs) == 0 { | |
| log.Debug("TLS CAs from fleet are empty or null, the TLS config will not be changed") | |
| } else { | |
| tlsCopy.CAs = make([]string, len(policyConfig.Transport.TLS.CAs)) | |
| copy(tlsCopy.CAs, policyConfig.Transport.TLS.CAs) | |
| log.Debug("received TLS CAs from fleet, applying it") | |
| } | |
| agentConfig.Transport.TLS = &tlsCopy | |
| } | |
| } |
which handles the proxy, TLS Certificate and the TLS CA configurations as different entities, when they should be treated as one.
In other words, if either change, the proxy or the TLS certificate or the CAs, they all should be replaced. If there is any change in policyConfig.Transport, apply the whole new Transport. Right now as proxy, TLS certificate and CA are handled separately, if the CLI defines a proxy with mTLS and the policy has another proxy with one way TLS, the result config will be a mix of both instead of only the new proxy with one way TLS. The expected result is to have the new proxy URL+headers and the CAs, but the certificate and certificate key must be cleared.
For confirmed bugs, please report:
- Version: 8.16, main
- Operating System: all
- Discuss Forum URL: N/A
- Steps to Reproduce:
- add a HTTPS proxy on fleetUI with its CA
- add this proxy to a fleet host
- enroll the agent passing a different proxy with mTLS
- after the agent is successfully enrolled and applied the policy from fleet-server, run the
inspectcommand - observer the agent has the new proxy and CA, but kept the old certificate, certificate key and passphrase (if set)