π Production Secrets Management
Overview
Agrotech uses environment variables for all sensitive configuration. Keeping secrets out of source control is critical β leaked credentials can compromise your database, allow unauthorized API access, or expose user data.
Key principles:
- β οΈ Never commit real secrets to the repository (
.envis in.gitignore) - Store production secrets exclusively in GitHub Secrets (or a secrets manager)
- Use the
productionGitHub Environment to gate deployments behind required reviewers - Rotate secrets immediately if they are ever accidentally exposed
Required GitHub Secrets
The following secrets must be configured in your GitHub repository before running the production deployment workflow:
| Secret | Used In | Description | Example / Generation |
|---|---|---|---|
POSTGRES_PASSWORD |
docker-compose.yml β api connection string |
PostgreSQL database password | openssl rand -base64 32 |
JWT_KEY |
docker-compose.yml β api β JwtSettings__Key |
HMAC key for signing JWT tokens (minimum 32 characters) | openssl rand -base64 64 |
DOMAIN |
nginx/prod.conf, scripts/init-letsencrypt.sh |
Production domain name for TLS certificate | your-production-domain.com |
EMAIL |
scripts/init-letsencrypt.sh |
Email for Letβs Encrypt registration and expiry notices | admin@your-production-domain.com |
CORS_ORIGIN |
docker-compose.yml β api β Cors__AllowedOrigins__0 |
Frontend URL allowed by CORS policy | https://your-production-domain.com |
Step-by-Step: Configuring GitHub Secrets
Via the GitHub UI
- Open your repository on GitHub.
- Go to Settings β Secrets and variables β Actions.
- Click New repository secret.
- Enter the Name (e.g.,
POSTGRES_PASSWORD) and the Secret value. - Click Add secret.
- Repeat for all five required secrets listed above.
Via GitHub CLI (recommended)
# Generate and set a strong database password
gh secret set POSTGRES_PASSWORD --body "$(openssl rand -base64 32)"
# Generate and set a strong JWT signing key (β₯ 32 characters)
gh secret set JWT_KEY --body "$(openssl rand -base64 64)"
# Set production domain (no https://, no trailing slash)
gh secret set DOMAIN --body "your-production-domain.com"
# Set Let's Encrypt registration email
gh secret set EMAIL --body "admin@your-production-domain.com"
# Set CORS origin for the frontend (include https://)
gh secret set CORS_ORIGIN --body "https://your-production-domain.com"
GitHub Environment Setup (Recommended)
Using a dedicated production environment adds an approval gate and allows environment-scoped secrets:
Create the environment
- Go to Settings β Environments β New environment.
- Name it
production. - Under Deployment protection rules:
- Enable Required reviewers and add at least one reviewer.
- Enable Restrict pushes that create matching branches β restrict to the
mainbranch.
- Under Environment secrets, add the same five secrets listed above (environment secrets take precedence over repository secrets for jobs that reference the environment).
Why use environments?
- Deployments to
productionrequire explicit approval from a reviewer. - Secrets in the environment are only available to jobs that declare
environment: production. - You get a full deployment history with approvals logged in GitHub.
Generating Strong Secret Values
Strong JWT key (β₯ 32 characters)
openssl rand -base64 64
This produces an 88-character Base64 string β well above the 32-character minimum required by the HMAC signing algorithm used in Agrotech.
Strong database password
openssl rand -base64 32
This produces a 44-character random password that is URL-safe for connection strings.
Local Development
For local development, you do not need to configure GitHub Secrets. The docker-compose.yml file provides safe defaults via ${VAR:-default} substitution:
cp .env.example .env
# Edit .env if needed, then:
docker compose up --build -d
The defaults in docker-compose.yml are intentionally weak (e.g., change_me_password) and are only suitable for local, non-public environments.
Secret Rotation Procedure
Rotating JWT_KEY
Rotating the JWT signing key will invalidate all existing user sessions β users will need to log in again.
- Generate a new key:
openssl rand -base64 64 - Update the secret in GitHub (Settings β Secrets and variables β Actions β
JWT_KEYβ Update). - Re-run the Deploy to Production workflow to apply the new key.
- Monitor
/health/readyand application logs to confirm the service is healthy.
Rotating POSTGRES_PASSWORD
- Generate a new password:
openssl rand -base64 32 - Update the PostgreSQL user password on the server:
docker exec -it <postgres_container> psql -U agroplatform -c \ "ALTER USER agroplatform WITH PASSWORD 'new-password-here';" - Update the secret in GitHub:
gh secret set POSTGRES_PASSWORD --body "new-password-here" - Re-run the Deploy to Production workflow to restart the API with the new password.
- Verify with
/health/ready.
Verifying Secrets Are Configured
You can run the validation workflow manually at any time without triggering a full deployment:
- Go to Actions β Validate Production Secrets.
- Click Run workflow.
- The workflow will report which secrets are present (β ) and which are missing (β).
The same validation runs automatically as the first job of the Deploy to Production workflow, blocking deployment if any secret is missing.
Security Checklist
Before deploying to production, confirm:
- All 5 required secrets are set in GitHub (repository or
productionenvironment) JWT_KEYis at least 32 characters and randomly generatedPOSTGRES_PASSWORDis strong and unique (not reused from other projects).envfile is listed in.gitignore(it is by default)- No real secret values appear in any committed file
- The
productionenvironment has required reviewers configured DOMAINandEMAILare correct for Letβs Encrypt registration