4.5 KiB
4.5 KiB
Hardening checklist
This server is full access by design (ADR 0001): whoever can call it has the power of the configured Gitea token, which for an admin token means everything. The server keeps a few invariants (audit, secret redaction, bounded output, validated input, fail-closed HTTP authentication), but it does not decide what is safe. This checklist is how you do that.
Decide what to expose
- Create the Gitea token with the narrowest scopes that do the job. Full access needs a
site-admin token with
all; a read-only assistant needs only read scopes. The token is the hard limit, because Gitea enforces it. - Prefer per-user OAuth to a shared admin token whenever more than one person connects: each user then acts under their own Gitea permissions and admin tools fail for non-admins.
- Narrow what is listed:
READ_ONLY=true,TOOLSETS=...,DISABLED_TOOLS=.... Hide what the assistant never needs:admin,actions(secrets),hook,user(tokens, keys) and the delete tools are the sensitive ones.gitea_api_requestcan reach any endpoint, so on a restricted profile dropmiscor disable it. - Keep
OAUTH_SCOPESas narrow as the use case allows. - Do not use Sudo-capable tokens for clients that do not need to impersonate users.
Treat the credentials as keys to the instance
GITEA_TOKENandMCP_BEARER_TOKENare equivalent in power on HTTP. Generate the bearer token withopenssl rand -hex 32, store it in a secret manager or a mode 0600 env file, rotate it when someone leaves, and never put it in a URL (it only goes in theAuthorizationheader).TOKEN_ENCRYPTION_KEYprotects the stored per-user tokens. Keep it separate from the data volume backups.GITEA_OAUTH_CLIENT_SECRETlikewise.- Use
setup, which writes the env file with mode 0600 and never prints secrets. The server loads./.envonly while it is a regular file you own with mode 0600; keep it elsewhere with--env-fileorAEGIS_ENV_FILE. - For a public OAuth deployment set
OAUTH_REDIRECT_ALLOWLIST(for examplehttps://claude.ai/,https://chat.mistral.ai/), so only the hosted clients you use can register, and leaveMCP_BEARER_TOKENandGITEA_TOKENunset when nobody needs the admin identity. - Do not paste tokens into chat with the assistant, and do not commit
.env.
Network and transport
- Keep the default bind
127.0.0.1. Publish the container port on127.0.0.1and put a reverse proxy with TLS in front. A non-loopback bind refuses to start without authentication; do not work around it. - Terminate TLS with a valid certificate.
PUBLIC_BASE_URLmust be https. - Set
ALLOWED_HOSTSto exactly the host names you serve. Requests with otherHostvalues are rejected. - Restrict who can reach the endpoint at the proxy or firewall too (VPN, allow list), as a second layer in front of bearer authentication.
- Set
FORWARDED_ALLOW_IPSto the proxy address only (not*), so a client cannot spoof its IP. - Leave
RATE_LIMIT_PER_MINUTEon. Put request-size and connection limits at the proxy. - Use https for
GITEA_URL. Plain http sends the token unencrypted (setup warns about it).
Container and host
- Run the image as the non-root user,
read_only: truewith atmpfsfor/tmp,cap_drop: ALLandno-new-privileges, as the compose snippet in deployment.md does. - Mount only the data volume. Give it to the service account alone (mode 0700).
- Pin the image by digest in production, and update regularly.
- Do not run the stdio server with a token that is broader than the user's own needs on a shared machine: any process of that user can read the client configuration.
Audit and monitoring
- Ship the audit log off the host and validate the chain regularly (audit-logging.md).
- Alert on repeated
forbiddenorunauthorizedoutcomes and on calls to admin, secret and delete tools. - Keep
LOG_LEVEL=INFOandEXPOSE_ERROR_DETAILS=falsein production. - Keep
SECRET_DETECTION_MODE=mask(orblock). Secret detection is a safety net with regular expressions, not a guarantee.
Untrusted content
- Keep tool-call confirmation enabled in the client for destructive tools. Prompt injection in issues, pull requests, comments and files is the realistic way a model is tricked into using the access it has.
- Do not connect a write-capable, broad-scope profile to an assistant that also reads untrusted content from other sources.
- Prefer separate profiles: a read-only one for browsing and triage, a write-capable one that you use deliberately.