---
title: "Escaping the AWS SSM AppArmor profile with systemd-run"
date: 2026-04-25
tags: [aws, ssm, apparmor, linux, ubuntu, troubleshooting]
summary: On Ubuntu, SSM Session Manager shells inherit the snap-amazon-ssm-agent AppArmor profile. Even root hits silent EACCES on writes. Escape via systemd-run.
aliases: [ssm-apparmor, ssm-shell-apparmor-systemd-run, ssm-systemd-run]
---

On Ubuntu via [SSM Session Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html), your shell (and every child it spawns) runs under the `snap.amazon-ssm-agent.amazon-ssm-agent` AppArmor profile. uid 0 with `CAP_DAC_OVERRIDE` doesn't get out of it. Writes to paths like `/var/log/postgresql/*` return `EACCES` even with a clean `lsattr`, a writable fs, and the right caps.

## Confirm it's AppArmor

```bash
$ cat /proc/self/attr/current
snap.amazon-ssm-agent.amazon-ssm-agent (enforce)
```

`dmesg` will probably stay quiet. Snap profiles use `audit deny` for "expected" paths, which suppresses the kernel audit line. When entries do show up they can lag a couple of minutes.

## Escape via systemd-run

`systemd` runs as PID 1, outside any AppArmor profile. Anything it starts is unconfined. `systemd-run --pipe --wait` delegates a command to PID 1 and pipes the result back:

```bash
sudo systemd-run --pipe --wait <cmd> [args...]
sudo systemd-run --pipe --wait --uid=postgres bash -c 'truncate -s 0 /var/log/postgresql/postgresql-16-main.log'
sudo systemd-run --pipe --wait tee /etc/foo/bar.conf <<'EOF'
some content
EOF
```

- `--pipe` forwards stdin/stdout/stderr.
- `--wait` is synchronous and propagates the exit code.
- `--uid=<user>` drops privilege. PID 1 can become any uid.

## Better alternatives

- **SSH with a real keypair.** SSH sessions don't inherit the snap profile. Worth the setup if you touch the box more than occasionally.

## Why bother

SSM is the right tool for ad-hoc ops without exposing SSH, or when you've lost the original key. It's also audited, which is nice. Knowing about the AppArmor inheritance saves you the hour of wondering why root can't write to a directory it owns (like I did).

## Related

- [[podman-vs-docker]]
- [[mcp-env-vars-not-from-bashrc]]

## References

- [AppArmor in Ubuntu](https://ubuntu.com/server/docs/security-apparmor)
- [`systemd-run(1)`](https://www.freedesktop.org/software/systemd/man/systemd-run.html)
- [AWS SSM Session Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html)
