Independent comparison · no paid rankings
Home / Blog / Git deploy keys: limit access without blocking automation
Technical

Git deploy keys: limit access without blocking automation

A read-only deploy key on the wrong repo, or a personal PAT with admin scope — two ways to "secure" CI while leaving production wide open.

5 min read Updated Jul 19, 2026

The production VPS pulls the repository via a deploy key — good. Except it was generated on the CTO's laptop, copied to /root/.ssh, and reused for staging and production. When staging is compromised via a vulnerable WordPress plugin, the attacker clones the private API repository too — same key, read access to the whole attached monorepo.

Deploy keys are the passport between your host and Git. Poorly scoped, they turn an application incident into intellectual property leakage.

SSH deploy key: minimal scope

On GitHub or GitLab: deploy key per repository, read-only for a server that only pulls code.

ApproachAdvantageRisk
Read-only deploy keyAccess limited to one repoKey duplicated across environments
Machine user PATRich APIScope too broad, no rotation
OAuth appCentralizedComplexity, audit

Create a Linux user deploy without login shell (/usr/sbin/nologin), with ForceCommand if you need to restrict to git-shell.

A key on the production server is worth whatever that server is worth — treat it as a tier-one secret.

CI vs runtime: two distinct identities

The CI pipeline (GitHub Actions, GitLab CI) uses a token with read_repository scope or a deploy key with write access only if you automate tags and releases — never with admin rights on the organization.

The production server only pulls code. CI builds and pushes the artifact (image, archive); the server does not necessarily clone on every deployment if you ship immutable images.

Separating build credentials and deployment credentials limits the attack chain.

Rotation, audit and inventory

Keep a registry: key → repository → environment → creation date → next rotation. Automate alerts at 90 days.

Standard procedure: generate a new ed25519 pair, add the public key on the Git host with brief coexistence, validate deployment on staging then production, revoke the old key. After an incident: revoke immediately, not "next Monday".

Hosts and alternative Git access

On shared hosting without SSH Git: deploy via FTP or rsync from CI — no long-lived key on shared hosting. On VPS and bare metal: standard deploy key.

Some PaaS platforms (Clever Cloud, etc.) use webhooks — no key on the machine; verify who can trigger a deployment. On bare metal, restrict the deploy user to git pull via forced command and disable interactive shell entirely.

Document which team member owns each key rotation. When the person who generated the original key leaves, orphaned credentials often survive for months because nobody knows which pipeline still references them.

Common mistakes

Private key committed in the repository — scan Git history. StrictHostKeyChecking no eases MITM attacks: pin known_hosts. Private submodule without dedicated deploy key: parent clone succeeds, submodule fails or forces an overly broad key.

The peak: read-only that reads too much

Automating without blocking means short-lived machine identities, minimal scope, documented rotation — not an immortal key in root.

Decide and move forward without blind spots

Create one deploy key per repository and per environment, a dedicated deploy user, separate CI credentials, quarterly rotation, and an audit of known_hosts. Compare VPS and PaaS with secure deployment via the directory and comparator. The guides cover pipelines in detail.

Run an immediate audit: list active Git keys and accessible repositories — remove orphans.

Frequently asked questions

Deploy key or CI token?

Use a read-only SSH deploy key per repository for a server that only pulls code — that limits blast radius. A CI token suits API calls such as pull requests and releases, with minimal scopes, short expiry, and never the lead developer's personal account. Mixing both roles on one credential defeats the purpose.

Why forbid write access on a deploy key?

A compromised server with write access can push code or tags — a direct supply chain risk. Reserve pull-only on the application repository; controlled pipelines handle push. Write keys belong in CI with narrow scope and audit logs, not on long-lived production VMs.

How do you rotate without cutting production?

Add the new key on the remote, validate deployment on staging then production, then remove the old key. Document date and owner, and alert on keys older than ninety days. Brief coexistence avoids Friday-night outages when rotation is overdue.

One shared git user on the server?

Anti-pattern — logs become indistinguishable and one shared key spreads compromise. Prefer a dedicated deploy system user and one deploy key per environment or server. Each environment should be revocable without touching the others.


A clean deploy key can clone one repository — not your morning after a compromised staging environment.

Compare European hosts

Filter by compliance, location and use case — then open the sheets to verify the real scope.

Browse the directory
Blog

Related reading

All articles →