Add support for CA root certificate to Fleet Desktop (fleetctl package's --fleet-certificate flag) (#6312)

* Orbit to pass the value of `--fleet-certificate` to Fleet Desktop

* Add changes for testing
This commit is contained in:
Lucas Manuel Rodriguez 2022-06-21 16:25:36 -03:00 committed by GitHub
parent b1442e6e55
commit 9b210fc6bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 55 additions and 34 deletions

View file

@ -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

View file

@ -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"))
}

View file

@ -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,

View file

@ -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
}

View file

@ -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

View file

@ -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

View file

@ -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 \