diff --git a/.github/workflows/check-tuf-timestamps.yml b/.github/workflows/check-tuf-timestamps.yml index 1a62757cc1..b9f9720aa8 100644 --- a/.github/workflows/check-tuf-timestamps.yml +++ b/.github/workflows/check-tuf-timestamps.yml @@ -3,10 +3,10 @@ name: Check TUF timestamps on: pull_request: paths: - - '.github/workflows/check-tuf-timestamps.yml' + - ".github/workflows/check-tuf-timestamps.yml" workflow_dispatch: # Manual schedule: - - cron: '0 10,22 * * *' + - cron: "0 10,22 * * *" # This allows a subsequently queued workflow run to interrupt previous runs concurrency: @@ -29,81 +29,151 @@ jobs: runs-on: ${{ matrix.os }} steps: - - name: Harden Runner - uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 - with: - egress-policy: audit + - name: Harden Runner + uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0 + with: + egress-policy: audit - - name: Check remote timestamp.json file - id: check_timestamp - run: | - expires=$(curl -s http://tuf.fleetctl.com/timestamp.json | jq -r '.signed.expires' | cut -c 1-10) - today=$(date "+%Y-%m-%d") - warning_at=$(date -d "$today + 4 day" "+%Y-%m-%d") - expires_sec=$(date -d "$expires" "+%s") - warning_at_sec=$(date -d "$warning_at" "+%s") + - name: Check remote timestamp.json file + id: check_timestamp + run: | + expires=$(curl -s http://tuf.fleetctl.com/timestamp.json | jq -r '.signed.expires' | cut -c 1-10) + today=$(date "+%Y-%m-%d") + warning_at=$(date -d "$today + 4 day" "+%Y-%m-%d") + expires_sec=$(date -d "$expires" "+%s") + warning_at_sec=$(date -d "$warning_at" "+%s") - if [ "$expires_sec" -le "$warning_at_sec" ]; then - echo "timestamp_warn=true" >> ${GITHUB_OUTPUT} - else - echo "timestamp_warn=false" >> ${GITHUB_OUTPUT} - fi + if [ "$expires_sec" -le "$warning_at_sec" ]; then + echo "timestamp_warn=true" >> ${GITHUB_OUTPUT} + else + echo "timestamp_warn=false" >> ${GITHUB_OUTPUT} + fi - - name: Check remote root.json file - id: check_root - run: | - expires=$(curl -s http://tuf.fleetctl.com/root.json | jq -r '.signed.expires' | cut -c 1-10) - today=$(date "+%Y-%m-%d") - warning_at=$(date -d "$today + 30 day" "+%Y-%m-%d") - expires_sec=$(date -d "$expires" "+%s") - warning_at_sec=$(date -d "$warning_at" "+%s") + - name: Check remote snapshot.json file + id: check_snapshot + run: | + expires=$(curl -s http://tuf.fleetctl.com/snapshot.json | jq -r '.signed.expires' | cut -c 1-10) + today=$(date "+%Y-%m-%d") + warning_at=$(date -d "$today + 30 day" "+%Y-%m-%d") + expires_sec=$(date -d "$expires" "+%s") + warning_at_sec=$(date -d "$warning_at" "+%s") - if [ "$expires_sec" -le "$warning_at_sec" ]; then - echo "root_warn=true" >> ${GITHUB_OUTPUT} - else - echo "root_warn=false" >> ${GITHUB_OUTPUT} - fi + if [ "$expires_sec" -le "$warning_at_sec" ]; then + echo "snapshot_warn=true" >> ${GITHUB_OUTPUT} + else + echo "snapshot_warn=false" >> ${GITHUB_OUTPUT} + fi + - name: Check remote targets.json file + id: check_targets + run: | + expires=$(curl -s http://tuf.fleetctl.com/targets.json | jq -r '.signed.expires' | cut -c 1-10) + today=$(date "+%Y-%m-%d") + warning_at=$(date -d "$today + 30 day" "+%Y-%m-%d") + expires_sec=$(date -d "$expires" "+%s") + warning_at_sec=$(date -d "$warning_at" "+%s") - - name: Slack Timestamp Notification - if: ${{ steps.check_timestamp.outputs.timestamp_warn == 'true' }} - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 - with: - payload: | - { - "text": "${{ job.status }}\n${{ github.event.pull_request.html_url || github.event.head.html_url }}", - "blocks": [ - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "⚠️ TUF timestamp.json is about to expire or has already expired\nhttps://github.com/fleetdm/fleet/actions/runs/${{ github.run_id }}" + if [ "$expires_sec" -le "$warning_at_sec" ]; then + echo "targets_warn=true" >> ${GITHUB_OUTPUT} + else + echo "targets_warn=false" >> ${GITHUB_OUTPUT} + fi + + - name: Check remote root.json file + id: check_root + run: | + expires=$(curl -s http://tuf.fleetctl.com/root.json | jq -r '.signed.expires' | cut -c 1-10) + today=$(date "+%Y-%m-%d") + warning_at=$(date -d "$today + 30 day" "+%Y-%m-%d") + expires_sec=$(date -d "$expires" "+%s") + warning_at_sec=$(date -d "$warning_at" "+%s") + + if [ "$expires_sec" -le "$warning_at_sec" ]; then + echo "root_warn=true" >> ${GITHUB_OUTPUT} + else + echo "root_warn=false" >> ${GITHUB_OUTPUT} + fi + + - name: Slack timestamp notification + if: ${{ steps.check_timestamp.outputs.timestamp_warn == 'true' }} + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + with: + payload: | + { + "text": "${{ job.status }}\n${{ github.event.pull_request.html_url || github.event.head.html_url }}", + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "⚠️ TUF timestamp.json is about to expire or has already expired\nhttps://github.com/fleetdm/fleet/actions/runs/${{ github.run_id }}" + } } - } - ] - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_G_HELP_ENGINEERING_WEBHOOK_URL }} - SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_G_HELP_ENGINEERING_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK - - name: Slack Root Notification - if: ${{ steps.check_root.outputs.root_warn == 'true' }} - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 - with: - payload: | - { - "text": "${{ job.status }}\n${{ github.event.pull_request.html_url || github.event.head.html_url }}", - "blocks": [ - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "⚠️ TUF root.json is about to expire or has already expired\nhttps://github.com/fleetdm/fleet/actions/runs/${{ github.run_id }}" + - name: Slack snapshot notification + if: ${{ steps.check_snapshot.outputs.snapshot_warn == 'true' }} + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + with: + payload: | + { + "text": "${{ job.status }}\n${{ github.event.pull_request.html_url || github.event.head.html_url }}", + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "⚠️ TUF snapshot.json is about to expire or has already expired\nhttps://github.com/fleetdm/fleet/actions/runs/${{ github.run_id }}" + } } - } - ] - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_G_HELP_ENGINEERING_WEBHOOK_URL }} - SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_G_HELP_ENGINEERING_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + - name: Slack targets notification + if: ${{ steps.check_targets.outputs.targets_warn == 'true' }} + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + with: + payload: | + { + "text": "${{ job.status }}\n${{ github.event.pull_request.html_url || github.event.head.html_url }}", + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "⚠️ TUF targets.json is about to expire or has already expired\nhttps://github.com/fleetdm/fleet/actions/runs/${{ github.run_id }}" + } + } + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_G_HELP_ENGINEERING_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + + - name: Slack root notification + if: ${{ steps.check_root.outputs.root_warn == 'true' }} + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + with: + payload: | + { + "text": "${{ job.status }}\n${{ github.event.pull_request.html_url || github.event.head.html_url }}", + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "⚠️ TUF root.json is about to expire or has already expired\nhttps://github.com/fleetdm/fleet/actions/runs/${{ github.run_id }}" + } + } + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_G_HELP_ENGINEERING_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK diff --git a/.github/workflows/dogfood-gitops.yml b/.github/workflows/dogfood-gitops.yml index 487cdac1ad..4de0e454d0 100644 --- a/.github/workflows/dogfood-gitops.yml +++ b/.github/workflows/dogfood-gitops.yml @@ -48,13 +48,6 @@ jobs: ref: main path: fleet-gitops - - name: Apply env vars to profiles - env: - MANAGED_CHROME_ENROLLMENT_TOKEN: ${{ secrets.CLOUD_MANAGEMENT_ENROLLMENT_TOKEN }} - run: | - envsubst < ./it-and-security/lib/configuration-profiles/macos-chrome-enrollment.mobileconfig > ./it-and-security/lib/configuration-profiles/macos-chrome-enrollment.confidential.mobileconfig - mv ./it-and-security/lib/configuration-profiles/macos-chrome-enrollment.confidential.mobileconfig ./it-and-security/lib/configuration-profiles/macos-chrome-enrollment.mobileconfig - - name: Apply latest configuration to Fleet uses: ./fleet-gitops/.github/gitops-action with: @@ -81,4 +74,5 @@ jobs: DOGFOOD_CALENDAR_API_KEY: ${{ secrets.DOGFOOD_CALENDAR_API_KEY }} DOGFOOD_COMPLIANCE_EXCLUSIONS_ENROLL_SECRET: ${{ secrets.DOGFOOD_COMPLIANCE_EXCLUSIONS_ENROLL_SECRET }} DOGFOOD_COMPANY_OWNED_IPHONES_ENROLL_SECRET: ${{ secrets.DOGFOOD_COMPANY_OWNED_IPHONES_ENROLL_SECRET }} - DOGFOOD_COMPANY_OWNED_IPADS_ENROLL_SECRET: ${{ secrets.DOGFOOD_COMPANY_OWNED_IPADS_ENROLL_SECRET }} \ No newline at end of file + DOGFOOD_COMPANY_OWNED_IPADS_ENROLL_SECRET: ${{ secrets.DOGFOOD_COMPANY_OWNED_IPADS_ENROLL_SECRET }} + MANAGED_CHROME_ENROLLMENT_TOKEN: ${{ secrets.CLOUD_MANAGEMENT_ENROLLMENT_TOKEN }} diff --git a/articles/fleet-usage-statistics.md b/articles/fleet-usage-statistics.md index 1db24222de..80e3e63284 100644 --- a/articles/fleet-usage-statistics.md +++ b/articles/fleet-usage-statistics.md @@ -18,6 +18,7 @@ Below is the JSON payload that is sent to Fleet Device Management Inc: "numUsers": 999, "numTeams": 999, "numPolicies": 999, + "numQueries": 999, "numLabels": 999, "softwareInventoryEnabled": true, "vulnDetectionEnabled": true, diff --git a/articles/introducing-workbrew.md b/articles/introducing-workbrew.md index da05080bb7..218c9c1d3a 100644 --- a/articles/introducing-workbrew.md +++ b/articles/introducing-workbrew.md @@ -2,7 +2,7 @@ ![Fleet and Workbrew](../website/assets/images/articles/fleet-and-workbrew-1600x900@2x.png) -[Workbrew recently](https://workbrew.com/) made waves with its official launch, highlighted in a [TechCrunch article](https://techcrunch.com/2024/11/19/workbrew-makes-open-source-package-manager-homebrew-enterprise-friendly/). Backed by $5 million in funding from developer-focused VC firms like Heavybit and Operator Collective, Workbrew is tackling a critical challenge: transforming Homebrew from a developer-centric tool into a secure, enterprise-ready solution. +[Workbrew recently](https://workbrew.com/) made waves with its [official launch](https://workbrew.com/blog/workbrew-1-0), highlighted in a [TechCrunch article](https://techcrunch.com/2024/11/19/workbrew-makes-open-source-package-manager-homebrew-enterprise-friendly/). Backed by $5 million in funding from developer-focused VC firms like Heavybit and Operator Collective, Workbrew is tackling a critical challenge: transforming Homebrew from a developer-centric tool into a secure, enterprise-ready solution. ## Workbrew’s mission: From single-player to multiplayer diff --git a/assets/fonts/inter/Inter-Bold.woff2 b/assets/fonts/inter/Inter-Bold.woff2 index 158cfcfc1d..b9e3cb3b1f 100644 Binary files a/assets/fonts/inter/Inter-Bold.woff2 and b/assets/fonts/inter/Inter-Bold.woff2 differ diff --git a/assets/fonts/inter/Inter-Regular-Italic.woff2 b/assets/fonts/inter/Inter-Regular-Italic.woff2 index 490c1a8343..9a1ad2167a 100644 Binary files a/assets/fonts/inter/Inter-Regular-Italic.woff2 and b/assets/fonts/inter/Inter-Regular-Italic.woff2 differ diff --git a/assets/fonts/inter/Inter-Regular.woff2 b/assets/fonts/inter/Inter-Regular.woff2 index 9f3b53d398..2bcd222ecf 100644 Binary files a/assets/fonts/inter/Inter-Regular.woff2 and b/assets/fonts/inter/Inter-Regular.woff2 differ diff --git a/assets/fonts/inter/Inter-Semibold.woff2 b/assets/fonts/inter/Inter-Semibold.woff2 index 8be198d444..fbae113d28 100644 Binary files a/assets/fonts/inter/Inter-Semibold.woff2 and b/assets/fonts/inter/Inter-Semibold.woff2 differ diff --git a/changes/18539-font-bug b/changes/18539-font-bug new file mode 100644 index 0000000000..6827466068 --- /dev/null +++ b/changes/18539-font-bug @@ -0,0 +1 @@ +* Update Inter font to latest version for woff2 files \ No newline at end of file diff --git a/changes/22361-os-update-ade-sso b/changes/22361-os-update-ade-sso new file mode 100644 index 0000000000..40221866fb --- /dev/null +++ b/changes/22361-os-update-ade-sso @@ -0,0 +1,2 @@ +- Fixed issue where minimum OS version enforcement was not being applied during Apple ADE if MDM + IdP integration was enabled. diff --git a/changes/22819-delete-modal b/changes/22819-delete-modal new file mode 100644 index 0000000000..a1dc4e5b61 --- /dev/null +++ b/changes/22819-delete-modal @@ -0,0 +1 @@ +- Fleet UI: Better information on what deleting a host does diff --git a/changes/23158-turn-off-windows-mdm-err b/changes/23158-turn-off-windows-mdm-err new file mode 100644 index 0000000000..4bc7d28c8e --- /dev/null +++ b/changes/23158-turn-off-windows-mdm-err @@ -0,0 +1 @@ +- Adds a clearer error message when users attempt to turn MDM off on a Windows host. \ No newline at end of file diff --git a/changes/23458-additional-stats b/changes/23458-additional-stats new file mode 100644 index 0000000000..73587d4def --- /dev/null +++ b/changes/23458-additional-stats @@ -0,0 +1 @@ +- Added additional statistics item for number of saved queries diff --git a/changes/23749-fix-learn-more-link b/changes/23749-fix-learn-more-link new file mode 100644 index 0000000000..d10d50f701 --- /dev/null +++ b/changes/23749-fix-learn-more-link @@ -0,0 +1 @@ +- Fleet UI: Fix learn more about JIT provisioning link diff --git a/changes/23758-use-fleethttp-client-for-apns-push-notifications b/changes/23758-use-fleethttp-client-for-apns-push-notifications new file mode 100644 index 0000000000..08a6eebba6 --- /dev/null +++ b/changes/23758-use-fleethttp-client-for-apns-push-notifications @@ -0,0 +1 @@ +* Fixed a bug where the HTTP client used for MDM APNs push notifications did not support using a configured proxy. diff --git a/changes/24024-no-setup-exp b/changes/24024-no-setup-exp new file mode 100644 index 0000000000..44ab42bcf0 --- /dev/null +++ b/changes/24024-no-setup-exp @@ -0,0 +1,2 @@ +- Modifies the Fleet setup experience feature to not run if there is no software or script + configured for the setup experience. \ No newline at end of file diff --git a/cmd/fleet/serve.go b/cmd/fleet/serve.go index 4923cb95ad..a523a91bac 100644 --- a/cmd/fleet/serve.go +++ b/cmd/fleet/serve.go @@ -22,6 +22,7 @@ import ( "github.com/e-dard/netbug" "github.com/fleetdm/fleet/v4/ee/server/licensing" eeservice "github.com/fleetdm/fleet/v4/ee/server/service" + "github.com/fleetdm/fleet/v4/pkg/fleethttp" "github.com/fleetdm/fleet/v4/pkg/scripts" "github.com/fleetdm/fleet/v4/server" configpkg "github.com/fleetdm/fleet/v4/server/config" @@ -498,7 +499,11 @@ the way that the Fleet server works. var mdmPushService push.Pusher nanoMDMLogger := service.NewNanoMDMLogger(kitlog.With(logger, "component", "apple-mdm-push")) - pushProviderFactory := buford.NewPushProviderFactory() + pushProviderFactory := buford.NewPushProviderFactory(buford.WithNewClient(func(cert *tls.Certificate) (*http.Client, error) { + return fleethttp.NewClient(fleethttp.WithTLSClientConfig(&tls.Config{ + Certificates: []tls.Certificate{*cert}, + })), nil + })) if os.Getenv("FLEET_DEV_MDM_APPLE_DISABLE_PUSH") == "1" { mdmPushService = nopPusher{} } else { @@ -1029,6 +1034,9 @@ the way that the Fleet server works. "get_frontend", service.ServeFrontend(config.Server.URLPrefix, config.Server.SandboxEnabled, httpLogger), ) + + frontendHandler = service.WithMDMEnrollmentMiddleware(svc, httpLogger, frontendHandler) + apiHandler = service.MakeHandler(svc, config, httpLogger, limiterStore) setupRequired, err := svc.SetupRequired(baseCtx) diff --git a/cmd/fleet/serve_test.go b/cmd/fleet/serve_test.go index 24175ef1ba..f18bfe391e 100644 --- a/cmd/fleet/serve_test.go +++ b/cmd/fleet/serve_test.go @@ -100,6 +100,7 @@ func TestMaybeSendStatistics(t *testing.T) { NumSoftwareCVEs: 105, NumTeams: 9, NumPolicies: 0, + NumQueries: 200, NumLabels: 3, SoftwareInventoryEnabled: true, VulnDetectionEnabled: true, @@ -139,7 +140,7 @@ func TestMaybeSendStatistics(t *testing.T) { require.NoError(t, err) assert.True(t, recorded) require.True(t, cleanedup) - assert.Equal(t, `{"anonymousIdentifier":"ident","fleetVersion":"1.2.3","licenseTier":"premium","organization":"Fleet","numHostsEnrolled":999,"numUsers":99,"numSoftwareVersions":100,"numHostSoftwares":101,"numSoftwareTitles":102,"numHostSoftwareInstalledPaths":103,"numSoftwareCPEs":104,"numSoftwareCVEs":105,"numTeams":9,"numPolicies":0,"numLabels":3,"softwareInventoryEnabled":true,"vulnDetectionEnabled":true,"systemUsersEnabled":true,"hostsStatusWebHookEnabled":true,"mdmMacOsEnabled":false,"hostExpiryEnabled":false,"mdmWindowsEnabled":false,"liveQueryDisabled":false,"numWeeklyActiveUsers":111,"numWeeklyPolicyViolationDaysActual":0,"numWeeklyPolicyViolationDaysPossible":0,"hostsEnrolledByOperatingSystem":{"linux":[{"version":"1.2.3","numEnrolled":22}]},"hostsEnrolledByOrbitVersion":[],"hostsEnrolledByOsqueryVersion":[],"storedErrors":[],"numHostsNotResponding":0,"aiFeaturesDisabled":true,"maintenanceWindowsEnabled":true,"maintenanceWindowsConfigured":true,"numHostsFleetDesktopEnabled":1984}`, requestBody) + assert.Equal(t, `{"anonymousIdentifier":"ident","fleetVersion":"1.2.3","licenseTier":"premium","organization":"Fleet","numHostsEnrolled":999,"numUsers":99,"numSoftwareVersions":100,"numHostSoftwares":101,"numSoftwareTitles":102,"numHostSoftwareInstalledPaths":103,"numSoftwareCPEs":104,"numSoftwareCVEs":105,"numTeams":9,"numPolicies":0,"numQueries":200,"numLabels":3,"softwareInventoryEnabled":true,"vulnDetectionEnabled":true,"systemUsersEnabled":true,"hostsStatusWebHookEnabled":true,"mdmMacOsEnabled":false,"hostExpiryEnabled":false,"mdmWindowsEnabled":false,"liveQueryDisabled":false,"numWeeklyActiveUsers":111,"numWeeklyPolicyViolationDaysActual":0,"numWeeklyPolicyViolationDaysPossible":0,"hostsEnrolledByOperatingSystem":{"linux":[{"version":"1.2.3","numEnrolled":22}]},"hostsEnrolledByOrbitVersion":[],"hostsEnrolledByOsqueryVersion":[],"storedErrors":[],"numHostsNotResponding":0,"aiFeaturesDisabled":true,"maintenanceWindowsEnabled":true,"maintenanceWindowsConfigured":true,"numHostsFleetDesktopEnabled":1984}`, requestBody) } func TestMaybeSendStatisticsSkipsSendingIfNotNeeded(t *testing.T) { diff --git a/docs/Contributing/API-for-contributors.md b/docs/Contributing/API-for-contributors.md index b8a5a82fb8..18cfc569f6 100644 --- a/docs/Contributing/API-for-contributors.md +++ b/docs/Contributing/API-for-contributors.md @@ -2790,7 +2790,7 @@ Device-authenticated routes are routes used by the Fleet Desktop application. Un - [Get device's transparency URL](#get-devices-transparency-url) - [Download device's MDM manual enrollment profile](#download-devices-mdm-manual-enrollment-profile) - [Migrate device to Fleet from another MDM solution](#migrate-device-to-fleet-from-another-mdm-solution) -- [Trigger FileVault key escrow](#trigger-filevault-key-escrow) +- [Trigger Linux disk encryption escrow](#trigger-linux-disk-encryption-escrow) - [Report an agent error](#report-an-agent-error) #### Refetch device's host @@ -2876,7 +2876,6 @@ Gets all information required by Fleet Desktop, this includes things like the nu "notifications": { "needs_mdm_migration": true, "renew_enrollment_profile": false, - "enforce_bitlocker_encryption": false, }, "config": { "org_info": { @@ -2898,8 +2897,6 @@ In regards to the `notifications` key: - `needs_mdm_migration` means that the device fits all the requirements to allow the user to initiate an MDM migration to Fleet. - `renew_enrollment_profile` means that the device is currently unmanaged from MDM but should be DEP enrolled into Fleet. -- `enforce_bitlocker_encryption` applies only to Windows devices and means that it should encrypt the disk and report the encryption key back to Fleet. - #### Get device's software @@ -3098,7 +3095,7 @@ This supports the dynamic discovery of API features supported by the server for #### Get device's transparency URL -Returns the URL to open when clicking the "Transparency" menu item in Fleet Desktop. Note that _Fleet Premium_ is required to configure a custom transparency URL. +Returns the URL to open when clicking the "About Fleet" menu item in Fleet Desktop. Note that _Fleet Premium_ is required to configure a custom transparency URL. `GET /api/v1/fleet/device/{token}/transparency` @@ -3170,6 +3167,30 @@ Signals the Fleet server to send a webbook request with the device UUID and seri --- +### Trigger Linux disk encryption escrow + +_Available in Fleet Premium_ + +Signals the fleet server to queue up the LUKS disk encryption escrow process (LUKS passphrase and slot key). If validation succeeds (disk encryption must be enforced for the team, the host's platform must be supported, the host's disk must already be encrypted, and the host's Orbit version must be new enough), this adds a notification flag for Orbit that, triggers escrow from the Orbit side. + +`POST /api/v1/fleet/device/{token}/mdm/linux/trigger_escrow` + +##### Parameters + +| Name | Type | In | Description | +| ----- | ------ | ---- | ---------------------------------- | +| token | string | path | The device's authentication token. | + +##### Example + +`POST /api/v1/fleet/device/abcdef012456789/mdm/linux/trigger_escrow` + +##### Default response + +`Status: 204` + +--- + ### Report an agent error Notifies the server about an agent error, resulting in two outcomes: @@ -3199,8 +3220,46 @@ Notifies the server about an agent error, resulting in two outcomes: ## Orbit-authenticated routes +- [Escrow LUKS data](#escrow-luks-data) - [Get the status of a device in the setup experience](#get-the-status-of-a-device-in-the-setup-experience) +--- + +### Escrow LUKS data + +`POST /api/fleet/orbit/luks_data` + +##### Parameters + +| Name | Type | In | Description | +| ----- | ------ | ---- | ---------------------------------- | +| orbit_node_key | string | body | The Orbit's node key for authentication. | +| client_error | string | body | An error description if the LUKS key escrow process fails client-side. If provided, passphrase/salt/key slot request parameters are ignored and may be omitted. | +| passphrase | string | body | The LUKS passphrase generated for Fleet (the end user's existing passphrase is not transmitted) | +| key_slot | int | body | The LUKS key slot ID corresponding to the provided passphrase | +| salt | string | body | The salt corresponding to the specified LUKS key slot. Provided to track cases where an end user rotates LUKS credentials (at which point we'll no longer be able to decrypt data with the escrowed passphrase). | + +##### Example + +`POST /api/v1/fleet/orbit/luks_data` + +##### Request body + +```json +{ + "orbit_node_key":"FbvSsWfTRwXEecUlCBTLmBcjGFAdzqd/", + "passphrase": "6e657665-7220676f-6e6e6120-67697665-20796f75-207570", + "salt": "d34db33f", + "key_slot": 1, + "client_error": "" +} +``` + +##### Default response + +`Status: 204` + +--- ### Get the status of a device in the setup experience diff --git a/docs/Deploy/Reference-Architectures.md b/docs/Deploy/Reference-Architectures.md index eecc179c36..54f4aac43d 100644 --- a/docs/Deploy/Reference-Architectures.md +++ b/docs/Deploy/Reference-Architectures.md @@ -30,6 +30,8 @@ Fleet requires at least MySQL version 8.0.36, and is tested using the InnoDB sto There are many "drop-in replacements" for MySQL available. If you'd like to experiment with some bleeding-edge technology and use Fleet with one of these alternative database servers, we think that's awesome! Please be aware they are not officially supported and that it is very important to set up a dev environment to thoroughly test new releases. +> If you use multiple databases per database server for multiple Fleet instances, you'll need to provision more resources for your database server to ensure performance. You can experiment with finding the right resourcing for your needs. + ### Redis Fleet uses Redis to ingest and queue the results of distributed queries, cache data, etc. Many cloud providers (such as [AWS](https://aws.amazon.com/elasticache/) and [GCP](https://console.cloud.google.com/launcher/details/click-to-deploy-images/redis)) host reliable Redis services which you may consider for this purpose. A well supported Redis [Docker image](https://hub.docker.com/_/redis/) also exists if you would rather run Redis in a container. For more information on how to configure the `fleet` binary to use the correct Redis instance, see the [Redis configuration](https://fleetdm.com/docs/configuration/fleet-server-configuration#redis) documentation. diff --git a/docs/Deploy/deploy-fleet.md b/docs/Deploy/deploy-fleet.md index a113002f28..97ed84bfab 100644 --- a/docs/Deploy/deploy-fleet.md +++ b/docs/Deploy/deploy-fleet.md @@ -143,3 +143,4 @@ This workflow takes about 30 minutes to complete and supports between 10 and 350 + diff --git a/ee/server/service/teams.go b/ee/server/service/teams.go index 20a526197b..eded9b4788 100644 --- a/ee/server/service/teams.go +++ b/ee/server/service/teams.go @@ -1516,15 +1516,15 @@ func unmarshalWithGlobalDefaults(b *json.RawMessage) (fleet.Features, error) { } func (svc *Service) updateTeamMDMDiskEncryption(ctx context.Context, tm *fleet.Team, enable *bool) error { - var didUpdate, didUpdateMacOSDiskEncryption bool + var didUpdate bool if enable != nil { - if svc.config.Server.PrivateKey == "" { - return ctxerr.New(ctx, "Missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key") - } if tm.Config.MDM.EnableDiskEncryption != *enable { + if *enable && svc.config.Server.PrivateKey == "" { + return ctxerr.New(ctx, "Missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key") + } + tm.Config.MDM.EnableDiskEncryption = *enable didUpdate = true - didUpdateMacOSDiskEncryption = true } } @@ -1537,13 +1537,7 @@ func (svc *Service) updateTeamMDMDiskEncryption(ctx context.Context, tm *fleet.T if err != nil { return err } - - // macOS-specific stuff. For legacy reasons we check if apple is configured - // via `appCfg.MDM.EnabledAndConfigured` - // - // TODO: is there a missing bitlocker activity feed item? (see same TODO on - // other methods that deal with disk encryption) - if appCfg.MDM.EnabledAndConfigured && didUpdateMacOSDiskEncryption { + if appCfg.MDM.EnabledAndConfigured { var act fleet.ActivityDetails if tm.Config.MDM.EnableDiskEncryption { act = fleet.ActivityTypeEnabledMacosDiskEncryption{TeamID: &tm.ID, TeamName: &tm.Name} diff --git a/frontend/pages/admin/OrgSettingsPage/cards/Sso/Sso.tsx b/frontend/pages/admin/OrgSettingsPage/cards/Sso/Sso.tsx index 3e6e33a516..7618e51a1b 100644 --- a/frontend/pages/admin/OrgSettingsPage/cards/Sso/Sso.tsx +++ b/frontend/pages/admin/OrgSettingsPage/cards/Sso/Sso.tsx @@ -8,6 +8,7 @@ import InputField from "components/forms/fields/InputField"; import validUrl from "components/forms/validators/valid_url"; import SectionHeader from "components/SectionHeader"; +import { LEARN_MORE_ABOUT_BASE_LINK } from "utilities/constants"; import { IAppConfigFormProps, IFormField } from "../constants"; const baseClass = "app-config-form"; @@ -209,15 +210,18 @@ const Sso = ({ name="enableJitProvisioning" value={enableJitProvisioning} parseTarget + helpText={ + <> + {" "} + about just-in-time (JIT) user provisioning. + + } > - <> - Create user and sync permissions on login{" "} - - + Create user and sync permissions on login )}