Skip to content

Commit 2352495

Browse files
committed
update README
1 parent b7c0b5a commit 2352495

File tree

3 files changed

+144
-32
lines changed

3 files changed

+144
-32
lines changed

Makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,13 @@ build-openbsd:
6060
GOOS=openbsd GOARCH=amd64 $(GOBUILD) $(BUILD_FLAGS) -o $(SERVER_BINARY)-openbsd-amd64 $(SERVER_PATH)
6161
GOOS=openbsd GOARCH=amd64 $(GOBUILD) $(BUILD_FLAGS) -o $(AGENT_BINARY)-openbsd-amd64 $(AGENT_PATH)
6262

63-
build-all: build-linux build-darwin build-freebsd build-openbsd
63+
build-windows:
64+
GOOS=windows GOARCH=amd64 $(GOBUILD) $(BUILD_FLAGS) -o $(SERVER_BINARY)-windows-amd64.exe $(SERVER_PATH)
65+
GOOS=windows GOARCH=amd64 $(GOBUILD) $(BUILD_FLAGS) -o $(AGENT_BINARY)-windows-amd64.exe $(AGENT_PATH)
66+
GOOS=windows GOARCH=arm64 $(GOBUILD) $(BUILD_FLAGS) -o $(SERVER_BINARY)-windows-arm64.exe $(SERVER_PATH)
67+
GOOS=windows GOARCH=arm64 $(GOBUILD) $(BUILD_FLAGS) -o $(AGENT_BINARY)-windows-arm64.exe $(AGENT_PATH)
68+
69+
build-all: build-linux build-darwin build-freebsd build-openbsd build-windows
6470

6571
ko-build:
6672
ko build --bare ./cmd/server

README.md

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
# gitMDM 🧪
1+
# gitMDM
22

3-
The MDM for folks that care about security.
3+
The SOC-2 compliance solution for the discerningly paranoid security engineer.
4+
5+
![logo](./media/logo_small.png "gitMDM logo")
46

57
## Your Problem
68

79
Your startup just hit the enterprise sales milestone where someone asks "are you SOC 2 compliant?" Meanwhile, your engineering team runs OpenBSD on ThinkPads, Arch on Frameworks, and that one person still dailying Plan 9.
810

9-
Traditional MDMs run as root, execute arbitrary code from their cloud servers, and auto-install binaries downloaded from the internet. Your security engineer just had an aneurysm.
11+
Traditional MDMs run as root, execute arbitrary code from cloud servers, and auto-install binaries downloaded from the internet. Your security engineer just had an aneurysm.
1012

1113
## Our Solution
1214

@@ -30,43 +32,47 @@ Your Team: "...continue"
3032

3133
## Demo
3234

33-
Visit our demo instance at https://gitmdm.codegroove.dev/
35+
Visit our demo instance at https://gitmdm.codegroove.dev/ - OK, so it's actually our prod instance.
36+
37+
## Quick Start
3438

35-
## Quick Start for the Impatient
39+
Build static binaries:
40+
41+
```bash
42+
make all
43+
```
44+
45+
Run a server:
3646

3747
```bash
38-
# On your secure server (Cloud Run, or laptop, we don't judge)
3948
./gitmdm-server -git /opt/compliance
49+
```
4050

41-
# On your OpenBSD machine
42-
$ doas pkg_add gitmdm-agent # just kidding, compile it yourself
43-
$ ./gitmdm-agent --install --server https://comply.internal --join XXXX
51+
If you are a fan of Google Cloud Run, check out `./hacks/deploy.sh` for a deployment script.
4452

45-
# On your Linux laptop
46-
$ ./gitmdm-agent --install --server https://comply.internal --join XXXX
53+
On a client:
4754

48-
# On that Mac the designer insisted on
55+
```bash
4956
$ ./gitmdm-agent --install --server https://comply.internal --join XXXX
5057
```
5158

52-
## What SOC 2 Actually Requires vs What We Check
59+
## What kind of checks do we do?
5360

54-
| SOC 2 Says | Traditional MDMs Do | We Do |
55-
|------------|---------------------|--------|
56-
| Disk encryption | Run as root to verify and enforce | Check encryption status as user |
57-
| Screen locks | Execute scripts as root to enforce policies | Read your existing screensaver config |
58-
| OS updates | Download and install updates as root | Report current version numbers |
59-
| Firewall enabled | Execute commands as root to modify rules | Check firewall status (read-only) |
61+
* Full Disk Encryption
62+
* Screen locks
63+
* OS updates
64+
* Firewall
6065

61-
## Platform Detection That Actually Works
66+
## What kind of bizarre platforms do you support?
6267

6368
```yaml
6469
# Your snowflake setups, our problem:
6570
- MATE on OpenBSD (we see you)
6671
- Sway on Alpine (of course)
6772
- i3 on Debian (classic)
6873
- Whatever that custom Wayland compositor you wrote is
69-
- Even macOS (unfortunate, but supported)
74+
- macOS (10.15+)
75+
- Windows 11/10 (though we've never tried it)
7076
```
7177
7278
We detect 11+ desktop environments because your team refuses to standardize.
@@ -87,26 +93,24 @@ The server literally cannot execute commands. We removed the code. It's not ther
8793

8894
## For Your Compliance Team
8995

90-
"What if someone tampers with the agent?"
96+
> "What happens if someone compromises the server?"
9197
92-
They can. It's their machine. They can also lie on spreadsheets. At least this has timestamps.
98+
Nothing. Perhaps they can clean up the old stale check-in data while they are there.
9399

94-
"Is this enterprise-ready?"
100+
> "What if someone tampers with the agent?"
95101
96-
No. But neither was Stripe when you started using it.
102+
They can. It's their machine. They can also lie on spreadsheets. At least this has timestamps.
97103

98-
## Building
104+
> "Is this enterprise-ready?"
99105
100-
```bash
101-
make all
102-
```
106+
No. But neither was Stripe when you started using it.
103107

104108
## Installation That Respects Your OS
105109

106110
- **Linux**: systemd user service (falls back to cron if you're systemd-free)
107-
- **OpenBSD**: cron (because rc.d requires root and we're not animals)
111+
- **(Dragonfly|Net|Free|Open)BSD**: cron (because rc.d requires root and we're not animals)
108112
- **macOS**: launchd (the least worst option)
109-
- **FreeBSD/NetBSD**: cron (see OpenBSD)
113+
- **Windows**: Task Scheduler (runs as user, not SYSTEM)
110114

111115
---
112116

cmd/agent/install.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,3 +528,105 @@ func uninstallCron() error {
528528

529529
return nil
530530
}
531+
532+
// installWindows installs Windows Task Scheduler task.
533+
func installWindows(agentPath, _, _ string) error {
534+
// Create the task XML content
535+
taskXML := fmt.Sprintf(`<?xml version="1.0" encoding="UTF-16"?>
536+
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
537+
<RegistrationInfo>
538+
<Description>GitMDM Compliance Agent</Description>
539+
</RegistrationInfo>
540+
<Triggers>
541+
<LogonTrigger>
542+
<Enabled>true</Enabled>
543+
</LogonTrigger>
544+
</Triggers>
545+
<Principals>
546+
<Principal id="Author">
547+
<LogonType>InteractiveToken</LogonType>
548+
<RunLevel>LeastPrivilege</RunLevel>
549+
</Principal>
550+
</Principals>
551+
<Settings>
552+
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
553+
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
554+
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
555+
<AllowHardTerminate>true</AllowHardTerminate>
556+
<StartWhenAvailable>true</StartWhenAvailable>
557+
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
558+
<IdleSettings>
559+
<StopOnIdleEnd>false</StopOnIdleEnd>
560+
<RestartOnIdle>false</RestartOnIdle>
561+
</IdleSettings>
562+
<AllowStartOnDemand>true</AllowStartOnDemand>
563+
<Enabled>true</Enabled>
564+
<Hidden>false</Hidden>
565+
<RunOnlyIfIdle>false</RunOnlyIfIdle>
566+
<WakeToRun>false</WakeToRun>
567+
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
568+
<Priority>7</Priority>
569+
<RestartOnFailure>
570+
<Interval>PT1M</Interval>
571+
<Count>3</Count>
572+
</RestartOnFailure>
573+
</Settings>
574+
<Actions Context="Author">
575+
<Exec>
576+
<Command>%s</Command>
577+
</Exec>
578+
</Actions>
579+
</Task>`, agentPath)
580+
581+
// Write task XML to temp file
582+
tempFile, err := os.CreateTemp("", "gitmdm-task-*.xml")
583+
if err != nil {
584+
return fmt.Errorf("failed to create temp file: %w", err)
585+
}
586+
defer os.Remove(tempFile.Name()) //nolint:errcheck
587+
588+
if _, err := tempFile.WriteString(taskXML); err != nil {
589+
return fmt.Errorf("failed to write task XML: %w", err)
590+
}
591+
tempFile.Close() //nolint:errcheck
592+
593+
// Delete existing task if present (ignore errors)
594+
cmd := exec.Command("schtasks", "/Delete", "/TN", "GitMDM Agent", "/F") //nolint:noctx
595+
_ = cmd.Run() //nolint:errcheck
596+
597+
// Create the scheduled task
598+
cmd = exec.Command("schtasks", "/Create", "/TN", "GitMDM Agent", "/XML", tempFile.Name()) //nolint:noctx
599+
output, err := cmd.CombinedOutput()
600+
if err != nil {
601+
return fmt.Errorf("failed to create scheduled task: %w\nOutput: %s", err, output)
602+
}
603+
604+
// Start the task immediately
605+
cmd = exec.Command("schtasks", "/Run", "/TN", "GitMDM Agent") //nolint:noctx
606+
_ = cmd.Run() //nolint:errcheck // Best effort
607+
608+
return nil
609+
}
610+
611+
// uninstallWindows removes Windows Task Scheduler task.
612+
func uninstallWindows() error {
613+
// Stop the task
614+
cmd := exec.Command("schtasks", "/End", "/TN", "GitMDM Agent") //nolint:noctx
615+
_ = cmd.Run() //nolint:errcheck // Best effort
616+
617+
// Delete the task
618+
cmd = exec.Command("schtasks", "/Delete", "/TN", "GitMDM Agent", "/F") //nolint:noctx
619+
output, err := cmd.CombinedOutput()
620+
if err != nil {
621+
if !strings.Contains(string(output), "The system cannot find") {
622+
return fmt.Errorf("failed to delete scheduled task: %w\nOutput: %s", err, output)
623+
}
624+
// Task doesn't exist, that's fine
625+
}
626+
627+
// Try to stop any running agent process
628+
cmd = exec.Command("taskkill", "/F", "/IM", "gitmdm-agent.exe") //nolint:noctx
629+
_ = cmd.Run() //nolint:errcheck // Best effort
630+
631+
return nil
632+
}

0 commit comments

Comments
 (0)