Skip to content

Commit

Permalink
Merge branch 'main' into 17558-validation-errs
Browse files Browse the repository at this point in the history
  • Loading branch information
jahzielv committed Sep 10, 2024
2 parents dbf0455 + 9fedb59 commit f794bb3
Show file tree
Hide file tree
Showing 72 changed files with 1,249 additions and 389 deletions.
1 change: 1 addition & 0 deletions .github/workflows/dogfood-gitops.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ jobs:
DOGFOOD_GLOBAL_ENROLL_SECRET: ${{ secrets.DOGFOOD_GLOBAL_ENROLL_SECRET }}
DOGFOOD_SSO_ISSUER_URI: ${{ secrets.DOGFOOD_SSO_ISSUER_URI }}
DOGFOOD_SSO_METADATA: ${{ secrets.DOGFOOD_SSO_METADATA }}
DOGFOOD_MDM_SSO_METADATA_URL: ${{ secrets.DOGFOOD_MDM_SSO_METADATA_URL }}
DOGFOOD_FAILING_POLICIES_WEBHOOK_URL: ${{ secrets.DOGFOOD_FAILING_POLICIES_WEBHOOK_URL }}
DOGFOOD_VULNERABILITIES_WEBHOOK_URL: ${{ secrets.DOGFOOD_VULNERABILITIES_WEBHOOK_URL }}
DOGFOOD_WORKSTATIONS_ENROLL_SECRET: ${{ secrets.DOGFOOD_WORKSTATIONS_ENROLL_SECRET }}
Expand Down
24 changes: 11 additions & 13 deletions articles/discovering-chrome-ai-using-fleet.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

# Discovering AI in Chrome with Fleet

Staying ahead of technological innovations is crucial for both individuals and organizations. Google Chrome, one of the most widely used web browsers, continually evolves to incorporate advanced features, including artificial intelligence (AI). This article will guide you through detecting if AI capabilities have been enabled in Chrome using Fleet.
Staying ahead of technological innovations is crucial for individuals and organizations. Google Chrome, one of the most widely used web browsers, continually evolves to incorporate new features, including artificial intelligence (AI). This article will guide you through detecting if AI capabilities have been enabled in Chrome using Fleet.

## Introduction to Chrome AI innovations

Google Chrome has integrated AI to enhance user experience by providing intelligent suggestions, improving search results, and offering in-browser assistance. To explore these innovations further, visit the [Chrome AI Innovations page](https://www.google.com/chrome/ai-innovations/). Detecting whether AI features are enabled in your Chrome browser can help you understand and leverage these advancements effectively.
Google Chrome has integrated AI to enhance user experience by providing intelligent suggestions, improving search results, and offering in-browser assistance. Visit the [Chrome AI Innovations page](https://www.google.com/chrome/ai-innovations/) for more infomration.

## Using Fleet to detect AI features in Chrome

Fleet, a comprehensive device management and security tool, allows you to monitor various aspects of your devices, including software configurations and enabled features. Using Fleet, you can detect whether AI features are enabled in Chrome by querying device settings, specifically in the "Preferences" JSON file.
Fleet, a comprehensive device management and security tool, allows you to monitor various aspects of your devices, including software configurations and enabled features. Using Fleet, you can detect whether AI features are enabled in Chrome by querying device settings, specifically in the Chrome "Preferences" JSON file.

### Step 1: Understanding Chrome's preferences JSON file

Expand All @@ -24,33 +24,31 @@ Chrome stores user settings and configurations in a JSON file at the following p

### Step 2: Identifying AI-related settings

Within this file, AI-related features are stored in the `optimization_guide` section. The `tab_organization_setting_state` field will tell you if AI-based tab management features are enabled:
AI-related features are stored in the `optimization_guide` section of the preferences. The `tab_organization_setting_state` field will tell you if AI-based tab management features are enabled:

- Enabled:
The setting will return `1`.
`> jq` is a lightweight and powerful command-line tool for parsing, filtering, and manipulating JSON data. It allows you to extract specific information from JSON files efficiently. In this case, we use `jq` to locate and read the value of the `tab_organization_setting_state` key within Chrome's preference file which will help us understand how to craft our Fleet query for reporting the state of this setting.

- If enabled, the setting will return `1`.

![Chrome settings UI with Chrome AI enabled](../website/assets/images/articles/discovering-chrome-ai-using-fleet-1-1472x370@2x.png)

```
% jq '.optimization_guide.tab_organization_setting_state' /Users/brock/Library/Application\ Support/Google/Chrome/Default/Preferences
% jq '.optimization_guide.tab_organization_setting_state' /Users/<user>/Library/Application\ Support/Google/Chrome/Default/Preferences
1
```

- Disabled:
The setting will return `2`.
- If disabled, the setting will return `2`.

![Chrome settings UI with Chrome AI disabled](../website/assets/images/articles/discovering-chrome-ai-using-fleet-2-1474x276@2x.png)

```
% jq '.optimization_guide.tab_organization_setting_state' /Users/brock/Library/Application\ Support/Google/Chrome/Default/Preferences
% jq '.optimization_guide.tab_organization_setting_state' /Users/<user>/Library/Application\ Support/Google/Chrome/Default/Preferences
2
```

`> jq` is a lightweight and powerful command-line tool for parsing, filtering, and manipulating JSON data. It allows you to extract specific information from JSON files efficiently. In this case, we use `jq` to locate and read the value of the `tab_organization_setting_state` key within Chrome's preference file.

### Step 3: Query the JSON file with Fleet

To query the JSON file and detect AI features, you can use the following command:
To query the JSON file and detect AI features using Fleet, you can use the following SQL query:

```
SELECT fullkey,path FROM parse_json WHERE path LIKE '/Users/%/Library/Application Support/Google/Chrome/Default/Preferences' AND fullkey='optimization_guide/tab_organization_setting_state';
Expand Down
2 changes: 1 addition & 1 deletion articles/macos-mdm-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ banner at the top of page reminding you to renew your token.
To renew an ABM token:

1. Navigate to the **Settings > Integrations > Mobile device management (MDM)** page.
2. Under "Automatic enrollment", click "Edit", and then fin
2. Under "Automatic enrollment", click "Edit", and then find the token that you want to renew. Token status is indicated in the "Renew date" column: tokens less than 30 days from expiring will have a yellow indicator, and expired tokens will have a red indicator. Click the "Actions" dropdown for the token and then click "Renew". Follow the instructions in the modal to download a new token from Apple Business Manager and then upload the new token to Fleet.

After connecting Fleet to ABM, set Fleet to be the MDM for all Macs:

Expand Down
2 changes: 1 addition & 1 deletion articles/teams.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

_Available in Fleet Premium_

In Fleet, you can group hosts together in a "team" in Fleet. This way, you can apply queries, policies, scripts, and more that are tailored to the hosts' risk/compliance needs.
In Fleet, you can group hosts together in a "team" in Fleet. This way, you can apply queries, policies, scripts, and more that are tailored to a host's risk/compliance needs.

A host can only belong to one team.

Expand Down
1 change: 1 addition & 0 deletions changes/20828-better-appid-error
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Improve clarity of gitops VPP app ID type errors
1 change: 1 addition & 0 deletions changes/21019-ota-enrollment
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Implement protocol support for OTA enrollment and automatic team assignment for hosts.
1 change: 1 addition & 0 deletions changes/21402-improve-windows-mdm-enabled-error-message
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Improve gitops error message about enabling windows MDM
2 changes: 2 additions & 0 deletions changes/21866-startup-expired-abm-cert
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Fixed issue where Fleet server could start when expired ABM cerfificate was provided as server
config options.
147 changes: 86 additions & 61 deletions cmd/fleet/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,18 @@ the way that the Fleet server works.
mdmPushService = nanomdm_pushsvc.New(mdmStorage, mdmStorage, pushProviderFactory, nanoMDMLogger)
}

// validate Apple APNs/SCEP config
checkMDMAssets := func(names []fleet.MDMAssetName) (bool, error) {
_, err = ds.GetAllMDMConfigAssetsByName(context.Background(), names)
if err != nil {
if fleet.IsNotFound(err) || errors.Is(err, mysql.ErrPartialResult) {
return false, nil
}
return false, err
}
return true, nil
}

// reconcile Apple Business Manager configuration environment variables with the database
if config.MDM.IsAppleAPNsSet() || config.MDM.IsAppleSCEPSet() {
if !config.MDM.IsAppleAPNsSet() {
initFatal(errors.New("Apple APNs MDM configuration must be provided when Apple SCEP is provided"), "validate Apple MDM")
Expand All @@ -508,40 +519,63 @@ the way that the Fleet server works.
}

if len(config.Server.PrivateKey) == 0 {
initFatal(errors.New("inserting APNs and SCEP assets"), "missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key")
initFatal(errors.New("inserting MDM APNs and SCEP assets"), "missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key")
}

// parse the APNs and SCEP assets from the config
_, apnsCertPEM, apnsKeyPEM, err := config.MDM.AppleAPNs()
if err != nil {
initFatal(err, "validate Apple APNs certificate and key")
initFatal(err, "parse Apple APNs certificate and key from config")
}

_, appleSCEPCertPEM, appleSCEPKeyPEM, err := config.MDM.AppleSCEP()
if err != nil {
initFatal(err, "validate Apple SCEP certificate and key")
initFatal(err, "load Apple SCEP certificate and key from config")
}

err = ds.InsertMDMConfigAssets(context.Background(), []fleet.MDMConfigAsset{
{Name: fleet.MDMAssetAPNSCert, Value: apnsCertPEM},
{Name: fleet.MDMAssetAPNSKey, Value: apnsKeyPEM},
{Name: fleet.MDMAssetCACert, Value: appleSCEPCertPEM},
{Name: fleet.MDMAssetCAKey, Value: appleSCEPKeyPEM},
})
if err != nil {
// duplicate key errors mean that we already
// have a value for those keys in the
// database, fail to initalize on other
// cases.
if !mysql.IsDuplicate(err) {
initFatal(err, "inserting MDM APNs and SCEP assets")
}
// first we'll check if the APNs and SCEP assets are already in the database and
// only insert config values if they're not already present in the database
toInsert := make([]fleet.MDMConfigAsset, 0, 4)

// check DB for APNs assets
found, err := checkMDMAssets([]fleet.MDMAssetName{fleet.MDMAssetAPNSCert, fleet.MDMAssetAPNSKey})
switch {
case err != nil:
initFatal(err, "reading APNs assets from database")
case !found:
toInsert = append(toInsert, fleet.MDMConfigAsset{Name: fleet.MDMAssetAPNSCert, Value: apnsCertPEM}, fleet.MDMConfigAsset{Name: fleet.MDMAssetAPNSKey, Value: apnsKeyPEM})
default:
level.Warn(logger).Log("msg", "Your server already has stored APNs certificates. Fleet will ignore any certificates provided via environment variables when this happens.")
}

level.Warn(logger).Log("msg", "Your server already has stored SCEP and APNs certificates. Fleet will ignore any certificates provided via environment variables when this happens.")
// check DB for SCEP assets
found, err = checkMDMAssets([]fleet.MDMAssetName{fleet.MDMAssetCACert, fleet.MDMAssetCAKey})
switch {
case err != nil:
initFatal(err, "reading SCEP assets from database")
case !found:
toInsert = append(toInsert, fleet.MDMConfigAsset{Name: fleet.MDMAssetCACert, Value: appleSCEPCertPEM}, fleet.MDMConfigAsset{Name: fleet.MDMAssetCAKey, Value: appleSCEPKeyPEM})
default:
level.Warn(logger).Log("msg", "Your server already has stored SCEP certificates. Fleet will ignore any certificates provided via environment variables when this happens.")
}

if len(toInsert) > 0 {
if len(config.Server.PrivateKey) == 0 {
initFatal(errors.New("inserting APNs and SCEP assets"), "missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key")
}
if err := ds.InsertMDMConfigAssets(context.Background(), toInsert); err != nil {
if mysql.IsDuplicate(err) {
// we already checked for existing assets so we should never have a duplicate key error here; we'll add a debug log just in case
level.Debug(logger).Log("msg", "unexpected duplicate key error inserting MDM APNs and SCEP assets")
} else {
initFatal(err, "inserting MDM APNs and SCEP assets")
}
}
}
}

// validate Apple BM config
// reconcile Apple Business Manager configuration environment variables with the database
if config.MDM.IsAppleBMSet() {
// TODO: Confirm whether we should have any fatal license errors
if !license.IsPremium() {
initFatal(errors.New("Apple Business Manager configuration is only available in Fleet Premium"), "validate Apple BM")
}
Expand All @@ -552,36 +586,38 @@ the way that the Fleet server works.

appleBM, err := config.MDM.AppleBM()
if err != nil {
initFatal(err, "validate Apple BM token, certificate and key")
initFatal(err, "parse Apple BM token, certificate and key from config")
}

err = ds.InsertMDMConfigAssets(context.Background(), []fleet.MDMConfigAsset{
{Name: fleet.MDMAssetABMKey, Value: appleBM.KeyPEM},
{Name: fleet.MDMAssetABMCert, Value: appleBM.CertPEM},
})
if err != nil {
// duplicate key errors mean that we already
// have a value for those keys in the
// database, fail to initalize on other
// cases.
if !mysql.IsDuplicate(err) {
initFatal(err, "inserting MDM ABM assets")
}
toInsert := make([]fleet.MDMConfigAsset, 0, 4)

found, err := checkMDMAssets([]fleet.MDMAssetName{fleet.MDMAssetABMKey, fleet.MDMAssetABMCert})
switch {
case err != nil:
initFatal(err, "reading ABM assets from database")
case !found:
toInsert = append(toInsert, fleet.MDMConfigAsset{Name: fleet.MDMAssetABMKey, Value: appleBM.KeyPEM}, fleet.MDMConfigAsset{Name: fleet.MDMAssetABMCert, Value: appleBM.CertPEM})
default:
level.Warn(logger).Log("msg", "Your server already has stored ABM certificates and token. Fleet will ignore any certificates provided via environment variables when this happens.")
} else {
// insert the ABM token without any metdata,
// it'll be picked by the
// apple_mdm_dep_profile_assigner cron and
// backfilled
tok := &fleet.ABMToken{
EncryptedToken: appleBM.EncryptedToken,
// 2000-01-01 is our "zero value" for time
RenewAt: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC),
}
_, err = ds.InsertABMToken(context.Background(), tok)
if err != nil {
initFatal(err, "save ABM token")
}

if len(toInsert) > 0 {
err := ds.InsertMDMConfigAssets(context.Background(), toInsert)
switch {
case err != nil && mysql.IsDuplicate(err):
// we already checked for existing assets so we should never have a duplicate key error here; we'll add a debug log just in case
level.Debug(logger).Log("msg", "unexpected duplicate key error inserting ABM assets")
case err != nil:
initFatal(err, "inserting ABM assets")
default:
// insert the ABM token without any metdata; it'll be picked by the
// apple_mdm_dep_profile_assigner cron and backfilled
if _, err := ds.InsertABMToken(context.Background(), &fleet.ABMToken{
EncryptedToken: appleBM.EncryptedToken,
RenewAt: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC), // 2000-01-01 is our "zero value" for time
}); err != nil {
initFatal(err, "save ABM token")
}
}
}
}
Expand All @@ -591,17 +627,6 @@ the way that the Fleet server works.
initFatal(err, "loading app config")
}

checkMDMAssets := func(names []fleet.MDMAssetName) (bool, error) {
_, err = ds.GetAllMDMConfigAssetsByName(context.Background(), names)
if err != nil {
if fleet.IsNotFound(err) || errors.Is(err, mysql.ErrPartialResult) {
return false, nil
}
return false, err
}
return true, nil
}

appCfg.MDM.EnabledAndConfigured = false
appCfg.MDM.AppleBMEnabledAndConfigured = false
if len(config.Server.PrivateKey) > 0 {
Expand All @@ -612,7 +637,7 @@ the way that the Fleet server works.
fleet.MDMAssetAPNSCert,
})
if err != nil {
initFatal(err, "validating MDM assets from database")
initFatal(err, "loading MDM assets from database")
}

var appleBMCerts bool
Expand All @@ -621,14 +646,14 @@ the way that the Fleet server works.
fleet.MDMAssetABMKey,
})
if err != nil {
initFatal(err, "validating MDM ABM assets from database")
initFatal(err, "loading MDM ABM assets from database")
}
if appleBMCerts {
// the ABM certs are there, check if a token exists and if so, apple
// BM is enabled and configured.
count, err := ds.GetABMTokenCount(context.Background())
if err != nil {
initFatal(err, "validating MDM ABM token from database")
initFatal(err, "loading MDM ABM token from database")
}
appCfg.MDM.AppleBMEnabledAndConfigured = count > 0
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/fleet/serve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ import (
"github.com/go-kit/log"
kitlog "github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/smallstep/pkcs7"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.mozilla.org/pkcs7"
)

// safeStore is a wrapper around mock.Store to allow for concurrent calling to
Expand Down
5 changes: 3 additions & 2 deletions cmd/fleetctl/gitops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1262,7 +1262,7 @@ func TestGitOpsTeamSofwareInstallers(t *testing.T) {
{"testdata/gitops/team_software_installer_install_not_found.yml", "no such file or directory"},
{"testdata/gitops/team_software_installer_post_install_not_found.yml", "no such file or directory"},
{"testdata/gitops/team_software_installer_no_url.yml", "software URL is required"},
{"testdata/gitops/team_software_installer_invalid_self_service_value.yml", "cannot unmarshal string into Go struct field SoftwarePackage.packages.self_service of type bool"},
{"testdata/gitops/team_software_installer_invalid_self_service_value.yml", "\"packages.self_service\" must be a bool, found string"},
}
for _, c := range cases {
t.Run(filepath.Base(c.file), func(t *testing.T) {
Expand Down Expand Up @@ -1311,7 +1311,7 @@ func TestGitOpsNoTeamSoftwareInstallers(t *testing.T) {
{"testdata/gitops/no_team_software_installer_install_not_found.yml", "no such file or directory"},
{"testdata/gitops/no_team_software_installer_post_install_not_found.yml", "no such file or directory"},
{"testdata/gitops/no_team_software_installer_no_url.yml", "software URL is required"},
{"testdata/gitops/no_team_software_installer_invalid_self_service_value.yml", "cannot unmarshal string into Go struct field SoftwarePackage.packages.self_service of type bool"},
{"testdata/gitops/no_team_software_installer_invalid_self_service_value.yml", "\"packages.self_service\" must be a bool, found string"},
}
for _, c := range cases {
t.Run(filepath.Base(c.file), func(t *testing.T) {
Expand Down Expand Up @@ -1383,6 +1383,7 @@ func TestGitOpsTeamVPPApps(t *testing.T) {
{"testdata/gitops/team_vpp_valid_empty.yml", "", time.Now().Add(-24 * time.Hour)},
{"testdata/gitops/team_vpp_valid_app.yml", "VPP token expired", time.Now().Add(-24 * time.Hour)},
{"testdata/gitops/team_vpp_invalid_app.yml", "app not available on vpp account", time.Now().Add(24 * time.Hour)},
{"testdata/gitops/team_vpp_incorrect_type.yml", "\"app_store_apps.app_store_id\" must be a string, found number", time.Now().Add(24 * time.Hour)},
{"testdata/gitops/team_vpp_empty_adamid.yml", "software app store id required", time.Now().Add(24 * time.Hour)},
}

Expand Down
17 changes: 17 additions & 0 deletions cmd/fleetctl/testdata/gitops/team_vpp_incorrect_type.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: "${TEST_TEAM_NAME}"
team_settings:
secrets:
- secret: "ABC"
features:
enable_host_users: true
enable_software_inventory: true
host_expiry_settings:
host_expiry_enabled: true
host_expiry_window: 30
agent_options:
controls:
policies:
queries:
software:
app_store_apps:
- app_store_id: 1
Loading

0 comments on commit f794bb3

Please sign in to comment.