Server inventory
What it is
One table, in the project's infra repo, listing every server and managed service: what it runs, how it is reached, how it is deployed, backed up and monitored, who owns it, and when it should be deleted. Plus the same facts as tags on the AWS resources.
Why we do it
We found stacks running for weeks with no DNS pointing at them, a bastion left on for a month, and a dev box running past its delete-after date. Each was found by accident. An inventory reviewed monthly finds them on purpose.
Steps
1. Create INVENTORY.md in the infra repo
| Name | Kind | Env | Runs | Access | Deploy | TLS | Backup | Monitor | Owner | Delete after |
|---|---|---|---|---|---|---|---|---|---|---|
acme-prod-api | ECS Fargate | prod | API | none (tasks) | Pipeline on v-* tag | ACM on ALB | n/a | Alarms, Sentry | Tech lead | never |
acme-prod-db | Aurora PostgreSQL 16 | prod | Main database | One-off task in app subnets | Terraform | in transit, RDS CA | 14-day PITR + monthly drill | Alarms | Tech lead | never |
acme-tools | EC2 t4g.small | shared | Feature flags, Compose | SSM only | Bundle via S3 + SSM | Caddy | Nightly pg_dump to S3 | Uptime + disk alarm | DevOps owner | never |
acme-demo | EC2 | sandbox | Sales demo | SSM only | Manual | Caddy | none (rebuildable) | none | Project lead | 2026-12-31 |
Fill every column. "None" is an allowed answer if it is a decision, not a gap.
2. Tag every AWS resource
| Tag | Example | Why |
|---|---|---|
Project | acme | Cost by project |
Environment | prod | Cost and access by environment |
Owner | tech-lead@example.com | Who to ask |
ManagedBy | terraform or manual | Manual resources are drift risks |
DeleteAfter | 2026-12-31 | Temporary resources; a monthly check lists the overdue ones |
Set default tags once in the Terraform AWS provider (default_tags), so nothing is
forgotten.
3. Self-hosted servers outside AWS
For a VPS or a client server, also record: provider, region, OS and version, SSH or VPN method, who holds the access, and where credentials are kept (the vault, never a file).
Check it worked
# resources whose DeleteAfter date has passed
aws resourcegroupstaggingapi get-resources --tag-filters Key=DeleteAfter \
--query 'ResourceTagMappingList[].[ResourceARN, Tags[?Key==`DeleteAfter`].Value | [0]]' \
--output text | awk -v today=$(date +%F) '$2 < today'
Rules
Server passwords and SSH keys live in the team vault, never in text files on a laptop or
in a shared folder. A folder of server.txt files and private keys is one stolen laptop
away from every server.
A resource created by hand gets ManagedBy = manual and a line in the inventory the same
day, or it is deleted.
Done when
-
INVENTORY.mdlists every server and managed service, every column filled. - Default tags set in Terraform; manual resources tagged.
- Credentials for self-hosted servers are in the vault only.