# Developer Workstation Hardening for AppSec and DevSecOps

> **Intro:** A developer workstation is not just a laptop. It is an execution environment for code, containers, secrets, package managers, browser sessions, cloud CLIs, and signing keys. For Product Security, a compromised workstation can become source-code theft, secret leakage, poisoned artifacts, or trusted-signature abuse.
>
> **What this page includes**
>
> * secure baseline for VS Code and JetBrains users;
> * pre-commit bundles for local guardrails;
> * local Docker security, including rootless mode and safer defaults;
> * commit signing, Cosign, and key hygiene;
> * secrets hygiene and safe sandboxing patterns for labs, PoCs, and untrusted code.

## The workstation threat model

A developer workstation typically has:

* access to source code and design notes;
* cloud CLIs and cached tokens;
* package registries and build tools;
* local containers and virtual machines;
* browser sessions into GitHub, GitLab, Jira, cloud consoles, and secrets systems;
* signing keys or the ability to request signatures.

That means one compromised workstation can affect:

* confidentiality of code and secrets;
* integrity of commits, tags, and release artifacts;
* trust in CI/CD and production deploys.

## Recommended secure baseline

### 1. Separate trust zones on the same machine

Use at least two categories of environments:

* **daily engineering zone** — your normal editor, browser, and tools;
* **unsafe or experimental zone** — disposable VM, dev container, or remote sandbox for PoCs, unknown scripts, and exploit labs.

Do **not** run unfamiliar shell scripts, offensive labs, or unknown Docker images in the same environment where your long-lived cloud tokens and signing material live.

### 2. Prefer passkeys or phishing-resistant MFA for key portals

High-value portals include:

* GitHub / GitLab;
* cloud consoles;
* password managers;
* artifact registries;
* CI/CD admin portals;
* SSO / IdP admin interfaces.

### 3. Keep local admin privileges limited

The more your workstation is operated as permanent local admin/root, the easier it is for malicious scripts or poisoned packages to pivot into lasting host compromise.

## VS Code setup

### Recommended extensions for security feedback

* Semgrep extension for fast inline finding feedback;
* YAML / Docker / Terraform extensions only from trusted publishers;
* avoid random marketplace extensions that request broad workspace access without justification.

Semgrep’s official VS Code extension supports scanning as you open and change files, showing inline results and autofix where rules provide it. citeturn359551search2

### Recommended VS Code settings

```json
{
  "security.workspace.trust.enabled": true,
  "extensions.autoCheckUpdates": true,
  "extensions.autoUpdate": true,
  "git.enableCommitSigning": true,
  "files.autoSave": "off",
  "terminal.integrated.confirmOnExit": "always"
}
```

### Practical comments

* keep **Workspace Trust** enabled, especially when opening unfamiliar repos or extracted conference/demo material;
* do not install one-off extensions from random blog posts for parsing IaC or security files unless the publisher is trusted;
* prefer dev containers or a disposable VM when opening complex PoCs that include helper scripts.

## JetBrains setup

JetBrains IDEs are strong for teams that want connected VCS hygiene and built-in Git/GPG integration.

JetBrains documents current GPG commit signing under **Settings / Preferences → Version Control → Git → Configure GPG Key**. The 2025.3 docs explicitly recommend using a proper `gpg2` setup with working pinentry support. citeturn838320search0

### JetBrains baseline

* enable commit signing;
* use trusted plugins only;
* review IDE HTTP client environment files and run configurations for secrets;
* avoid storing persistent credentials in run configurations checked into the repo.

## Pre-commit bundle

Use a local pre-commit stack to catch the easiest issues before they ever reach CI.

### Recommended first bundle

* `gitleaks` or `git-secrets` for secrets;
* `semgrep` for fast code and config checks;
* formatting / linting hooks for YAML, JSON, Dockerfiles, and shell where relevant.

### Example `.pre-commit-config.yaml`

```yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.24.2
    hooks:
      - id: gitleaks

  - repo: https://github.com/returntocorp/semgrep
    rev: v1.120.0
    hooks:
      - id: semgrep
        args:
          - --config=p/owasp-top-ten
          - --config=p/secrets
          - --config=p/terraform

  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: check-yaml
      - id: end-of-file-fixer
      - id: trailing-whitespace
```

### Install

```bash
python3 -m pip install --user pre-commit
pre-commit install
pre-commit run --all-files
```

## Git signing

### Why sign commits

Commit signing does not prove code is safe, but it improves provenance and makes repo history harder to tamper with silently.

GitHub supports **GPG, SSH, and S/MIME** commit signature verification. The docs explicitly note that for most individual users, **GPG or SSH** are the most practical choices, and that SSH signing requires Git 2.34 or later. citeturn838320search1turn838320search5

### Recommended 2026 default

For many teams, **SSH commit signing** is now simpler than GPG for daily commits. Keep GPG for teams with existing smartcard/YubiKey workflows or policy requirements.

### Example SSH signing setup

```bash
ssh-keygen -t ed25519 -C "dev-signing@example.com" -f ~/.ssh/id_ed25519_signing

git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519_signing.pub
git config --global commit.gpgsign true
git config --global tag.gpgsign true
```

Then upload the **public signing key** to your Git hosting provider as a signing key, not only as an auth key.

### Example GPG signing setup

```bash
gpg --full-generate-key
gpg --list-secret-keys --keyid-format=long

git config --global user.signingkey <LONG_KEY_ID>
git config --global commit.gpgsign true
git config --global tag.gpgsign true
```

## Cosign on the workstation

### Why Cosign belongs on developer workstations

Cosign is not only for CI. It is useful locally for:

* verifying the provenance of security tools you download;
* verifying signed container images;
* testing blob signing and verification before CI rollout;
* debugging attestation flows.

Sigstore’s current docs still position **Cosign** as the recommended CLI for signing and verifying software artifacts. Installation options include `go install`, Homebrew, distro packages, GitHub Actions, GitLab, and container images. citeturn359551search1turn359551search4

### Install Cosign

```bash
# Homebrew / Linuxbrew
brew install cosign

# or Go
GO111MODULE=on go install github.com/sigstore/cosign/v3/cmd/cosign@latest
```

### Verify a blob locally

```bash
cosign sign-blob artifact.tar.gz --bundle artifact.sigstore.json
cosign verify-blob artifact.tar.gz --bundle artifact.sigstore.json \
  --certificate-identity-regexp '.*' \
  --certificate-oidc-issuer https://oauth2.sigstore.dev/auth
```

## Local Docker security

### Recommended baseline

* prefer **rootless Docker** where compatible;
* avoid mounting `/var/run/docker.sock` into random containers;
* avoid `--privileged` unless you have a short-lived, explicit reason;
* do not treat local third-party images as trusted code;
* prune old images and build cache regularly.

Docker’s current docs say **rootless mode** runs both the daemon and containers inside a user namespace, unlike `userns-remap`, where the daemon still runs as root. citeturn359551search0

### Rootless Docker quick setup

```bash
# prerequisites vary by distro; uidmap is typically required
sudo apt-get install -y uidmap

dockerd-rootless-setuptool.sh install
systemctl --user start docker
systemctl --user enable docker
```

### Verify user namespace mapping

```bash
docker run --rm alpine cat /proc/self/uid_map
```

### Safer defaults when testing images

```bash
docker run --rm -it \
  --read-only \
  --tmpfs /tmp:size=64m,noexec,nosuid \
  --cap-drop=ALL \
  --security-opt no-new-privileges \
  alpine:3.20 sh
```

## Secrets hygiene

### Principles

* do not store secrets in shell history, repo files, IDE run configs, or screenshots;
* prefer federated auth and short-lived credentials over long-lived static keys;
* separate human access from automation identities;
* rotate local cloud credentials and delete stale CLI profiles.

### Fast local checks

```bash
gitleaks dir .
git secrets --scan-history
```

### Common workstation leak points

* `.env` files committed accidentally;
* cloud CLIs leaving cached tokens in home directories;
* IDE database/browser connectors with saved passwords;
* copied kubeconfigs shared over chat or left in screenshots;
* shell history with `export AWS_SECRET_ACCESS_KEY=...`.

## Safe sandboxing for labs and PoCs

### Good options

* disposable VM for malware-ish or offensive material;
* dev container for ordinary untrusted build/test content;
* remote throwaway cloud account or isolated lab for cloud exploitation exercises;
* separate browser profile for conference tools, demos, and disposable SaaS signups.

### Bad option

Running random PoC code in the same host session where you:

* are logged into GitHub/GitLab;
* have AWS/GCP/Azure CLI tokens cached;
* have `~/.kube/config` for production clusters;
* can sign commits or images.

## Suggested workstation checklist

* [ ] full-disk encryption enabled
* [ ] phishing-resistant MFA for code, cloud, and SSO portals
* [ ] trusted password manager in use
* [ ] commit signing enabled
* [ ] Semgrep and secret scanning available locally
* [ ] pre-commit hooks installed in high-value repos
* [ ] Docker rootless or otherwise reduced-privilege local runtime considered
* [ ] separate sandbox for labs, PoCs, and suspicious repos
* [ ] stale cloud credentials and kubeconfigs reviewed regularly

## Cross-links

* [Secure Coding Training Platforms for Developers](/learning-labs-interview-and-templates/index-2/secure-coding-training-platforms-for-developers.md)
* [IDE Security Linters and Pre-Commit SAST](/application-security-and-secure-sdlc/index-1/ide-security-linters-and-pre-commit-sast.md)
* [Git Commit Signing and Image Signing](/learning-labs-interview-and-templates/index/git-commit-signing-and-image-signing.md)
* [Dockerfile Security Best Practices](/cloud-kubernetes-and-infrastructure-security/index-1/dockerfile-security-best-practices.md)
* [AppArmor and Seccomp for Docker](/cloud-kubernetes-and-infrastructure-security/index-1/apparmor-and-seccomp-for-docker.md)

***

*Author attribution: Ivan Piskunov, 2026 - Educational and defensive-engineering use.*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.product-security.expert/learning-labs-interview-and-templates/index-2/developer-workstation-hardening-for-appsec-and-devsecops.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
