Team Member Offboarding

When a team member leaves, you need to revoke their access and rotate any secrets they had visibility into. envctl makes this process explicit and auditable.

Why Rotation Matters

Removing someone from a project revokes their ability to receive future updates, but they still have copies of the secrets they previously had access to. These copies exist on their local machine, potentially in backups, or in their memory.

For true security, you must:

  1. Revoke access — Stop them from receiving new secrets
  2. Rotate secrets — Change the values of secrets they had access to
  3. Update CI bundles — Re-export encrypted bundles with new secrets

Removal alone is not enough

Simply removing a team member does not invalidate the secrets they've already seen. Always rotate secrets after removing someone, especially for production environments.

Step 1: Review Their Access

Before removing someone, understand what they had access to:

$ envctl project access bob
Access for bob in myproject:

Environment   Role      Since
-----------   ----      -----
dev           member    2024-01-10
staging       member    2024-01-10
prod          reader    2024-02-15

This shows which environments Bob could access and their role in each. Roles determine what they could do:

  • reader — Can view secrets but not modify them
  • member — Can view and modify secrets
  • admin — Can manage members and environments

All roles can see secret values, so all environments they had access to need rotation.

Step 2: Remove from Project

Remove the team member from the project. After removal, envctl will prompt you to rotate secrets:

$ envctl project remove bob
Remove 'bob' from project? [y/N] y
Member 'bob' removed.

'bob' had access to: dev, staging, prod

SECURITY: The removed member may have copied secret values.
You should set NEW values for sensitive secrets (API keys, passwords, etc.)

Rotate secrets for these environments? [Y/n] y

Rotating secrets for myproject/prod...
# Opens $EDITOR - update secrets with NEW values, save and close
  Updated: DATABASE_URL, API_KEY, STRIPE_SECRET
Rotating secrets for myproject/staging...
# Opens $EDITOR again for staging
  Updated: DATABASE_URL, API_KEY
Rotating secrets for myproject/dev...
# Opens $EDITOR again for dev
  Updated: DATABASE_URL

Done. Updated secrets will be synced to team members when the daemon is running.

This does several things:

  • Removes their membership from the project chain
  • Prevents them from receiving new sync messages
  • Revokes their ability to decrypt future secrets
  • Prompts to rotate secrets in each environment they had access to

Editor-based rotation

When you choose to rotate secrets, envctl opens your $EDITOR for each environment. The file shows all current secrets with helpful comments explaining what needs to be done. Update any sensitive values (API keys, passwords, tokens) with NEW values from your service providers, then save and close.

Use --silent to skip all prompts (useful for scripts, but remember to rotate secrets separately):

$ envctl project remove bob --silent
Member 'bob' removed.

Step 3: Identify Secrets to Rotate

envctl tracks who has seen which secrets. View the secrets Bob had access to:

$ envctl env var list -e dev
Variables in myproject/dev:

DATABASE_URL      = postgres://... (set by alice, 2024-01-10)
API_KEY           = sk_dev_...     (set by bob, 2024-02-01)
STRIPE_KEY        = pk_test_...    (set by alice, 2024-01-15)

All secrets in environments Bob had access to should be considered compromised and rotated.

Check the Audit Log

For a detailed view of what Bob accessed:

$ envctl log --search bob --since 90d
2024-03-01 14:20  bob  Pulled secrets (dev: 3, staging: 3, prod: 2)
2024-02-28 09:15  bob  Set API_KEY in dev
2024-02-15 11:30  alice  Granted bob reader access to prod
2024-02-01 10:00  bob  Set API_KEY in dev
2024-01-10 09:00  alice  Added bob to project

Step 4: Rotate Affected Secrets

If you used the integrated rotation prompt in Step 2, you've already rotated secrets in the editor. This section covers what you need to do at the service level and how to rotate manually if needed.

What "Rotation" Really Means

Rotating a secret involves two steps:

  1. Generate new credentials at the actual service (database, API provider, etc.)
  2. Update the secret in envctl with the new value

Simply changing the value in envctl isn't enough—you need to create a genuinely new credential at the source.

Example: Rotating Database Credentials

  1. Create a new database user or password in your database
  2. Update the secret in envctl (in the editor, or manually):
    $ envctl env var set -e prod DATABASE_URL=postgres://newuser:newpass@host/db
     Set DATABASE_URL in prod
  3. Deploy your application with the new credentials
  4. Delete the old database user or password

Example: Rotating API Keys

  1. Generate a new API key from the service provider
  2. Update the secret (in the editor, or manually):
    $ envctl env var set -e prod API_KEY=sk_live_new_key_here
     Set API_KEY in prod
  3. Revoke the old API key from the service provider

Rotate in order of sensitivity

The integrated rotation prompt handles environments in the order the member had access, but if you're doing it manually, start with production secrets, then staging, then development.

Manual Rotation (Alternative)

If you skipped the rotation prompt or need to rotate additional secrets later, use the editor command:

# Edit secrets in an environment
$ envctl env edit -e prod
# Opens $EDITOR with all secrets - make changes, save and close

# Or set individual secrets
$ envctl env var set -e prod DATABASE_URL=postgres://newuser:newpass@host/db
$ envctl env var set -e prod API_KEY=sk_prod_new_key

Step 5: Update CI Bundles

If you use envctl for CI/CD, re-export your encrypted bundles with the new secrets:

$ envctl ci export -e prod -o .envctl/prod.enc
Exported 8 variables to .envctl/prod.enc

$ envctl ci export -e staging -o .envctl/staging.enc
Exported 6 variables to .envctl/staging.enc

$ git add .envctl/*.enc
$ git commit -m "Rotate secrets after team change"
$ git push

Your CI pipelines will automatically use the new secrets on the next run.

Step 6: Verify Removal

Confirm the team member has been removed:

$ envctl project members
Members of myproject:

Name          Role    Environments         Joined
----          ----    ------------         ------
alice         admin   dev, staging, prod   2024-01-05
charlie       member  dev, staging         2024-01-20

2 members total

Bob no longer appears in the member list.

Verify in the Audit Log

$ envctl project log | head
2024-03-01 16:00  alice  Removed bob (reason: Left company)
2024-03-01 16:05  alice  Set DATABASE_URL in prod
2024-03-01 16:05  alice  Set API_KEY in prod
...

Notify Remaining Team

After rotating secrets, remaining team members need to sync:

$ envctl pull
 Pulled 6 updates from alice
  prod: 3 variables changed
  staging: 2 variables changed
  dev: 1 variable changed

If using the relay, syncing happens automatically. For P2P-only setups, team members may need to be online at the same time or manually pull updates.

Team members should also update their local .env files:

$ envctl env use dev
 .env written (3 secrets)

Best Practices

Create an Offboarding Checklist

For your organization, maintain a checklist of secrets that need rotation when someone leaves. Group them by service:

  • Database — DATABASE_URL, REDIS_URL
  • Payment — STRIPE_SECRET, STRIPE_WEBHOOK_SECRET
  • Email — SENDGRID_API_KEY, SMTP_PASSWORD
  • Cloud — AWS_SECRET_ACCESS_KEY, GCP_SERVICE_ACCOUNT
  • Third-party APIs — TWILIO_AUTH_TOKEN, GITHUB_TOKEN

Use Environment-Based Access Control

Limit who has access to production:

# Grant dev/staging access to new developers
$ envctl project grant alice --env dev,staging

# Only grant prod access when needed
$ envctl project grant alice --env prod

This minimizes the rotation scope when someone leaves—if they only had dev access, you only need to rotate dev secrets.

Schedule Regular Rotation

Don't wait for offboarding to rotate secrets. Consider:

  • Rotating production secrets quarterly
  • Rotating after any security incident
  • Rotating when contractors complete projects

Document in the Audit Log

Use descriptive reasons when removing members:

$ envctl project remove bob --reason "Contract ended 2024-03-01"

This creates a permanent record in the project chain that's visible to all admins.

Emergency Removal

If you suspect a security incident or need to remove someone immediately:

  1. Remove immediately:
    $ envctl project remove compromised-user --reason "Security incident"
  2. Rotate production secrets first:
    $ envctl env var set -e prod CRITICAL_SECRET=new_value
  3. Re-export CI bundles:
    $ envctl ci export -e prod -o .envctl/prod.enc && git add .envctl/prod.enc && git commit -m "Emergency rotation" && git push
  4. Deploy with new secrets
  5. Rotate remaining environments
  6. Review audit logs for suspicious activity

Related