Replies: 3 comments 1 reply
-
|
hi @RobertWi all of these very much make sense to me and have been thinking the same. I can give you a quick speedy reply and from there we can figure out how to break out into work items.
+1 The credential system already has a URI scheme pattern
+1 L7 filtering is another must have. right now the proxy is a host-level gate; adding method+path turns it into a proper API surface restriction. For AI agents with tool-use, the difference between "can access GitLab" and "can only GET merge requests and POST comments" is significant and a big boost. We can start with your example - method + path globs, that covers a majority of use case for API surface restriction. A simple declarative format in json. In time we will also want Request/response body inspection, Cross-request state (rate limiting, quotas), etc which is where we are going to want to consider a policy engine. As it stands this wouold only work for reverse proxy mode (where the proxy sees the plaintext request). CONNECT tunnels are opaque the proxy can't inspect the path, which means we need to consider TLS interception , so nono generates a CA cert at startup (or loads a user-provided one, calls a CA). The sandboxed process can't reach the internet directly - it can only talk to localhost where the proxy listens. So the trust boundary is already "trust the proxy." Adding a MITM cert doesn't really change the trust model, it just makes the proxy's inspection uniform. For bonus points TLS injection gets us far more covereage for cred injections, right now we can only really work with those who play nice with HTTP_PROXY , Base URL etc
+1 , also composes naturally cred injection already does the "agent never sees credentials" pattern. Adding client_credentials token exchange extends that from static tokens to rotating ones. Implementation-wise, this adds an HTTP client dependency to nono-proxy for the token exchange, plus a token cache with TTL. Not trivial, but easily doable if well-scoped. |
Beta Was this translation helpful? Give feedback.
-
|
Hi @lukehinds, good to know it's not a nono 😄 Went ahead and built all three. They're running in our K8s cluster now — agents sandboxed with Landlock V4, credentials they never see, blissful ignorance all around. Ran into some fun edge cases worth sharing:
Everything rebased on current Branches on my fork (https://github.com/RobertWi/nono):
Happy to open PRs whenever, or reshuffle the split if you prefer. Let me know how you'd like to take these in. |
Beta Was this translation helpful? Give feedback.
-
|
Quick update — opened PRs for the features discussed here:
All rebased on v0.25.0, tests passing. L7 path filtering is covered by @andreaTP's #513 (commented there with some edge cases we ran into). Thanks for the guidance on direction, @lukehinds — made it straightforward to split into clean PRs. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
We're running nono inside containers to sandbox AI agents in a Kubernetes cluster. Landlock enforcement works well — it's the cleanest way to restrict filesystem and network access for agents that have LLM tool-use capabilities.
As we've built this out, we've run into three patterns that don't have a clean solution in nono today. Wanted to open a conversation about whether these fit the project's direction, or whether they belong in a separate layer.
1.
file://credential sourceIn containerized environments, secrets are typically injected as files (Vault Agent sidecar writes to
/vault/secrets/, Kubernetes mounts secrets as files). nono's credential system supports keystore,op://,apple-password://, andenv://— but not reading a credential from a file path.Today we work around this with an entrypoint wrapper that reads files into env vars before nono starts, then uses
env://. It works, but adds a shell script layer that feels like it shouldn't be necessary.A
file://source would fit naturally alongside the existing credential URI scheme:{ "custom_credentials": { "gitlab": { "upstream": "https://gitlab.example.com", "credential_key": "file:///vault/secrets/gitlab", "inject_header": "PRIVATE-TOKEN" } } }Read strategy: Read at startup (before Landlock activates) matches the
env://pattern. For secrets that rotate (Vault Agent rewrites the file periodically), a file-watch or TTL-based re-read would be needed. These could be two separate behaviors — startup-read as the default, with an opt-in"watch": truefor rotation.2. L7 path filtering on the proxy
nono's proxy already sees every outbound HTTP request and filters by host. Adding L7 method + path matching would enable restricting not just where an agent connects, but what it can do there.
Example: an agent should be able to read merge requests and post comments, but not delete repositories or access admin APIs:
{ "network": { "allow_domain": [ { "host": "gitlab.example.com:443", "paths": [ { "method": "GET", "path": "/api/v4/projects/*/merge_requests/**" }, { "method": "POST", "path": "/api/v4/projects/*/merge_requests/*/notes" } ] } ] } }This is relevant beyond our use case. Any sandboxed AI agent with HTTP tool-use could benefit from API surface restriction — the difference between "can access GitHub" and "can read issues but not push to main."
3. OAuth2 client_credentials for custom providers
nono handles OAuth2 natively for built-in providers (Anthropic, OpenAI, etc.), but custom upstreams only get static header/param injection. For services that use standard OAuth2 client_credentials flow, the agent currently has to handle the token exchange itself — which means it needs access to the client secret.
If the proxy could handle
client_credentialstoken exchange for custom upstreams (given atoken_url,client_id,client_secret, andscope), the agent never sees credentials at all. The proxy obtains and refreshes the Bearer token, the agent just makes API calls.{ "custom_credentials": { "internal_api": { "upstream": "https://api.example.com", "auth": { "type": "client_credentials", "token_url": "https://auth.example.com/oauth/token", "client_id": "file:///vault/secrets/client_id", "client_secret": "file:///vault/secrets/client_secret", "scope": "api:read api:write" } } } }This composes well with
file://— credentials come from Vault, the proxy handles the exchange, the sandboxed process never touches any of it.Context
We're building and experimenting with an agent framework where each agent runs in its own container, sandboxed by nono with Landlock V4. The agents use LLM tool-calling to interact with GitLab, internal APIs, and each other. nono's Landlock enforcement is doing the heavy lifting for filesystem and network containment. These three features would close the remaining gaps between "agent can reach a host" and "agent can only do specific things on that host, with credentials it never sees."
Happy to contribute any of these if they align with the project direction. Also open to hearing that some of these belong in a separate proxy layer — the question is genuine.
Beta Was this translation helpful? Give feedback.
All reactions