EbookFoundation / EbookFoundation/regluit-provisioning

AWS hygiene: replace static IAM user keys in prod.wsgi with an EC2 instance role (keyless S3 auth)

Open
#59 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Shell
Stars
6
Forks
8
Avg merge
1h 13m
Merged PRs (30d)
2

Description

**Why**: prod.wsgi embeds long-lived IAM *user* access keys (`aws_access_key_id`/`aws_secret_access_key`, from `host_keys` in group_vars/production) as plaintext env exports, used solely for S3 media storage (`DEFAULT_FILE_STORAGE = S3Boto3Storage`, bucket `tieulgnu`). The box is EC2 — it can authenticate to S3 via an **attached IAM instance profile** and carry **zero** static AWS keys in any file.

Surfaced by the 2026-07-01 leak: a `--check --diff` drift audit printed prod.wsgi's rendered secrets (incl. the AWS key) into an AI transcript. With an instance role, there would have been **no AWS credential to leak**. The static key is also in the aws-hygiene backlog ("rotate s3user prod key") — this is the durable version of that.

**Scope**
1. Create/confirm an IAM role with least-privilege access to the `tieulgnu` bucket (and any other S3 the app touches); attach as an instance profile to the prod EC2.
2. Confirm boto3/django-storages picks up the instance-role credentials automatically (drop the explicit `AWS_ACCESS_KEY_ID`/`SECRET` so the default provider chain → instance metadata is used).
3. Remove `aws_access_key_id`/`aws_secret_access_key` from `host_keys` (group_vars + vault); keep `aws_storage_bucket_name`.
4. Verify media upload/serve on **test** first (once test is a real testbed — provisioning#56), then prod.
5. Then deactivate+delete the static s3user key.

**Related**: this PR-#58 (no_log + 0640 hardening of prod.wsgi — the immediate containment), #56 (single-source-of-truth reconciliation; note the latent bug that prod.wsgi isn't re-rendered on `--tags config`, so key rotations silently miss it — an instance role removes that failure mode entirely).

**Blast-radius note for whoever picks this up**: verify which services share this key (S3 media only, or also SES/other?) before deletion — SES uses a *separate* `email_host_user` credential, not this AWS key.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_017f8mDXQDLfw3A34ynseDyc

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by tracing the AWS key from prod.wsgi and group_vars/production, including the vault, and verify which services use it; PRs #58 and #56 provide related context. Confirm the least-privilege instance role and testbed path, then verify media upload and serving on test before prod. Done means no static S3 keys remain, the instance profile works, and the old key is deactivated and deleted.

Written by the indexing model from the issue text.

Assessment

Tech stack
ansible, aws
Domain
cloud, devops, infrastructure, security
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.