Secrets Manager stores credentials encrypted with KMS, controls access through IAM, logs every read to CloudTrail, and, the part that justifies its price, rotates supported secrets automatically without anyone touching a config file.\n\nThat last capability is the deciding factor. If you don't need rotation, Parameter Store does the same job for free.\n\n## Creating a secret\n\nbash\naws secretsmanager create-secret \\\n --name prod/payments/db \\\n --description \"Aurora credentials for the payments service\" \\\n --secret-string '{\"username\":\"payments\",\"password\":\"REPLACE_ME\",\"host\":\"db.internal\",\"port\":5432}'\n\n\njson\n{\n \"ARN\": \"arn:aws:secretsmanager:us-east-1:111122223333:secret:prod/payments/db-AbCdEf\",\n \"Name\": \"prod/payments/db\",\n \"VersionId\": \"8f3c1e2a-...\"\n}\n\n\nNote the six random characters AWS appends to the ARN. They're deliberate: they stop a deleted secret's name from being immediately reusable by someone who might inherit its permissions. It also means you can't construct a secret ARN by hand, if you're writing IAM policies, either look the ARN up or end the resource with a wildcard: arn:aws:secretsmanager:us-east-1:111122223333:secret:prod/payments/db-*.\n\nStore JSON rather than a bare string. Rotation functions expect structured fields, and it lets one secret carry the host and port alongside the credentials.\n\nUse a naming convention with a path-like shape, \u003cenv\u003e/\u003cservice\u003e/\u003cpurpose\u003e, because IAM policies can then grant a service everything under its own prefix:\n\njson\n{\n \"Effect\": \"Allow\",\n \"Action\": \"secretsmanager:GetSecretValue\",\n \"Resource\": \"arn:aws:secretsmanager:us-east-1:111122223333:secret:prod/payments/*\"\n}\n\n\n## Reading a secret\n\nbash\naws secretsmanager get-secret-value \\\n --secret-id prod/payments/db \\\n --query SecretString --output text\n\n\nIn application code, retrieve at startup and cache, never call Secrets Manager on every request:\n\n```python\nimport json, boto3\nfrom botocore.exceptions import ClientError\n\n_cache = {}\n\ndef get_secret(name: str, region: str = "us-east-1") -\u003e dict:\n if name in _cache:\n return _cache[name]\n client = boto3.client("secretsmanager", region_name=region)\n try:\n response = client.get_secret_value(SecretId=name)\n except ClientError as err:\n # ResourceNotFoundException here is almost always a region mismatch.\n raise RuntimeError(f"Could not read secret {name}: {err}") from err\n _cache[name] = json.loads(response["SecretString\
Learn how IAM users and groups work, why AWS recommends against IAM users for people, how to keep access keys safe and how to move to IAM Identity Center.
Understand IAM roles and policies: trust vs permission policies, assuming roles with STS, managed vs inline policies, boundaries and AssumeRole errors.
Harden IAM: replace IAM users with Identity Center, drop long-lived CI keys, lock down root, reach least privilege from usage data and set boundaries.