Skip to main content
Back to module
Cloud Fundamentals · Identity and Security

Secrets and keys

Reading17mLesson 2 of 4 in this module

Keep passwords, API keys and other secrets out of code and fetch them safely at runtime.

Why it matters

A secret is any value that grants access: database passwords, API keys, cloud access keys, private TLS keys, signing keys, webhook tokens. Once a secret is committed to a Git repository, you should assume it is public: forks, clones, CI logs and backups keep copies even after you delete the line. Attackers run bots that scan public repositories for cloud keys and start using them within minutes, often to mine cryptocurrency on your bill.

The core idea

Code should say which secret it needs, never what the secret is. The value is supplied at runtime from a place designed to protect it, and access to that place is controlled by IAM.

A ladder from worst to best:

  1. Hard-coded in source. Never.
  2. In a config file committed to Git. Never.
  3. In environment variables set by the deployment platform. Acceptable for many apps, as long as the values themselves are stored securely by the platform and not echoed into logs.
  4. In a secrets manager (AWS Secrets Manager or Systems Manager Parameter Store SecureString, Azure Key Vault, Google Secret Manager), fetched at runtime by a role. Best for production: central storage, encryption with a managed key, access logging and rotation.
  5. No long-lived secret at all. Use roles and short-lived tokens wherever the service supports it, for example a VM role instead of an access key, or a CI system using OpenID Connect to assume a cloud role.

Worked example: from hard-coded to managed

The anti-pattern:

# app.py  (do not do this)
DB_PASSWORD = "S3cretPassw0rd!"

Step one, read it from the environment and fail loudly if it is missing:

import os

DB_PASSWORD = os.environ["DB_PASSWORD"]   # KeyError at start-up if not set

For local development, keep values in a .env file that is listed in .gitignore, and commit a .env.example with names but no values:

# .gitignore
.env

# .env.example (committed)
DB_PASSWORD=
PAYMENTS_API_KEY=

Step two, in production fetch the secret from a manager using the compute's role, so no secret ever sits in the deployment configuration:

import json
import boto3

def get_db_password():
    client = boto3.client("secretsmanager")
    resp = client.get_secret_value(SecretId="prod/shop/db")
    return json.loads(resp["SecretString"])["password"]

The role's policy allows secretsmanager:GetSecretValue on that one secret only, which is least privilege applied to secrets.

Keys and encryption

Encryption keys are a special kind of secret. Cloud key management services (AWS KMS, Azure Key Vault keys, Google Cloud KMS) keep the key material inside the service; you ask the service to encrypt or decrypt, and IAM controls who may do so. Most storage and database services can encrypt at rest with a managed key at the tick of a box. Rotation means replacing a key or password on a schedule, or immediately if it may have leaked. Secrets managers can rotate some database passwords automatically.

If a secret leaks

Act in this order:

  1. Revoke or rotate it immediately in the system that issued it. Deleting the commit is not enough.
  2. Check access logs (for example AWS CloudTrail) for use of the leaked credential.
  3. Remove it from the repository history if needed, and add scanning to stop a repeat.

Secret scanning tools (GitHub secret scanning and push protection, gitleaks, trufflehog) catch many leaks before or just after they happen.

Common mistakes

  • Printing configuration (including secrets) to logs at start-up.
  • Sharing one powerful key across many apps and people, so it can never be rotated safely.
  • Committing .env "just once" for a teammate.
  • Putting secrets in container images or front-end JavaScript, where anyone can read them.
  • Rotating a leaked key days later "after the release".

Quick recap

  • Code names the secret; the runtime supplies the value from environment variables or, better, a secrets manager.
  • Prefer roles and short-lived tokens so there is no long-lived secret to leak.
  • Keep .env out of Git, scan for secrets, and rotate immediately on any leak.
Also in this lesson: