Skip to content

🔑 Key & Secrets Management

Level: Core Solves: Secure storage và rotation của secrets, encryption keys, và sensitive configuration

🎯 Mục tiêu (Outcomes)

Sau khi áp dụng kiến thức trong trang này, bạn sẽ có khả năng:

  • Chọn đúng Secret Storage Service dựa trên use case (KMS, Secrets Manager, Parameter Store)
  • Thiết kế KMS Key Hierarchy với CMKs và data keys
  • Triển khai Automatic Rotation cho database credentials và API keys
  • Cấu hình Cross-Account Sharing an toàn
  • Implement Secret Versioning cho zero-downtime rotation
  • Audit Secret Access với CloudTrail và alerting

Khi nào dùng

ServiceUse CaseLý do
KMS CMKEncryption keysKey management, rotation, audit
Secrets ManagerDatabase credentialsAuto-rotation, RDS integration
Secrets ManagerAPI keys, tokensVersioning, cross-account
Parameter Store StandardNon-sensitive configFree, simple
Parameter Store SecureStringSensitive config không cần rotationCheaper than Secrets Manager

Khi nào KHÔNG dùng

PatternVấn đềThay thế
Hardcode secrets trong codeSecurity risk, khó rotateSecrets Manager
Environment variables cho productionVisible trong console, logsSecrets Manager
Parameter Store cho DB passwordsKhông auto-rotationSecrets Manager
Secrets Manager cho static configUnnecessary costParameter Store
AWS-managed keys cho complianceKhông control key policyCustomer-managed CMK

⚠️ Cảnh báo từ Raizo

"Một developer commit AWS access key vào GitHub. Trong vòng 10 phút, crypto miners đã spin up $50,000 EC2 instances. Secret scanning và rotation policy là critical. Assume secrets SẼ bị leak và plan accordingly."

Service Selection

Decision Matrix

┌─────────────────────────────────────────────────────────────────┐
│              SECRETS MANAGEMENT DECISION                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  What are you storing?                                          │
│                                                                 │
│  ├── Encryption keys → KMS                                      │
│  │   • Customer master keys (CMKs)                              │
│  │   • Data encryption keys                                     │
│  │   • Asymmetric keys for signing                              │
│  │                                                              │
│  ├── Database credentials → Secrets Manager                     │
│  │   • Automatic rotation                                       │
│  │   • RDS integration                                          │
│  │   • Cross-account sharing                                    │
│  │                                                              │
│  ├── API keys, tokens → Secrets Manager                         │
│  │   • Third-party service credentials                          │
│  │   • OAuth tokens                                             │
│  │   • Webhook secrets                                          │
│  │                                                              │
│  └── Configuration values → Parameter Store                     │
│      • Feature flags                                            │
│      • Environment-specific config                              │
│      • Non-sensitive settings                                   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Service Comparison

FeatureKMSSecrets ManagerParameter Store
PurposeKey managementSecrets storageConfig storage
RotationManualAutomaticManual
Pricing$1/key/month$0.40/secret/monthFree (Standard)
Size Limit4KB64KB8KB (Advanced)
VersioningNoYesYes
Cross-AccountYesYesLimited

AWS KMS

Key Hierarchy

┌─────────────────────────────────────────────────────────────────┐
│                    KMS KEY HIERARCHY                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              Customer Master Key (CMK)                   │    │
│  │              • Never leaves KMS                          │    │
│  │              • Used to encrypt Data Keys                 │    │
│  └────────────────────────┬────────────────────────────────┘    │
│                           │                                     │
│                           ▼                                     │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              Data Encryption Key (DEK)                   │    │
│  │              • Generated by KMS                          │    │
│  │              • Used to encrypt actual data               │    │
│  │              • Stored encrypted alongside data           │    │
│  └────────────────────────┬────────────────────────────────┘    │
│                           │                                     │
│                           ▼                                     │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                    Your Data                             │    │
│  │              • Encrypted with DEK                        │    │
│  │              • Stored in S3, EBS, etc.                   │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                 │
│  ENVELOPE ENCRYPTION:                                           │
│  Data → Encrypted with DEK → DEK encrypted with CMK             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Key Types

TypeManagementUse Case
AWS ManagedAWSDefault encryption (S3, EBS)
Customer ManagedYouCustom policies, rotation
Customer OwnedYou (CloudHSM)Regulatory requirements

Key Policy Example

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Enable IAM policies",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": "kms:*",
      "Resource": "*"
    },
    {
      "Sid": "Allow key administrators",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/KeyAdminRole"
      },
      "Action": [
        "kms:Create*",
        "kms:Describe*",
        "kms:Enable*",
        "kms:List*",
        "kms:Put*",
        "kms:Update*",
        "kms:Revoke*",
        "kms:Disable*",
        "kms:Get*",
        "kms:Delete*",
        "kms:ScheduleKeyDeletion",
        "kms:CancelKeyDeletion"
      ],
      "Resource": "*"
    },
    {
      "Sid": "Allow key usage",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/ApplicationRole"
      },
      "Action": [
        "kms:Encrypt",
        "kms:Decrypt",
        "kms:GenerateDataKey*"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:ViaService": "s3.us-east-1.amazonaws.com"
        }
      }
    }
  ]
}

AWS Secrets Manager

Secret Lifecycle

Secret Structure

json
{
  "username": "app_user",
  "password": "super-secret-password",
  "engine": "mysql",
  "host": "mydb.cluster-xxx.us-east-1.rds.amazonaws.com",
  "port": 3306,
  "dbname": "myapp"
}

Rotation Configuration

python
import boto3
import json

def create_secret_with_rotation():
    client = boto3.client('secretsmanager')
    
    # Create secret
    response = client.create_secret(
        Name='prod/myapp/database',
        Description='Production database credentials',
        SecretString=json.dumps({
            'username': 'app_user',
            'password': 'initial-password',
            'engine': 'mysql',
            'host': 'mydb.xxx.us-east-1.rds.amazonaws.com',
            'port': 3306,
            'dbname': 'myapp'
        }),
        Tags=[
            {'Key': 'Environment', 'Value': 'production'},
            {'Key': 'Application', 'Value': 'myapp'}
        ]
    )
    
    # Enable rotation
    client.rotate_secret(
        SecretId='prod/myapp/database',
        RotationLambdaARN='arn:aws:lambda:us-east-1:123456789012:function:SecretsRotation',
        RotationRules={
            'AutomaticallyAfterDays': 30,
            'ScheduleExpression': 'rate(30 days)'
        }
    )

Application Integration

python
import boto3
import json
from botocore.exceptions import ClientError

def get_secret(secret_name: str, region: str = 'us-east-1') -> dict:
    """Retrieve secret from Secrets Manager with caching"""
    
    client = boto3.client('secretsmanager', region_name=region)
    
    try:
        response = client.get_secret_value(SecretId=secret_name)
        
        if 'SecretString' in response:
            return json.loads(response['SecretString'])
        else:
            # Binary secret
            return response['SecretBinary']
            
    except ClientError as e:
        if e.response['Error']['Code'] == 'ResourceNotFoundException':
            raise ValueError(f"Secret {secret_name} not found")
        elif e.response['Error']['Code'] == 'InvalidRequestException':
            raise ValueError(f"Invalid request for secret {secret_name}")
        else:
            raise

# Usage
db_creds = get_secret('prod/myapp/database')
connection = mysql.connector.connect(
    host=db_creds['host'],
    user=db_creds['username'],
    password=db_creds['password'],
    database=db_creds['dbname']
)

Parameter Store

Parameter Hierarchy

┌─────────────────────────────────────────────────────────────────┐
│              PARAMETER STORE HIERARCHY                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  /myapp/                                                        │
│  ├── /myapp/production/                                         │
│  │   ├── /myapp/production/database/host                        │
│  │   ├── /myapp/production/database/port                        │
│  │   ├── /myapp/production/api/endpoint                         │
│  │   └── /myapp/production/feature/new-ui-enabled               │
│  │                                                              │
│  ├── /myapp/staging/                                            │
│  │   ├── /myapp/staging/database/host                           │
│  │   └── /myapp/staging/api/endpoint                            │
│  │                                                              │
│  └── /myapp/shared/                                             │
│      ├── /myapp/shared/log-level                                │
│      └── /myapp/shared/timeout                                  │
│                                                                 │
│  Benefits:                                                      │
│  • IAM policies can scope to path prefix                        │
│  • GetParametersByPath for bulk retrieval                       │
│  • Clear organization by environment                            │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Parameter Types

TypeUse CaseEncryption
StringPlain text configNo
StringListComma-separated valuesNo
SecureStringSensitive valuesKMS

Bulk Retrieval

python
import boto3

def get_parameters_by_path(path: str) -> dict:
    """Get all parameters under a path"""
    
    ssm = boto3.client('ssm')
    parameters = {}
    
    paginator = ssm.get_paginator('get_parameters_by_path')
    
    for page in paginator.paginate(
        Path=path,
        Recursive=True,
        WithDecryption=True
    ):
        for param in page['Parameters']:
            # Convert path to key
            key = param['Name'].replace(path, '').lstrip('/')
            parameters[key] = param['Value']
    
    return parameters

# Usage
config = get_parameters_by_path('/myapp/production/')
# Returns: {'database/host': 'xxx', 'database/port': '3306', ...}

Cross-Account Secrets Sharing

Architecture

┌─────────────────────────────────────────────────────────────────┐
│           CROSS-ACCOUNT SECRETS SHARING                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Shared Services Account              Workload Account          │
│  ┌─────────────────────┐             ┌─────────────────────┐    │
│  │                     │             │                     │    │
│  │ ┌─────────────────┐ │             │ ┌─────────────────┐ │    │
│  │ │ Secrets Manager │ │             │ │   Application   │ │    │
│  │ │                 │◄┼─────────────┼─┤                 │ │    │
│  │ │ • DB creds      │ │  AssumeRole │ │ • Reads secrets │ │    │
│  │ │ • API keys      │ │             │ │                 │ │    │
│  │ └─────────────────┘ │             │ └─────────────────┘ │    │
│  │                     │             │                     │    │
│  │ ┌─────────────────┐ │             │                     │    │
│  │ │      KMS        │ │             │                     │    │
│  │ │ (Encryption key)│ │             │                     │    │
│  │ └─────────────────┘ │             │                     │    │
│  │                     │             │                     │    │
│  └─────────────────────┘             └─────────────────────┘    │
│                                                                 │
│  Requirements:                                                  │
│  1. Secret resource policy allows cross-account access          │
│  2. KMS key policy allows cross-account decrypt                 │
│  3. Workload account has IAM role with permissions              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Resource Policy

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::222222222222:role/WorkloadAppRole"
      },
      "Action": "secretsmanager:GetSecretValue",
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "secretsmanager:VersionStage": "AWSCURRENT"
        }
      }
    }
  ]
}

Best Practices

Secret Naming Convention

{environment}/{application}/{secret-type}/{name}

Examples:
- prod/payment-service/database/primary
- staging/api-gateway/credentials/stripe
- shared/infrastructure/ssh/bastion-key

Security Checklist

  • [ ] Use Secrets Manager for credentials that need rotation
  • [ ] Enable automatic rotation for database credentials
  • [ ] Use customer-managed KMS keys for sensitive secrets
  • [ ] Implement least privilege access to secrets
  • [ ] Enable CloudTrail logging for secret access
  • [ ] Use resource policies for cross-account sharing
  • [ ] Never hardcode secrets in application code
  • [ ] Rotate secrets on suspected compromise

⚖️ Trade-offs

Trade-off 1: Secrets Manager vs Parameter Store

Khía cạnhSecrets ManagerParameter Store SecureString
Cost$0.40/secret/thángFree (Standard)
RotationAutomaticManual
Cross-accountNative supportCần Lambda
VersioningBuilt-inLimited
RDS integrationNativeManual

Khuyến nghị:

  • Secrets Manager: Database credentials, API keys cần rotation
  • Parameter Store: Config values, flags, secrets ít thay đổi

Trade-off 2: AWS-managed vs Customer-managed KMS Keys

Khía cạnhAWS-managedCustomer-managed
CostFree$1/key/tháng
Key policyAWS controlsYou control
RotationAutomatic (yearly)You configure
Cross-accountKhông
ComplianceLimited proofFull control

Trade-off 3: Rotation Frequency vs Operational Overhead

Rotation PeriodSecurityOverheadUse Case
DailyRất caoCaoUltra-sensitive
WeeklyCaoTrung bìnhProduction credentials
30 daysTrung bìnhThấpStandard
90 daysThấpRất thấpLow-risk

🚨 Failure Modes

Failure Mode 1: Rotation Breaks Application

🔥 Incident thực tế

Auto-rotation chạy nhưng application vẫn cache old password. Database connections fail. Production down 2 giờ. Team không biết về secret versioning.

Cách phát hiệnCách phòng tránh
Application errors post-rotationTest rotation trong staging
Database connection failuresUse AWSCURRENTAWSPREVIOUS labels
Rotation Lambda errorsMonitor rotation Lambda metrics

Failure Mode 2: Secret Exposure

Cách phát hiỆnCách phòng tránh
CloudTrail unusual accessRestrict secret access với IAM
GitHub secret scanning alertsPre-commit hooks, git-secrets
GuardDuty findingsResource policies cho secrets
Credential usage từ unknown locationsVPC endpoints, IP restrictions

Failure Mode 3: KMS Key Deletion

Cách phát hiệnCách phòng tránh
ScheduleKeyDeletion CloudTrail eventSCPs block key deletion
Decryption failures7-30 day deletion window
Data inaccessibleKey policy restrictions

🔐 Security Baseline

Secrets Security Requirements

RequirementImplementationVerification
No hardcoded secretsCode scanningPre-commit hooks
Encryption at restKMS encryptionDefault enabled
Access loggingCloudTrail data eventsEnabled organization-wide
Rotation policyAuto-rotation enabledCompliance check
Least privilegeIAM policiesAccess Analyzer

Secret Access Pattern

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["secretsmanager:GetSecretValue"],
      "Resource": "arn:aws:secretsmanager:*:*:secret:prod/*",
      "Condition": {
        "StringEquals": {
          "secretsmanager:VersionStage": "AWSCURRENT"
        },
        "IpAddress": {
          "aws:VpcSourceIp": "10.0.0.0/8"
        }
      }
    }
  ]
}

📊 Ops Readiness

Metrics cần Monitoring

MetricSourceAlert Threshold
Secret access from unknown principalCloudTrailAny
Rotation Lambda errorsCloudWatch> 0
KMS key scheduled for deletionCloudTrailAny
Secret access deniedCloudTrailSpike
Decryption failuresCloudWatch> 0

Runbook Entry Points

Tình huốngRunbook
Suspected secret leakrunbook/secret-rotation-emergency.md
Rotation failurerunbook/rotation-troubleshooting.md
KMS key issuesrunbook/kms-key-recovery.md
Cross-account access deniedrunbook/secrets-cross-account.md
Application can't access secretrunbook/secret-access-debug.md

Design Review Checklist

Secret Storage

  • [ ] Đúng service cho từng loại secret
  • [ ] Naming convention consistent
  • [ ] KMS key selection appropriate
  • [ ] Cross-account access configured nếu cần

Rotation

  • [ ] Auto-rotation enabled cho credentials
  • [ ] Rotation đã test trong non-prod
  • [ ] Application hỗ trợ secret versioning
  • [ ] Rotation Lambda monitored

Security

  • [ ] Least privilege IAM
  • [ ] CloudTrail logging enabled
  • [ ] No hardcoded secrets trong code
  • [ ] Secret scanning trong CI/CD

Operations

  • [ ] Access monitoring configured
  • [ ] Alerting cho anomalies
  • [ ] Runbooks documented
  • [ ] Emergency rotation procedure

📎 Liên kết