diff --git a/orbit/cmd/desktop/desktop.go b/orbit/cmd/desktop/desktop.go index a2f5fdccac..dd1c05f9e2 100644 --- a/orbit/cmd/desktop/desktop.go +++ b/orbit/cmd/desktop/desktop.go @@ -64,10 +64,9 @@ func main() { if os.Getenv("FLEET_DESKTOP_INSECURE") != "" { insecureSkipVerify = true } + rootCA := os.Getenv("FLEET_DESKTOP_FLEET_ROOT_CA") - // TODO: figure out the right rootCA to pass to the client - client, err := service.NewDeviceClient(basePath, deviceToken, insecureSkipVerify, "") - + client, err := service.NewDeviceClient(basePath, deviceToken, insecureSkipVerify, rootCA) if err != nil { log.Fatal().Err(err).Msg("unable to initialize request client") } @@ -175,7 +174,7 @@ func setupLogs() { dir = filepath.Join(dir, "Fleet") - if err := os.MkdirAll(dir, 0755); err != nil { + if err := os.MkdirAll(dir, 0o755); err != nil { log.Logger = log.Output(stderrOut) log.Error().Err(err).Msg("make directories for log files") return diff --git a/orbit/cmd/orbit/orbit.go b/orbit/cmd/orbit/orbit.go index 21dd77796a..87975d0a89 100644 --- a/orbit/cmd/orbit/orbit.go +++ b/orbit/cmd/orbit/orbit.go @@ -497,7 +497,7 @@ func main() { registerExtensionRunner(&g, r.ExtensionSocketPath(), deviceAuthToken) if c.Bool("fleet-desktop") { - desktopRunner := newDesktopRunner(desktopPath, fleetURL, deviceAuthToken, c.Bool("insecure")) + desktopRunner := newDesktopRunner(desktopPath, fleetURL, deviceAuthToken, c.String("fleet-certificate"), c.Bool("insecure")) g.Add(desktopRunner.actor()) } @@ -529,16 +529,18 @@ type desktopRunner struct { desktopPath string fleetURL string deviceAuthToken string + fleetRootCA string insecure bool interruptCh chan struct{} // closed when interrupt is triggered executeDoneCh chan struct{} // closed when execute returns } -func newDesktopRunner(desktopPath, fleetURL, deviceAuthToken string, insecure bool) *desktopRunner { +func newDesktopRunner(desktopPath, fleetURL, deviceAuthToken, fleetRootCA string, insecure bool) *desktopRunner { return &desktopRunner{ desktopPath: desktopPath, fleetURL: fleetURL, deviceAuthToken: deviceAuthToken, + fleetRootCA: fleetRootCA, insecure: insecure, interruptCh: make(chan struct{}), executeDoneCh: make(chan struct{}), @@ -570,6 +572,9 @@ func (d *desktopRunner) execute() error { opts := []execuser.Option{ execuser.WithEnv("FLEET_DESKTOP_DEVICE_URL", url.String()), } + if d.fleetRootCA != "" { + opts = append(opts, execuser.WithEnv("FLEET_DESKTOP_FLEET_ROOT_CA", d.fleetRootCA)) + } if d.insecure { opts = append(opts, execuser.WithEnv("FLEET_DESKTOP_INSECURE", "1")) } diff --git a/server/service/base_client.go b/server/service/base_client.go index 0a2991ed20..4f2d02b1eb 100644 --- a/server/service/base_client.go +++ b/server/service/base_client.go @@ -76,31 +76,38 @@ func newBaseClient(addr string, insecureSkipVerify bool, rootCA, urlPrefix strin } rootCAPool := x509.NewCertPool() - if rootCA != "" { + + tlsConfig := &tls.Config{ + // Osquery itself requires >= TLS 1.2. + // https://github.com/osquery/osquery/blob/9713ad9e28f1cfe6c16a823fb88bd531e39e192d/osquery/remote/transports/tls.cpp#L97-L98 + MinVersion: tls.VersionTLS12, + } + + switch { + case rootCA != "": // read in the root cert file specified in the context certs, err := ioutil.ReadFile(rootCA) if err != nil { return nil, fmt.Errorf("reading root CA: %w", err) } - // add certs to pool if ok := rootCAPool.AppendCertsFromPEM(certs); !ok { return nil, errors.New("failed to add certificates to root CA pool") } - } else if !insecureSkipVerify { + tlsConfig.RootCAs = rootCAPool + case insecureSkipVerify: + // Ignoring "G402: TLS InsecureSkipVerify set true", needed for development/testing. + tlsConfig.InsecureSkipVerify = true //nolint:gosec + default: // Use only the system certs (doesn't work on Windows) rootCAPool, err = x509.SystemCertPool() if err != nil { return nil, fmt.Errorf("loading system cert pool: %w", err) } + tlsConfig.RootCAs = rootCAPool } - httpClient := fleethttp.NewClient(fleethttp.WithTLSClientConfig(&tls.Config{ - // Ignoring "G402: TLS InsecureSkipVerify set true", needed for development/testing. - InsecureSkipVerify: insecureSkipVerify, //nolint:gosec - RootCAs: rootCAPool, - })) - + httpClient := fleethttp.NewClient(fleethttp.WithTLSClientConfig(tlsConfig)) client := &baseClient{ baseURL: baseURL, http: httpClient, diff --git a/server/service/client.go b/server/service/client.go index 9f6336e66b..2941a79d6b 100644 --- a/server/service/client.go +++ b/server/service/client.go @@ -31,7 +31,6 @@ func NewClient(addr string, insecureSkipVerify bool, rootCA, urlPrefix string, o // TODO #265 refactor all optional parameters to functional options // API breaking change, needs a major version release baseClient, err := newBaseClient(addr, insecureSkipVerify, rootCA, urlPrefix) - if err != nil { return nil, err } diff --git a/server/service/device_client.go b/server/service/device_client.go index f8f9ff2ee2..8dcac11e73 100644 --- a/server/service/device_client.go +++ b/server/service/device_client.go @@ -22,7 +22,6 @@ func (dc *DeviceClient) request(verb string, path string, query string, response dc.url(path, query).String(), bytes.NewBuffer(bodyBytes), ) - if err != nil { return err } @@ -37,14 +36,16 @@ func (dc *DeviceClient) request(verb string, path string, query string, response } // NewDeviceClient instantiates a new client to perform requests against device endpoints -func NewDeviceClient(addr string, token string, insecureSkipVerify bool, rootCA string) (*DeviceClient, error) { +func NewDeviceClient(addr, token string, insecureSkipVerify bool, rootCA string) (*DeviceClient, error) { baseClient, err := newBaseClient(addr, insecureSkipVerify, rootCA, "") - if err != nil { return nil, err } - return &DeviceClient{baseClient: baseClient, token: token}, nil + return &DeviceClient{ + baseClient: baseClient, + token: token, + }, nil } // ListDevicePolicies fetches all policies for the device with the provided token diff --git a/tools/tuf/test/README.md b/tools/tuf/test/README.md index 1ff3571899..c8788bd108 100644 --- a/tools/tuf/test/README.md +++ b/tools/tuf/test/README.md @@ -9,20 +9,21 @@ Scripts in this directory aim to ease the testing of Orbit and the [TUF](https:/ The `main.sh` creates and runs the TUF repository and optionally generate the installers (GENERATE_PKGS): ```sh SYSTEMS="macos windows linux" \ -PKG_FLEET_URL=https://127.0.0.1:8080 \ -PKG_TUF_URL=http://127.0.0.1:8081 \ -DEB_FLEET_URL=https://172.16.132.1:8080 \ -DEB_TUF_URL=http://172.16.132.1:8081 \ -RPM_FLEET_URL=https://172.16.132.1:8080 \ -RPM_TUF_URL=http://172.16.132.1:8081 \ -MSI_FLEET_URL=https://172.16.132.1:8080 \ -MSI_TUF_URL=http://172.16.132.1:8081 \ +PKG_FLEET_URL=https://localhost:8080 \ +PKG_TUF_URL=http://localhost:8081 \ +DEB_FLEET_URL=https://host.docker.internal:8080 \ +DEB_TUF_URL=http://host.docker.internal:8081 \ +RPM_FLEET_URL=https://host.docker.internal:8080 \ +RPM_TUF_URL=http://host.docker.internal:8081 \ +MSI_FLEET_URL=https://host.docker.internal:8080 \ +MSI_TUF_URL=http://host.docker.internal:8081 \ GENERATE_PKG=1 \ GENERATE_DEB=1 \ GENERATE_RPM=1 \ GENERATE_MSI=1 \ ENROLL_SECRET=6/EzU/+jPkxfTamWnRv1+IJsO4T9Etju \ FLEET_DESKTOP=1 \ +FLEET_CERTIFICATE=1 \ ./tools/tuf/test/main.sh ``` @@ -30,7 +31,10 @@ Separate `*_FLEET_URL` and `*_TUF_URL` variables are needed for each package to E.g. The values shown above assume: 1. The script is executed on a macOS host. 2. Fleet server also running on the same macOS host. -3. Three VMs running on the macOS host where the access IP to host is `172.16.132.1`. +3. All VMs (and the macOS host itself) are configured to resolve `host.docker.internal` to the macOS host IP (by modifying their `hosts` file). + +> PS: We use `host.docker.internal` because the testing certificate `./tools/osquery/fleet.crt` +> has such hostname (and `localhost`) defined as SANs. # Add new updates diff --git a/tools/tuf/test/gen_pkgs.sh b/tools/tuf/test/gen_pkgs.sh index 6cec121b11..1bdc2b58b3 100755 --- a/tools/tuf/test/gen_pkgs.sh +++ b/tools/tuf/test/gen_pkgs.sh @@ -1,6 +1,6 @@ #!/bin/bash -set -e +set -ex # This script generates fleet-osquery packages for all supported platforms # using the specified TUF server. @@ -25,6 +25,12 @@ set -e # ENROLL_SECRET: Fleet server enroll secret. # ROOT_KEYS: TUF repository root keys. # FLEET_DESKTOP: Whether to build with Fleet Desktop support. +# FLEET_CERTIFICATE: Whether to use a custom certificate bundle. If not set, then --insecure mode is used. + +TLS_FLAG="--insecure" +if [ -n "$FLEET_CERTIFICATE" ]; then + TLS_FLAG="--fleet-certificate=./tools/osquery/fleet.crt" +fi if [ -n "$GENERATE_PKG" ]; then echo "Generating pkg..." @@ -33,7 +39,7 @@ if [ -n "$GENERATE_PKG" ]; then ${FLEET_DESKTOP:+--fleet-desktop} \ --fleet-url=$PKG_FLEET_URL \ --enroll-secret=$ENROLL_SECRET \ - --insecure \ + ${TLS_FLAG} \ --debug \ --update-roots="$ROOT_KEYS" \ --update-interval=10s \ @@ -48,7 +54,7 @@ if [ -n "$GENERATE_DEB" ]; then ${FLEET_DESKTOP:+--fleet-desktop} \ --fleet-url=$DEB_FLEET_URL \ --enroll-secret=$ENROLL_SECRET \ - --insecure \ + ${TLS_FLAG} \ --debug \ --update-roots="$ROOT_KEYS" \ --update-interval=10s \ @@ -63,7 +69,7 @@ if [ -n "$GENERATE_RPM" ]; then ${FLEET_DESKTOP:+--fleet-desktop} \ --fleet-url=$RPM_FLEET_URL \ --enroll-secret=$ENROLL_SECRET \ - --insecure \ + ${TLS_FLAG} \ --debug \ --update-roots="$ROOT_KEYS" \ --update-interval=10s \ @@ -78,7 +84,7 @@ if [ -n "$GENERATE_MSI" ]; then ${FLEET_DESKTOP:+--fleet-desktop} \ --fleet-url=$MSI_FLEET_URL \ --enroll-secret=$ENROLL_SECRET \ - --insecure \ + ${TLS_FLAG} \ --debug \ --update-roots="$ROOT_KEYS" \ --update-interval=10s \