mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 00:45:19 +00:00
Add a tool to generate manifests for Apple MDM (#10959)
Related to #9459 this will allow us to host a `fleetd` metadata alongside the installer that can be used by Apple's MDM `InstallEnterpriseApplication`
This commit is contained in:
parent
ee135fe06b
commit
ab583d66e6
39
server/mdm/apple/appmanifest/appmanifest.go
Normal file
39
server/mdm/apple/appmanifest/appmanifest.go
Normal file
@ -0,0 +1,39 @@
|
||||
// package appmanifest provides utilities for managing app manifest files
|
||||
// used by MDM InstallApplication commands.
|
||||
//
|
||||
// It's heavily based on the micromdm/mdm/appmanifest package but it uses
|
||||
// SHA256 as the hashing algorithm instead of MD5.
|
||||
package appmanifest
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/micromdm/micromdm/mdm/appmanifest"
|
||||
)
|
||||
|
||||
// Create builds an AppManifest using SHA256 checksums and the provided URL
|
||||
func Create(file io.Reader, url string) (*appmanifest.Manifest, error) {
|
||||
hash := sha256.New()
|
||||
if _, err := io.Copy(hash, file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sum := fmt.Sprintf("%x", hash.Sum(nil))
|
||||
|
||||
ast := appmanifest.Asset{
|
||||
Kind: "software-package",
|
||||
SHA256Size: int64(hash.Size()),
|
||||
SHA256s: []string{sum},
|
||||
URL: url,
|
||||
}
|
||||
|
||||
return &appmanifest.Manifest{
|
||||
ManifestItems: []appmanifest.Item{
|
||||
{
|
||||
Assets: []appmanifest.Asset{ast},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
52
server/mdm/apple/appmanifest/appmanifest_test.go
Normal file
52
server/mdm/apple/appmanifest/appmanifest_test.go
Normal file
@ -0,0 +1,52 @@
|
||||
package appmanifest
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/micromdm/micromdm/mdm/appmanifest"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var errTest = errors.New("test error")
|
||||
|
||||
type alwaysFailReader struct{}
|
||||
|
||||
func (alwaysFailReader) Read(p []byte) (n int, err error) {
|
||||
return 0, errTest
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
url := "https://test.example.com"
|
||||
|
||||
cases := []struct {
|
||||
in io.Reader
|
||||
out *appmanifest.Manifest
|
||||
err error
|
||||
}{
|
||||
{
|
||||
in: strings.NewReader("foo"),
|
||||
out: &appmanifest.Manifest{
|
||||
ManifestItems: []appmanifest.Item{{Assets: []appmanifest.Asset{{
|
||||
Kind: "software-package",
|
||||
SHA256Size: 32,
|
||||
SHA256s: []string{"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"},
|
||||
URL: "https://test.example.com",
|
||||
}}}}},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
in: alwaysFailReader{},
|
||||
out: nil,
|
||||
err: errTest,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
m, err := Create(c.in, url)
|
||||
require.Equal(t, c.out, m)
|
||||
require.Equal(t, c.err, err)
|
||||
}
|
||||
}
|
36
tools/mdm/apple/appmanifest/README.md
Normal file
36
tools/mdm/apple/appmanifest/README.md
Normal file
@ -0,0 +1,36 @@
|
||||
## appmanifest
|
||||
|
||||
`appmanifest` is a tool that outputs to stdout a valid XML manifest that can be used by the MDM `InstallEnterpriseApplication` command to install a package.
|
||||
|
||||
```
|
||||
$ go run tools/mdm/apple/appmanifest/main.go --help
|
||||
Usage of appmanifest:
|
||||
-pkg-file string
|
||||
Path to a .pkg file
|
||||
-pkg-url string
|
||||
URL where the package will be served
|
||||
```
|
||||
|
||||
### Example workflow
|
||||
|
||||
1. Create a fleetd installer
|
||||
|
||||
```
|
||||
fleetctl package --type=pkg --fleet-desktop
|
||||
```
|
||||
|
||||
2. Sign the installer so it can be installed via MDM
|
||||
|
||||
```
|
||||
productsign --sign "Developer ID Installer: $DEVID_INFO" fleet-osquery.pkg fleetd-base.pkg
|
||||
```
|
||||
|
||||
3. Run `appmanifest`
|
||||
|
||||
```
|
||||
$ go run tools/mdm/apple/appmanifest/main.go \
|
||||
-pkg-file fleetd-base.pkg \
|
||||
-pkg-url $YOUR_URL > fleetd-base-manifest.plist
|
||||
```
|
||||
|
||||
4. Upload `fleetd-base.pkg` to `$YOUR_URL` and `fleetd-base-manifest.plist` to a publicly accessible location.
|
43
tools/mdm/apple/appmanifest/main.go
Normal file
43
tools/mdm/apple/appmanifest/main.go
Normal file
@ -0,0 +1,43 @@
|
||||
// Command appmanifest takes a .pkg file and outputs an XML manifest for it
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/apple/appmanifest"
|
||||
"github.com/groob/plist"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pkgFile := flag.String("pkg-file", "", "Path to a .pkg file")
|
||||
pkgURL := flag.String("pkg-url", "", "URL where the package will be served")
|
||||
flag.Parse()
|
||||
|
||||
if *pkgFile == "" || *pkgURL == "" {
|
||||
log.Fatal("both --pkg-file and --pkg-url must be provided")
|
||||
}
|
||||
|
||||
fp, err := os.Open(*pkgFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
m, err := appmanifest.Create(fp, *pkgURL)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
enc := plist.NewEncoder(&buf)
|
||||
enc.Indent(" ")
|
||||
if err := enc.Encode(m); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(buf.String())
|
||||
}
|
Loading…
Reference in New Issue
Block a user