Skip to content

Commit 5ddeb31

Browse files
authored
Added dconf_read table and documentation to enable fleet desktop on Fedora and Debian (#27684)
For #20675 and #25977. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files) for more information. - [x] A detailed QA plan exists on the associated ticket (if it isn't there, work with the product group's QA engineer to add it) - [X] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [X] Make sure fleetd is compatible with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/fleetd-development-and-release-strategy.md)). - [X] Orbit runs on macOS, Linux and Windows. Check if the orbit feature/bugfix should only apply to one platform (`runtime.GOOS`). - [X] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [x] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)).
1 parent 8a05cb6 commit 5ddeb31

16 files changed

+295
-34
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Enabling Fleet Desktop on Fedora and Debian
2+
3+
[Fleet Desktop](https://fleetdm.com/guides/fleet-desktop) is a menu bar icon available on macOS, Windows, and Linux that gives your end users visibility into the security posture of their machine.
4+
5+
Fedora and Debian do not support tray icons by default and rely on the [appindicator-support](https://extensions.gnome.org/extension/615/appindicator-support/) GNOME extension for enabling tray icons. GNOME extensions prompt the end user to accept the installation.
6+
7+
This article aims to explain how admins can enable Fleet Desktop on such Linux distributions by using policy queries paired with script execution.
8+
9+
## Policy and script execution
10+
11+
The [fedora-debian-check-fleet-desktop.yml](../it-and-security/lib/linux/policies/fedora-debian-check-fleet-desktop.yml) policy (used in our Dogfood environment) can be used to check if the extension needed for Fleet Desktop is installed and enabled on Fedora and Debian hosts.
12+
> NOTE: fleetd 1.41.0 is required (the policy query relies on a table added to that version).
13+
14+
Starting in version v4.58.0, Fleet supports running scripts to remediate failing policies (see the [Automatically run scripts](./policy-automation-run-script.md) article for more information). Admins can therefore configure Fleet to run [fedora-debian-enable-fleet-desktop.sh](../it-and-security/lib/linux/scripts/fedora-debian-enable-fleet-desktop.sh) on devices where the policy detects the extension is missing.
15+
16+
[Here](../it-and-security/lib/linux/policies/fedora-debian-check-fleet-desktop.yml)'s the full example (policy + script) we use in our GitOps configuration for our Dogfood environment.
17+
18+
### End-user experience
19+
20+
Following are screenshots of the end-user experience when Fleet runs the script to install the extension (GNOME requires a prompt for installation of extensions for security purposes).
21+
22+
<p float="left">
23+
<img src="../website/assets/images/fedora_38_appindicator_extension_prompt.png" title="Fedora 38" width="300" />
24+
<img src="../website/assets/images/debian_12_appindicator_extension_prompt.png" title="Debian 12" width="300" />
25+
</p>
26+
27+
> If the end-user hits `Cancel` instead of `Install` then the extension won't be installed and the policy will continue to fail on the host. Fleet only deploys the script on the first failure of the policy, so the end-user won't be prompted again and again, just once. Admins can still run the script on such hosts manually.
28+
29+
### Tray icon
30+
31+
After the extension is installed your users will see the Fleet icon on their menu bar:
32+
33+
<p float="left">
34+
<img src="../website/assets/images/fedora_38_fleet_desktop_tray.png" title="Fedora 38" width="300" />
35+
<img src="../website/assets/images/debian_12_fleet_desktop_tray.png" title="Debian 12" width="300" />
36+
</p>
37+
38+
<meta name="authorGitHubUsername" value="lucasmrod">
39+
<meta name="authorFullName" value="Lucas Rodriguez">
40+
<meta name="publishedOn" value="2025-04-01">
41+
<meta name="articleTitle" value="Enabling Fleet Desktop on Fedora and Debian">
42+
<meta name="category" value="guides">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
- name: Check Fleet Desktop on Fedora and Debian
2+
critical: false
3+
description: This policy checks if the extension required for Fleet Desktop is installed and enabled.
4+
resolution: |
5+
Install and enable the "[email protected]" extension by running the following commands on a terminal (as user, not root):
6+
gdbus call --session \
7+
--dest org.gnome.Shell.Extensions \
8+
--object-path /org/gnome/Shell/Extensions \
9+
--method org.gnome.Shell.Extensions.InstallRemoteExtension \
10+
11+
gnome-extensions enable "[email protected]"
12+
platform: linux
13+
query: |
14+
SELECT 1 WHERE NOT EXISTS (
15+
-- Policy succeeds on Linux distributions that are not Fedora or Debian.
16+
SELECT 1 FROM os_version WHERE name = 'Fedora Linux' OR platform = 'debian'
17+
) OR NOT EXISTS (
18+
-- Policy succeeds on Linux hosts that do not have Fleet Desktop enabled or
19+
-- Fleet Desktop is not running (e.g. logged out from GUI).
20+
SELECT 1 FROM processes WHERE name = 'fleet-desktop' LIMIT 1
21+
) OR EXISTS (
22+
WITH fleet_desktop AS (SELECT TRIM(cwd, '/home/') AS username, cwd AS home FROM processes WHERE name = 'fleet-desktop' LIMIT 1)
23+
SELECT 1 WHERE EXISTS (
24+
-- Check if the extension is installed (an extension can be enabled but not installed, and viceversa).
25+
SELECT 1 FROM file WHERE path = CONCAT((SELECT home FROM fleet_desktop), '/.local/share/gnome-shell/extensions/[email protected]') AND type = 'directory'
26+
) AND EXISTS (
27+
-- Check if the extension is enabled (an extension can be enabled but not installed, and viceversa).
28+
SELECT 1 FROM dconf_read WHERE username = (SELECT fleet_desktop.username FROM fleet_desktop) AND key = '/org/gnome/shell/enabled-extensions' AND value like '%[email protected]%'
29+
)
30+
);
31+
run_script:
32+
path: ../scripts/fedora-debian-enable-fleet-desktop.sh

it-and-security/lib/linux/queries/all-deb-hosts.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
logging: snapshot
77
observer_can_run: true
88
platform: linux
9-
query: SELECT * FROM os_version WHERE platform_like = 'debian';
9+
query: SELECT * FROM os_version WHERE platform = 'debian';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/bin/bash
2+
3+
# Script assumes one user is using the desktop environment (no multi-session).
4+
# It was tested on Fedora 38, 39 and Debian 12.
5+
6+
set -x
7+
8+
run_uid=$(id -u)
9+
10+
# Start detached script and exit as root (to send result back to Fleet).
11+
if [ $run_uid == 0 ] && [ $# -eq 0 ]; then
12+
/bin/bash -c "/bin/bash $0 1 >/var/log/orbit/appindicator_script.log 2>/var/log/orbit/appindicator_script.log </dev/null &"
13+
echo "A detached script to install extension has been started (logs can be found in /var/log/orbit/appindicator_script.log)."
14+
exit 0
15+
fi
16+
17+
# Wait for user to be logged in to the GUI (by checking fleet-desktop process).
18+
fleet_desktop_pid=$(pgrep fleet-desktop)
19+
while [ -z $fleet_desktop_pid ]; do
20+
fleet_desktop_pid=$(pgrep fleet-desktop)
21+
sleep 10
22+
done
23+
24+
extension_name="[email protected]"
25+
username=$(ps -o user= -p $fleet_desktop_pid | xargs)
26+
uid=$(ps -o uid= -p $fleet_desktop_pid | xargs)
27+
28+
# If the extension is not installed, then prompt the user.
29+
if [ ! -d "/home/$username/.local/share/gnome-shell/extensions/$extension_name" ]; then
30+
# Show notification to user before the prompt.
31+
sudo -i -u $username -H DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus \
32+
gdbus call --session \
33+
--dest org.freedesktop.Notifications \
34+
--object-path /org/freedesktop/Notifications \
35+
--method org.freedesktop.Notifications.Notify \
36+
"Fleet Desktop" 0 \"\" "Fleet Desktop" "Install a GNOME extension to enable Fleet Desktop. This lets you see what your organization is doing on your computer." "[]" '{"urgency": <2>}' 0
37+
38+
# Give some time to user to see notification.
39+
sleep 10
40+
41+
# Prompt user for installation of extension.
42+
sudo -i -u $username -H DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus \
43+
gdbus call --session \
44+
--dest org.gnome.Shell.Extensions \
45+
--object-path /org/gnome/Shell/Extensions \
46+
--method org.gnome.Shell.Extensions.InstallRemoteExtension \
47+
"$extension_name"
48+
49+
# Wait until the extension is accepted by the user ("gbus call" command above is asynchronous).
50+
while [ ! -d "/home/$username/.local/share/gnome-shell/extensions/$extension_name" ]; do
51+
sleep 1
52+
done
53+
54+
# Sleep to give some time for files to be downloaded.
55+
sleep 15
56+
fi
57+
58+
# Enable the extension in case it was disabled in the past.
59+
sudo -i -u $username -H DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus \
60+
gnome-extensions enable "$extension_name"

it-and-security/teams/compliance-exclusions.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ controls:
3333
- path: ../lib/macos/scripts/uninstall-fleetd-macos.sh
3434
- path: ../lib/windows/scripts/uninstall-fleetd-windows.ps1
3535
- path: ../lib/linux/scripts/uninstall-fleetd-linux.sh
36+
- path: ../lib/linux/scripts/fedora-debian-enable-fleet-desktop.sh
3637
policies:
37-
- path: ../lib/macos/policies/enrollment-profile-up-to-date.yml
38+
- path: ../lib/macos/policies/enrollment-profile-up-to-date.yml
39+
- path: ../lib/linux/policies/fedora-debian-check-fleet-desktop.yml
3840
queries:
3941
software:
4042
packages:

it-and-security/teams/servers-canary.yml

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ controls:
2727
deadline_days: null
2828
grace_period_days: null
2929
scripts:
30+
- path: ../lib/linux/scripts/fedora-debian-enable-fleet-desktop.sh
3031
policies:
32+
- path: ../lib/linux/policies/fedora-debian-check-fleet-desktop.yml
3133
queries:
3234
software:

it-and-security/teams/workstations-canary.yml

+32-30
Original file line numberDiff line numberDiff line change
@@ -27,35 +27,35 @@ agent_options:
2727
logger_tls_period: 10
2828
pack_delimiter: /
2929
overrides:
30-
platforms:
31-
darwin:
32-
auto_table_construction:
33-
tcc_system:
34-
path: /Library/Application Support/com.apple.TCC/TCC.db
35-
query: 'select service, client, client_type, auth_value, auth_reason, policy_id, indirect_object_identifier, indirect_object_identifier_type, last_modified from access'
36-
columns:
37-
- service
38-
- client
39-
- client_type
40-
- auth_value
41-
- auth_reason
42-
- policy_id
43-
- indirect_object_identifier
44-
- indirect_object_identifier_type
45-
- last_modified
46-
tcc_user:
47-
path: /Users/%/Library/Application Support/com.apple.TCC/TCC.db
48-
query: 'select service, client, client_type, auth_value, auth_reason, policy_id, indirect_object_identifier, indirect_object_identifier_type, last_modified from access'
49-
columns:
50-
- service
51-
- client
52-
- client_type
53-
- auth_value
54-
- auth_reason
55-
- policy_id
56-
- indirect_object_identifier
57-
- indirect_object_identifier_type
58-
- last_modified
30+
platforms:
31+
darwin:
32+
auto_table_construction:
33+
tcc_system:
34+
path: /Library/Application Support/com.apple.TCC/TCC.db
35+
query: "select service, client, client_type, auth_value, auth_reason, policy_id, indirect_object_identifier, indirect_object_identifier_type, last_modified from access"
36+
columns:
37+
- service
38+
- client
39+
- client_type
40+
- auth_value
41+
- auth_reason
42+
- policy_id
43+
- indirect_object_identifier
44+
- indirect_object_identifier_type
45+
- last_modified
46+
tcc_user:
47+
path: /Users/%/Library/Application Support/com.apple.TCC/TCC.db
48+
query: "select service, client, client_type, auth_value, auth_reason, policy_id, indirect_object_identifier, indirect_object_identifier_type, last_modified from access"
49+
columns:
50+
- service
51+
- client
52+
- client_type
53+
- auth_value
54+
- auth_reason
55+
- policy_id
56+
- indirect_object_identifier
57+
- indirect_object_identifier_type
58+
- last_modified
5959
update_channels:
6060
# We want to use these hosts to smoke test edge releases.
6161
osqueryd: edge
@@ -140,6 +140,7 @@ controls:
140140
- path: ../lib/windows/scripts/create-admin-user.ps1
141141
- path: ../lib/windows/scripts/uninstall-fleetd-windows.ps1
142142
- path: ../lib/linux/scripts/uninstall-fleetd-linux.sh
143+
- path: ../lib/linux/scripts/fedora-debian-enable-fleet-desktop.sh
143144
policies:
144145
- path: ../lib/macos/policies/1password-emergency-kit-check.yml
145146
- path: ../lib/macos/policies/update-firefox.yml
@@ -156,6 +157,7 @@ policies:
156157
- path: ../lib/windows/policies/1password-installed.yml
157158
- path: ../lib/windows/policies/update-1password.yml
158159
- path: ../lib/linux/policies/disk-encryption-check.yml
160+
- path: ../lib/linux/policies/fedora-debian-check-fleet-desktop.yml
159161
queries:
160162
- path: ../lib/macos/queries/detect-apple-intelligence.yml
161163
software:
@@ -174,4 +176,4 @@ software:
174176
- path: ../lib/windows/software/google-chrome-arm.yml # Google Chrome for Windows (ARM)
175177
- path: ../lib/windows/software/1password.yml # 1Password for Windows
176178
app_store_apps:
177-
- app_store_id: '803453959' # Slack Desktop
179+
- app_store_id: "803453959" # Slack Desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* Added `dconf_read` table to get configuration information from GNOME.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//go:build linux
2+
// +build linux
3+
4+
package dconf_read
5+
6+
import (
7+
"bytes"
8+
"context"
9+
"errors"
10+
"fmt"
11+
"os/exec"
12+
13+
"github.com/osquery/osquery-go/plugin/table"
14+
"github.com/rs/zerolog/log"
15+
)
16+
17+
// Columns is the schema of the table.
18+
func Columns() []table.ColumnDefinition {
19+
return []table.ColumnDefinition{
20+
table.TextColumn("username"), // required
21+
table.TextColumn("key"), // required
22+
table.TextColumn("value"),
23+
}
24+
}
25+
26+
// Generate is called to return the results for the table at query time.
27+
// Constraints for generating can be retrieved from the queryContext.
28+
func Generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) {
29+
getFirstConstraint := func(columnName string) string {
30+
if constraints, ok := queryContext.Constraints[columnName]; ok {
31+
for _, constraint := range constraints.Constraints {
32+
if constraint.Operator == table.OperatorEquals {
33+
return constraint.Expression
34+
}
35+
}
36+
}
37+
return ""
38+
}
39+
40+
username := getFirstConstraint("username")
41+
if username == "" {
42+
return nil, errors.New("missing username")
43+
}
44+
45+
key := getFirstConstraint("key")
46+
if key == "" {
47+
return nil, errors.New("missing key")
48+
}
49+
50+
cmd := exec.Command("/usr/bin/sudo", "-u", username, "/usr/bin/dconf", "read", key)
51+
var (
52+
stdout bytes.Buffer
53+
stderr bytes.Buffer
54+
)
55+
cmd.Stderr = &stderr
56+
cmd.Stdout = &stdout
57+
log.Debug().Str("cmd", cmd.String()).Msg("running")
58+
err := cmd.Run()
59+
if err != nil {
60+
return nil, fmt.Errorf("dconf read failed: %w: %s", err, stderr.String())
61+
}
62+
63+
return []map[string]string{{
64+
"username": username,
65+
"key": key,
66+
"value": stdout.String(),
67+
}}, nil
68+
}

orbit/pkg/table/extension_linux.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import (
77
"github.com/fleetdm/fleet/v4/orbit/pkg/table/crowdstrike/falconctl"
88
"github.com/fleetdm/fleet/v4/orbit/pkg/table/cryptsetup"
99
"github.com/fleetdm/fleet/v4/orbit/pkg/table/dataflattentable"
10-
"github.com/rs/zerolog/log"
11-
10+
"github.com/fleetdm/fleet/v4/orbit/pkg/table/dconf_read"
1211
"github.com/osquery/osquery-go"
12+
"github.com/osquery/osquery-go/plugin/table"
13+
"github.com/rs/zerolog/log"
1314
)
1415

1516
func PlatformTables(_ PluginOpts) ([]osquery.OsqueryPlugin, error) {
@@ -18,5 +19,6 @@ func PlatformTables(_ PluginOpts) ([]osquery.OsqueryPlugin, error) {
1819
falconctl.NewFalconctlOptionTable(log.Logger), // table name is "falconctl_option"
1920
falcon_kernel_check.TablePlugin(log.Logger), // table name is "falcon_kernel_check"
2021
dataflattentable.TablePluginExec(log.Logger, "nftables", dataflattentable.JsonType, []string{"nft", "-jat", "list", "ruleset"}, dataflattentable.WithBinDirs("/usr/bin", "/usr/sbin")), // -j (json) -a (show object handles) -t (terse, omit set contents)
22+
table.NewPlugin("dconf_read", dconf_read.Columns(), dconf_read.Generate),
2123
}, nil
2224
}

schema/osquery_fleet_schema.json

+31
Original file line numberDiff line numberDiff line change
@@ -6011,6 +6011,37 @@
60116011
],
60126012
"fleetRepoUrl": "https://github.com/fleetdm/fleet/blob/main/schema/tables/curl_certificate.yml"
60136013
},
6014+
{
6015+
"name": "dconf_read",
6016+
"platforms": [
6017+
"linux"
6018+
],
6019+
"description": "Returns GNOME configuration using the \"dconf read\" command.",
6020+
"columns": [
6021+
{
6022+
"name": "username",
6023+
"type": "text",
6024+
"required": true,
6025+
"description": "End user's username."
6026+
},
6027+
{
6028+
"name": "key",
6029+
"type": "text",
6030+
"required": true,
6031+
"description": "Name of the configuration key to read."
6032+
},
6033+
{
6034+
"name": "value",
6035+
"type": "text",
6036+
"required": false,
6037+
"description": "Value of the provided key."
6038+
}
6039+
],
6040+
"notes": "This table is not a core osquery table. It is included as part of Fleet's agent ([fleetd](https://fleetdm.com/docs/get-started/anatomy#fleetd)).",
6041+
"evented": false,
6042+
"url": "https://fleetdm.com/tables/dconf_read",
6043+
"fleetRepoUrl": "https://github.com/fleetdm/fleet/blob/main/schema/tables/dconf_read.yml"
6044+
},
60146045
{
60156046
"name": "deb_packages",
60166047
"description": "The installed DEB package database.",

schema/tables/dconf_read.yml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: dconf_read
2+
platforms:
3+
- linux
4+
description: Returns GNOME configuration using the "dconf read" command.
5+
columns:
6+
- name: username
7+
type: text
8+
required: true
9+
description: End user's username.
10+
- name: key
11+
type: text
12+
required: true
13+
description: Name of the configuration key to read.
14+
- name: value
15+
type: text
16+
required: false
17+
description: Value of the provided key.
18+
notes: This table is not a core osquery table. It is included as part of Fleet's agent ([fleetd](https://fleetdm.com/docs/get-started/anatomy#fleetd)).
19+
evented: false
Loading
Loading
Loading
Loading

0 commit comments

Comments
 (0)