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

Secrets and keys

Reading17mLesson 2 of 4 in this module

What you'll learn

  • Keep secrets out of code
  • Supply secrets at runtime from environment variables or a secrets manager
  • Prefer roles and short-lived tokens so there is no long-lived secret to leak
  • Respond to a leaked secret by revoking or rotating it immediately

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:

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

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

Python
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:

Python
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.

Key terms (5)

secret
Any value that grants access, such as a database password, API key, cloud access key or signing key.
secrets manager
A cloud service that stores secrets encrypted, controls access with IAM, logs use and can rotate them.
key management service
A cloud service that keeps encryption keys inside it and encrypts or decrypts on request, with IAM controlling who may.
Rotation
Replacing a key or password on a schedule, or immediately if it may have leaked.
secret scanning
Automated checks that detect credentials in repositories, sometimes blocking a push before it lands.

Recap

  • Code names the secret; the runtime supplies the value.
  • Environment variables are acceptable; a secrets manager fetched with a role is best for production.
  • Prefer roles and short-lived tokens so there is no long-lived secret at all.
  • Keep .env out of Git and commit a .env.example with names only.
  • If a secret leaks, revoke or rotate it first; deleting the commit is not enough.
Also in this lesson: