7.7 KiB
Android
Reference links
Using Android MDM for development
By default, Fleet server uses fleetdm.com proxy to access the Google Android Management API. However, the proxy limits each Fleet server URL to 1 Android enterprise. This means that you should turn off Android MDM before wiping your development DB.
You can also setup a local proxy or use the Google API directly.
Android MDM can't be turned on with localhost server URL (e.g. https://localhost:8412), so your server can receive
STATUS_REPORTvia PubSub notifications. Use ngrok or a similar solution to expose your local server to the public internet.
Setup a Google project and service account
Instead of creating your own, you can use the shared Android DEV Google cloud project. The credentials for the Android DEV google cloud project can be found in 1Password.
Create a Google service account with the following Roles
- Android Management User
- Pub/Sub Admin
To do so:
- Follow instructions at https://developers.google.com/android/management/service-account to create the project and service account
- Follow instructions at https://developers.google.com/android/management/notifications to create pub/sub notifications
- Troubleshooting: watch the video of Gabe and Victor discussion post-standup: https://us-65885.app.gong.io/call?id=4731209913082368849 (starting at the 12:50 timestamp)
Run an Android MDM environment with a local proxy
If you're hosting your own Fleet website instance, you need to set the following in website/config/custom.js:
// Android proxy
androidEnterpriseProjectId: 'yourProject-123456',
androidEnterpriseServiceAccountEmailAddress: 'yourUser@yourProject-123456.iam.gserviceaccount.com',
androidEnterpriseServiceAccountPrivateKey: '-----BEGIN PRIVATE KEY-----\nDATA\n-----END PRIVATE KEY-----\n',
And also set the following env var for your Fleet server:
export FLEET_DEV_ANDROID_PROXY_ENDPOINT=https://public.url.of.your.website/api/endpoint/
Then, launch the website and your Fleet server.
Run an Android MDM environment connected directly to Google
Set the following env vars:
export FLEET_DEV_ANDROID_GOOGLE_CLIENT=1
export FLEET_DEV_ANDROID_GOOGLE_SERVICE_CREDENTIALS=$(cat credentials.json)
To turn on Android MDM, use a Chrome private window (so that you are not logged in with your "fleetdm.com" address). This is only required to enable Android MDM, you can use a normal window for the rest. In "Settings -> Integrations -> MDM -> Turn On Android -> Connect", use a personal email address (not a "fleetdm.com" one). Select "Sign-up for Android only". Domain name is not important ("test.com" for example). No need to fill anything in the "Data protection officer" and "EU representative" sections, just check the checkbox.
If it fails enabling Android MDM due to an already existing enterprise (error "This enterprise is already enrolled with another EMM." when attempting to enable it again) and a personal (gmail) account was used, you must go to https://play.google.com/work, click "Admin settings", and delete the organization that was created the last time (e.g. "test.com"). You will then be able to enable Android MDM again.
There's also a command-line tool in tools/android that can list/delete/etc. enterprises associated with the service account.
Known issues and limitations
- The Fleet server URL must be public for pub/sub to work properly.
- The Fleet server URL cannot change -- pub/sub is set up with one URL. See issue Allow Fleet server URL update when using Android
- Network reliability issues may leave the Android enterprise flow in a broken state. For example, if fleetdm.com proxy creates an Android enterprise but Fleet server goes offline and does not receive the secret key.
Architecture diagrams
---
title: Enable Android MDM
---
sequenceDiagram
autonumber
actor Admin
participant Fleet server
participant fleetdm.com
participant Google
Admin->>+Fleet server: Enable Android
Fleet server->>+fleetdm.com: Get signup url
fleetdm.com->>+Google: Get signup url
Google-->>-fleetdm.com: Signup url
fleetdm.com-->>-Fleet server: Signup url
Fleet server->>-Admin: UI redirect (new page)
Admin->>Google: Enterprise signup
activate Google
Google->>Fleet server: Signup callback
deactivate Google
activate Fleet server
Fleet server->>+fleetdm.com: Create enterprise/policy/pubsub
fleetdm.com->>+Google: Create enterprise/policy/pubsub
Google-->>-fleetdm.com: Created
fleetdm.com-->>-Fleet server: Created
Fleet server->>Admin: Self-closing HTML page
Fleet server--)Admin: Android enabled (SSE)
deactivate Fleet server
---
title: Enroll BYOD Android device
---
sequenceDiagram
autonumber
actor Admin
actor Employee
participant Enroll page
participant Fleet server
participant fleetdm.com
participant Google
Admin->>+Fleet server: Get signup link
Fleet server-->>-Admin: Signup link
Admin->>Employee: Email signup link
Employee->>+Fleet server: Click signup link
Fleet server-->>-Enroll page: HTML page
Employee->>+Enroll page: Click enroll
Enroll page->>+Fleet server: Get enroll token
Fleet server->>+fleetdm.com: Get enroll token
fleetdm.com->>+Google: Get enroll token
Google-->>-fleetdm.com: Enroll token
fleetdm.com-->>-Fleet server: Enroll token
Fleet server-->>-Enroll page: Enroll token
Enroll page->>-Employee: Redirect to enroll flow
Employee->>+Google: Enroll device
Google-->>Employee: Device enrolled
Google--)Fleet server: Pub/Sub push: ENROLLMENT
Google--)-Fleet server: Pub/Sub push: STATUS_REPORT
Admin->>+Fleet server: Get hosts
Fleet server-->>-Admin: Hosts (including Android)
---
title: Partial class diagram
config:
class:
hideEmptyMembersBox: true
---
classDiagram
direction LR
class `android.Service`
<<interface>> `android.Service`
class `android/service.Service`
`android/service.Service` ..|> `android.Service`: implements
class `fleet.AndroidDatastore`
<<interface>> `fleet.AndroidDatastore`
class `fleet.Datastore`
<<interface>> `fleet.Datastore`
class `android.Datastore`
<<interface>> `android.Datastore`
`android/service.Service` *-- `fleet.AndroidDatastore`: uses
`fleet.Datastore` *-- `fleet.AndroidDatastore`: contains
`mysql.Datastore` ..|> `fleet.Datastore`: implements
`fleet.AndroidDatastore` *-- `android.Datastore`: contains
`mysql.Datastore` *-- `android.Datastore`: contains
`android/mysql.Datastore` ..|> `android.Datastore`: implements
Security and authentication
Android enterprise signup callback is authenticated by a token in the callback URL. The token is created by Fleet server.
Getting the Android device enrollment token is authenticated with the Fleet enroll secret.
Pub/sub push callback is authenticated by a token query parameter. This token is created by Fleet server. As of June 2025, this token cannot be easily rotated. We could add another level of authentication where the Fleet server would need to check with Google to authenticate the pub/sub message: