Add a tool to extract MDM assets from a Fleet database (#20659)

This commit is contained in:
Roberto Dip 2024-07-23 13:11:18 -05:00 committed by GitHub
parent ea354ef479
commit 650914519d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 135 additions and 0 deletions

View file

@ -0,0 +1,30 @@
## MDM asset extractor
The MDM Asset Extractor is a tool designed to extract all MDM assets from a
Fleet database. The assets are extracted unencrypted; hence, the key used for
encrypting the assets must be provided.
### Usage
During development, a typical usage example would be:
```
go run tools/mdm/assets/main.go -key=E6Ow1t2dbKARxEF6O9GFI3DDQRMROhI8 -dir=mdm_assets
```
Supported flags are:
```
-db-address string
Address used to connect to the MySQL instance (default "localhost:3306")
-db-name string
Name of the database with the asset information in the MySQL instance (default "fleet")
-db-password string
Password used to connect to the MySQL instance (default "insecure")
-db-user string
Username used to connect to the MySQL instance (default "fleet")
-dir string
Directory to put the exported assets
-key string
Key used to encrypt the assets
```

105
tools/mdm/assets/main.go Normal file
View file

@ -0,0 +1,105 @@
package main
import (
"context"
"database/sql"
"errors"
"flag"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"github.com/WatchBeam/clock"
"github.com/fleetdm/fleet/v4/server/config"
"github.com/fleetdm/fleet/v4/server/datastore/mysql"
"github.com/fleetdm/fleet/v4/server/fleet"
)
const (
testUsername = "fleet"
testPassword = "insecure"
testAddress = "localhost:3306"
testDatabase = "fleet"
)
func main() {
flagKey := flag.String("key", "", "Key used to encrypt the assets")
flagDir := flag.String("dir", "", "Directory to put the exported assets")
flagDBUser := flag.String("db-user", testUsername, "Username used to connect to the MySQL instance")
flagDBPass := flag.String("db-password", testPassword, "Password used to connect to the MySQL instance")
flagDBAddress := flag.String("db-address", testAddress, "Address used to connect to the MySQL instance")
flagDBName := flag.String("db-name", testDatabase, "Name of the database with the asset information in the MySQL instance")
flag.Parse()
if *flagKey == "" {
log.Fatal("-key flag is required")
}
if *flagDir != "" {
if err := os.MkdirAll(*flagDir, os.ModePerm); err != nil {
log.Fatal("ensuring directory: ", err)
}
}
db, err := sql.Open(
"mysql",
fmt.Sprintf("%s:%s@tcp(%s)/?multiStatements=true", testUsername, testPassword, testAddress),
)
if err != nil {
log.Fatal("opening MySQL connection:", err)
}
defer db.Close()
mysqlCfg := config.MysqlConfig{
Username: *flagDBUser,
Password: *flagDBPass,
Address: *flagDBAddress,
Database: *flagDBName,
}
ds, err := mysql.New(
mysqlCfg,
clock.NewMockClock(),
mysql.LimitAttempts(1),
mysql.WithFleetConfig(&config.FleetConfig{
Server: config.ServerConfig{
PrivateKey: *flagKey,
},
}),
)
if err != nil {
log.Fatal("creating datastore instance:", err)
}
defer ds.Close()
ctx := context.Background()
assets, err := ds.GetAllMDMConfigAssetsByName(ctx, []fleet.MDMAssetName{
fleet.MDMAssetCACert,
fleet.MDMAssetCAKey,
fleet.MDMAssetAPNSKey,
fleet.MDMAssetAPNSCert,
fleet.MDMAssetABMCert,
fleet.MDMAssetABMKey,
fleet.MDMAssetABMToken,
fleet.MDMAssetSCEPChallenge,
})
if err != nil && !errors.Is(err, mysql.ErrPartialResult) {
log.Fatal("retrieving assets from db:", err)
}
for _, asset := range assets {
path := filepath.Join(*flagDir, string(asset.Name))
switch {
case strings.Contains(path, "_key"):
path = path + ".key"
case strings.Contains(path, "_cert"):
path = path + ".crt"
}
if err := os.WriteFile(path, asset.Value, 0600); err != nil {
log.Fatal("writing asset:", err)
}
log.Printf("wrote %s in %s", asset.Name, path)
}
}