@icarusmx/creta 1.5.6 → 1.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
# AWS Billing Detective Guide 🕵️
|
|
2
|
+
|
|
3
|
+
## The Mystery: "I turned everything off but AWS still charges me"
|
|
4
|
+
|
|
5
|
+
Common culprits (in order of likelihood):
|
|
6
|
+
1. **EBS Volumes** (orphaned disks after stopping EC2)
|
|
7
|
+
2. **Elastic IPs** (charged when not attached to running instance)
|
|
8
|
+
3. **Snapshots** (backups accumulating)
|
|
9
|
+
4. **NAT Gateways** ($0.045/hour = $32/month EACH)
|
|
10
|
+
5. **Load Balancers** (ALB/NLB = $16-22/month each)
|
|
11
|
+
6. **RDS instances** (databases running in background)
|
|
12
|
+
7. **S3 storage** (forgotten buckets)
|
|
13
|
+
8. **CloudWatch logs** (accumulating logs)
|
|
14
|
+
9. **Data transfer** (cross-region/out-to-internet)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Part 1: Get Your AWS Access Keys
|
|
19
|
+
|
|
20
|
+
### Step 1: Navigate to IAM Console
|
|
21
|
+
1. Log into AWS Console: https://console.aws.amazon.com
|
|
22
|
+
2. Search for "IAM" in top search bar
|
|
23
|
+
3. Click **IAM** (Identity and Access Management)
|
|
24
|
+
|
|
25
|
+
### Step 2: Create Access Keys
|
|
26
|
+
1. In left sidebar → Click **Users**
|
|
27
|
+
2. Click your username
|
|
28
|
+
3. Click **Security credentials** tab
|
|
29
|
+
4. Scroll to **Access keys** section
|
|
30
|
+
5. Click **Create access key**
|
|
31
|
+
6. Select use case: **"Command Line Interface (CLI)"**
|
|
32
|
+
7. Check acknowledgment box
|
|
33
|
+
8. Click **Next** → **Create access key**
|
|
34
|
+
9. **IMPORTANT:** Download `.csv` or copy both:
|
|
35
|
+
- Access key ID (like `AKIAIOSFODNN7EXAMPLE`)
|
|
36
|
+
- Secret access key (like `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`)
|
|
37
|
+
- **You can't see the secret again!**
|
|
38
|
+
|
|
39
|
+
### Step 3: (Alternative) Use Existing Keys
|
|
40
|
+
If you already created keys before:
|
|
41
|
+
- Check your `~/.aws/credentials` file
|
|
42
|
+
- Or retrieve from password manager
|
|
43
|
+
- **Never share these or commit to git**
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Part 2: Install & Configure AWS CLI
|
|
48
|
+
|
|
49
|
+
### Install AWS CLI
|
|
50
|
+
|
|
51
|
+
**macOS:**
|
|
52
|
+
```bash
|
|
53
|
+
brew install awscli
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Linux:**
|
|
57
|
+
```bash
|
|
58
|
+
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
|
|
59
|
+
unzip awscliv2.zip
|
|
60
|
+
sudo ./aws/install
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Windows:**
|
|
64
|
+
Download installer from: https://aws.amazon.com/cli/
|
|
65
|
+
|
|
66
|
+
### Configure AWS CLI
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
aws configure
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
You'll be prompted:
|
|
73
|
+
```
|
|
74
|
+
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
|
|
75
|
+
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
|
|
76
|
+
Default region name [None]: us-east-1
|
|
77
|
+
Default output format [None]: json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Configuration is saved to:**
|
|
81
|
+
- `~/.aws/credentials` (keys)
|
|
82
|
+
- `~/.aws/config` (region/settings)
|
|
83
|
+
|
|
84
|
+
### Verify Setup
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
aws sts get-caller-identity
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Should return your account ID and user ARN.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Part 3: The AWS Billing Audit
|
|
95
|
+
|
|
96
|
+
### 🔍 Step 1: Check Which Regions You're Using
|
|
97
|
+
|
|
98
|
+
AWS charges can hide in regions you forgot about.
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# List all regions
|
|
102
|
+
aws ec2 describe-regions --output table
|
|
103
|
+
|
|
104
|
+
# Check which regions have resources
|
|
105
|
+
for region in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do
|
|
106
|
+
echo "Checking region: $region"
|
|
107
|
+
aws ec2 describe-instances --region $region --output table 2>/dev/null | grep -v "^$"
|
|
108
|
+
done
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Most common regions:**
|
|
112
|
+
- `us-east-1` (N. Virginia) - DEFAULT, check this first
|
|
113
|
+
- `us-west-2` (Oregon)
|
|
114
|
+
- `eu-west-1` (Ireland)
|
|
115
|
+
|
|
116
|
+
### 🔍 Step 2: Hunt for EC2 Charges
|
|
117
|
+
|
|
118
|
+
#### List ALL EC2 Instances (all states)
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# Check default region
|
|
122
|
+
aws ec2 describe-instances --output table
|
|
123
|
+
|
|
124
|
+
# Check specific region
|
|
125
|
+
aws ec2 describe-instances --region us-east-1 --output table
|
|
126
|
+
|
|
127
|
+
# One-liner: Show instance ID, state, and type
|
|
128
|
+
aws ec2 describe-instances \
|
|
129
|
+
--query 'Reservations[].Instances[].[InstanceId,State.Name,InstanceType]' \
|
|
130
|
+
--output table
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### Stop Running Instances
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# Stop specific instance
|
|
137
|
+
aws ec2 stop-instances --instance-ids i-1234567890abcdef0
|
|
138
|
+
|
|
139
|
+
# Stop ALL running instances in region (⚠️ DANGEROUS)
|
|
140
|
+
aws ec2 stop-instances --instance-ids $(aws ec2 describe-instances \
|
|
141
|
+
--query 'Reservations[].Instances[?State.Name==`running`].InstanceId' \
|
|
142
|
+
--output text)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### Terminate Instances (permanent deletion)
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Terminate specific instance
|
|
149
|
+
aws ec2 terminate-instances --instance-ids i-1234567890abcdef0
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 🔍 Step 3: Hunt for EBS Volumes (THE USUAL SUSPECT)
|
|
153
|
+
|
|
154
|
+
**When you stop an EC2 instance, its disk (EBS volume) keeps running and charging!**
|
|
155
|
+
|
|
156
|
+
#### List ALL EBS Volumes
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Show all volumes with state and size
|
|
160
|
+
aws ec2 describe-volumes \
|
|
161
|
+
--query 'Volumes[].[VolumeId,State,Size,VolumeType]' \
|
|
162
|
+
--output table
|
|
163
|
+
|
|
164
|
+
# Show only AVAILABLE volumes (not attached = wasting money)
|
|
165
|
+
aws ec2 describe-volumes \
|
|
166
|
+
--filters "Name=status,Values=available" \
|
|
167
|
+
--query 'Volumes[].[VolumeId,Size,VolumeType,CreateTime]' \
|
|
168
|
+
--output table
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Available volumes = orphaned disks = charging you for nothing**
|
|
172
|
+
|
|
173
|
+
#### Calculate EBS Costs
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Get total GB of volumes
|
|
177
|
+
aws ec2 describe-volumes \
|
|
178
|
+
--query 'sum(Volumes[].Size)' \
|
|
179
|
+
--output text
|
|
180
|
+
|
|
181
|
+
# Rough cost: gp3 = $0.08/GB/month, gp2 = $0.10/GB/month
|
|
182
|
+
# Example: 100GB gp3 = $8/month
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### Delete Unused EBS Volumes
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Delete specific volume
|
|
189
|
+
aws ec2 delete-volume --volume-id vol-049df61146c4d7901
|
|
190
|
+
|
|
191
|
+
# ⚠️ Delete ALL available volumes (be careful!)
|
|
192
|
+
for vol in $(aws ec2 describe-volumes \
|
|
193
|
+
--filters "Name=status,Values=available" \
|
|
194
|
+
--query 'Volumes[].VolumeId' \
|
|
195
|
+
--output text); do
|
|
196
|
+
echo "Deleting volume: $vol"
|
|
197
|
+
aws ec2 delete-volume --volume-id $vol
|
|
198
|
+
done
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 🔍 Step 4: Hunt for Elastic IPs (Silent Killers)
|
|
202
|
+
|
|
203
|
+
**Elastic IPs are FREE when attached to a running instance.**
|
|
204
|
+
**But they cost $0.005/hour ($3.60/month) when not attached!**
|
|
205
|
+
|
|
206
|
+
#### List Elastic IPs
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Show all Elastic IPs
|
|
210
|
+
aws ec2 describe-addresses --output table
|
|
211
|
+
|
|
212
|
+
# Show unattached IPs (costing money)
|
|
213
|
+
aws ec2 describe-addresses \
|
|
214
|
+
--query 'Addresses[?AssociationId==null].[PublicIp,AllocationId]' \
|
|
215
|
+
--output table
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
#### Release Elastic IPs
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
# Release specific IP
|
|
222
|
+
aws ec2 release-address --allocation-id eipalloc-12345678
|
|
223
|
+
|
|
224
|
+
# Release ALL unattached IPs
|
|
225
|
+
for ip in $(aws ec2 describe-addresses \
|
|
226
|
+
--query 'Addresses[?AssociationId==null].AllocationId' \
|
|
227
|
+
--output text); do
|
|
228
|
+
echo "Releasing IP: $ip"
|
|
229
|
+
aws ec2 release-address --allocation-id $ip
|
|
230
|
+
done
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### 🔍 Step 5: Hunt for NAT Gateways (EXPENSIVE!)
|
|
234
|
+
|
|
235
|
+
**NAT Gateways cost $0.045/hour = $32.40/month EACH + data transfer**
|
|
236
|
+
|
|
237
|
+
#### List NAT Gateways
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
aws ec2 describe-nat-gateways --output table
|
|
241
|
+
|
|
242
|
+
# Show only active NAT gateways
|
|
243
|
+
aws ec2 describe-nat-gateways \
|
|
244
|
+
--filter "Name=state,Values=available" \
|
|
245
|
+
--query 'NatGateways[].[NatGatewayId,State,SubnetId]' \
|
|
246
|
+
--output table
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
#### Delete NAT Gateways
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
# Delete specific NAT gateway
|
|
253
|
+
aws ec2 delete-nat-gateway --nat-gateway-id nat-0a1b2c3d4e5f6g7h8
|
|
254
|
+
|
|
255
|
+
# Delete ALL NAT gateways (⚠️ careful)
|
|
256
|
+
for nat in $(aws ec2 describe-nat-gateways \
|
|
257
|
+
--filter "Name=state,Values=available" \
|
|
258
|
+
--query 'NatGateways[].NatGatewayId' \
|
|
259
|
+
--output text); do
|
|
260
|
+
echo "Deleting NAT Gateway: $nat"
|
|
261
|
+
aws ec2 delete-nat-gateway --nat-gateway-id $nat
|
|
262
|
+
done
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### 🔍 Step 6: Hunt for Load Balancers
|
|
266
|
+
|
|
267
|
+
**ALB = $16-22/month, NLB = $16-22/month**
|
|
268
|
+
|
|
269
|
+
#### List Load Balancers
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# Application Load Balancers
|
|
273
|
+
aws elbv2 describe-load-balancers --output table
|
|
274
|
+
|
|
275
|
+
# Classic Load Balancers
|
|
276
|
+
aws elb describe-load-balancers --output table
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
#### Delete Load Balancers
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
# Delete Application Load Balancer
|
|
283
|
+
aws elbv2 delete-load-balancer --load-balancer-arn arn:aws:elasticloadbalancing:...
|
|
284
|
+
|
|
285
|
+
# Delete Classic Load Balancer
|
|
286
|
+
aws elb delete-load-balancer --load-balancer-name my-load-balancer
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### 🔍 Step 7: Hunt for RDS Databases
|
|
290
|
+
|
|
291
|
+
#### List RDS Instances
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
aws rds describe-db-instances \
|
|
295
|
+
--query 'DBInstances[].[DBInstanceIdentifier,DBInstanceStatus,DBInstanceClass]' \
|
|
296
|
+
--output table
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
#### Stop RDS Instance (temporary - 7 days max)
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
aws rds stop-db-instance --db-instance-identifier mydbinstance
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
#### Delete RDS Instance (permanent)
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
# Without final snapshot
|
|
309
|
+
aws rds delete-db-instance \
|
|
310
|
+
--db-instance-identifier mydbinstance \
|
|
311
|
+
--skip-final-snapshot
|
|
312
|
+
|
|
313
|
+
# With final snapshot (safer)
|
|
314
|
+
aws rds delete-db-instance \
|
|
315
|
+
--db-instance-identifier mydbinstance \
|
|
316
|
+
--final-db-snapshot-identifier mydb-final-snapshot
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### 🔍 Step 8: Hunt for Snapshots
|
|
320
|
+
|
|
321
|
+
#### List EBS Snapshots
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
# Show your snapshots
|
|
325
|
+
aws ec2 describe-snapshots --owner-ids self \
|
|
326
|
+
--query 'Snapshots[].[SnapshotId,VolumeSize,StartTime]' \
|
|
327
|
+
--output table
|
|
328
|
+
|
|
329
|
+
# Calculate total GB
|
|
330
|
+
aws ec2 describe-snapshots --owner-ids self \
|
|
331
|
+
--query 'sum(Snapshots[].VolumeSize)' \
|
|
332
|
+
--output text
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
#### Delete Snapshots
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
# Delete specific snapshot
|
|
339
|
+
aws ec2 delete-snapshot --snapshot-id snap-1234567890abcdef0
|
|
340
|
+
|
|
341
|
+
# Delete old snapshots (BE CAREFUL - this is destructive)
|
|
342
|
+
for snap in $(aws ec2 describe-snapshots --owner-ids self \
|
|
343
|
+
--query 'Snapshots[].SnapshotId' --output text); do
|
|
344
|
+
echo "Deleting snapshot: $snap"
|
|
345
|
+
aws ec2 delete-snapshot --snapshot-id $snap
|
|
346
|
+
done
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### 🔍 Step 9: Hunt for S3 Buckets
|
|
350
|
+
|
|
351
|
+
#### List S3 Buckets and Sizes
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
# List all buckets
|
|
355
|
+
aws s3 ls
|
|
356
|
+
|
|
357
|
+
# Show bucket sizes (slow, but accurate)
|
|
358
|
+
for bucket in $(aws s3 ls | awk '{print $3}'); do
|
|
359
|
+
echo "Bucket: $bucket"
|
|
360
|
+
aws s3 ls s3://$bucket --recursive --summarize | grep "Total Size"
|
|
361
|
+
done
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### Delete S3 Bucket
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
# Empty bucket first
|
|
368
|
+
aws s3 rm s3://my-bucket --recursive
|
|
369
|
+
|
|
370
|
+
# Then delete bucket
|
|
371
|
+
aws s3 rb s3://my-bucket
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### 🔍 Step 10: Check CloudWatch Logs
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
# List log groups
|
|
378
|
+
aws logs describe-log-groups \
|
|
379
|
+
--query 'logGroups[].[logGroupName,storedBytes]' \
|
|
380
|
+
--output table
|
|
381
|
+
|
|
382
|
+
# Delete log group
|
|
383
|
+
aws logs delete-log-group --log-group-name /aws/lambda/my-function
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## Part 4: The Nuclear Option - Check Everything
|
|
389
|
+
|
|
390
|
+
### All-Regions Audit Script
|
|
391
|
+
|
|
392
|
+
Create `aws-audit-all-regions.sh`:
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
#!/bin/bash
|
|
396
|
+
|
|
397
|
+
echo "=== AWS RESOURCE AUDIT ==="
|
|
398
|
+
echo ""
|
|
399
|
+
|
|
400
|
+
for region in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do
|
|
401
|
+
echo "🔍 Checking region: $region"
|
|
402
|
+
echo ""
|
|
403
|
+
|
|
404
|
+
# EC2 Instances
|
|
405
|
+
instances=$(aws ec2 describe-instances --region $region \
|
|
406
|
+
--query 'Reservations[].Instances[].[InstanceId,State.Name]' \
|
|
407
|
+
--output text 2>/dev/null)
|
|
408
|
+
if [ ! -z "$instances" ]; then
|
|
409
|
+
echo " EC2 Instances:"
|
|
410
|
+
echo "$instances" | sed 's/^/ /'
|
|
411
|
+
fi
|
|
412
|
+
|
|
413
|
+
# EBS Volumes
|
|
414
|
+
volumes=$(aws ec2 describe-volumes --region $region \
|
|
415
|
+
--query 'Volumes[].[VolumeId,State,Size]' \
|
|
416
|
+
--output text 2>/dev/null)
|
|
417
|
+
if [ ! -z "$volumes" ]; then
|
|
418
|
+
echo " EBS Volumes:"
|
|
419
|
+
echo "$volumes" | sed 's/^/ /'
|
|
420
|
+
fi
|
|
421
|
+
|
|
422
|
+
# Elastic IPs
|
|
423
|
+
eips=$(aws ec2 describe-addresses --region $region \
|
|
424
|
+
--query 'Addresses[].[PublicIp,AssociationId]' \
|
|
425
|
+
--output text 2>/dev/null)
|
|
426
|
+
if [ ! -z "$eips" ]; then
|
|
427
|
+
echo " Elastic IPs:"
|
|
428
|
+
echo "$eips" | sed 's/^/ /'
|
|
429
|
+
fi
|
|
430
|
+
|
|
431
|
+
# NAT Gateways
|
|
432
|
+
nats=$(aws ec2 describe-nat-gateways --region $region \
|
|
433
|
+
--query 'NatGateways[].[NatGatewayId,State]' \
|
|
434
|
+
--output text 2>/dev/null)
|
|
435
|
+
if [ ! -z "$nats" ]; then
|
|
436
|
+
echo " NAT Gateways:"
|
|
437
|
+
echo "$nats" | sed 's/^/ /'
|
|
438
|
+
fi
|
|
439
|
+
|
|
440
|
+
echo ""
|
|
441
|
+
done
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
Run it:
|
|
445
|
+
```bash
|
|
446
|
+
chmod +x aws-audit-all-regions.sh
|
|
447
|
+
./aws-audit-all-regions.sh
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## Part 5: Use AWS Cost Explorer (Web UI)
|
|
453
|
+
|
|
454
|
+
1. Go to: https://console.aws.amazon.com/cost-management/home
|
|
455
|
+
2. Click **Cost Explorer** → **Enable Cost Explorer** (if first time)
|
|
456
|
+
3. Wait 24 hours for data to populate
|
|
457
|
+
4. Use filters to see:
|
|
458
|
+
- **Service** breakdown (what's charging you)
|
|
459
|
+
- **Region** breakdown (where charges come from)
|
|
460
|
+
- **Daily costs** (when did charges start)
|
|
461
|
+
|
|
462
|
+
**Look for:**
|
|
463
|
+
- EC2-Other (EBS volumes)
|
|
464
|
+
- VPC (NAT Gateway, Elastic IPs)
|
|
465
|
+
- RDS
|
|
466
|
+
- S3
|
|
467
|
+
- Data Transfer
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Part 6: Set Up Billing Alerts
|
|
472
|
+
|
|
473
|
+
**Prevent this from happening again:**
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
# Create billing alarm (requires CloudWatch)
|
|
477
|
+
aws cloudwatch put-metric-alarm \
|
|
478
|
+
--alarm-name "BillingAlarm" \
|
|
479
|
+
--alarm-description "Alert when AWS bill exceeds $10" \
|
|
480
|
+
--metric-name EstimatedCharges \
|
|
481
|
+
--namespace AWS/Billing \
|
|
482
|
+
--statistic Maximum \
|
|
483
|
+
--period 21600 \
|
|
484
|
+
--evaluation-periods 1 \
|
|
485
|
+
--threshold 10.0 \
|
|
486
|
+
--comparison-operator GreaterThanThreshold
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
**Better: Use AWS Budgets (Web UI)**
|
|
490
|
+
1. Go to: https://console.aws.amazon.com/billing/home#/budgets
|
|
491
|
+
2. Create Budget
|
|
492
|
+
3. Set threshold (e.g., $10/month)
|
|
493
|
+
4. Add email alert
|
|
494
|
+
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
## Quick Reference: Most Common Commands
|
|
498
|
+
|
|
499
|
+
```bash
|
|
500
|
+
# Check identity
|
|
501
|
+
aws sts get-caller-identity
|
|
502
|
+
|
|
503
|
+
# List EC2 instances
|
|
504
|
+
aws ec2 describe-instances --output table
|
|
505
|
+
|
|
506
|
+
# List EBS volumes (THE MOST COMMON CULPRIT)
|
|
507
|
+
aws ec2 describe-volumes --output table
|
|
508
|
+
|
|
509
|
+
# List Elastic IPs (unattached = charging)
|
|
510
|
+
aws ec2 describe-addresses --output table
|
|
511
|
+
|
|
512
|
+
# List NAT Gateways (EXPENSIVE)
|
|
513
|
+
aws ec2 describe-nat-gateways --output table
|
|
514
|
+
|
|
515
|
+
# List RDS databases
|
|
516
|
+
aws rds describe-db-instances --output table
|
|
517
|
+
|
|
518
|
+
# List S3 buckets
|
|
519
|
+
aws s3 ls
|
|
520
|
+
|
|
521
|
+
# Check all regions
|
|
522
|
+
for region in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do
|
|
523
|
+
echo "Region: $region"
|
|
524
|
+
aws ec2 describe-instances --region $region --output table
|
|
525
|
+
done
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
## Troubleshooting
|
|
531
|
+
|
|
532
|
+
### "Unable to locate credentials"
|
|
533
|
+
```bash
|
|
534
|
+
# Check if credentials exist
|
|
535
|
+
cat ~/.aws/credentials
|
|
536
|
+
|
|
537
|
+
# Reconfigure
|
|
538
|
+
aws configure
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### "Region not found"
|
|
542
|
+
```bash
|
|
543
|
+
# Set default region
|
|
544
|
+
aws configure set region us-east-1
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### "Access Denied" errors
|
|
548
|
+
- Your IAM user might lack permissions
|
|
549
|
+
- Attach `PowerUserAccess` or `AdministratorAccess` policy in IAM console
|
|
550
|
+
|
|
551
|
+
### Still being charged?
|
|
552
|
+
1. **Wait 24-48 hours** - AWS billing has delay
|
|
553
|
+
2. **Check Cost Explorer** - see exact service charging you
|
|
554
|
+
3. **Check ALL regions** - use the audit script above
|
|
555
|
+
4. **Check Route 53** - hosted zones cost $0.50/month each
|
|
556
|
+
5. **Check CloudFront** - distributions can accumulate charges
|
|
557
|
+
6. **Contact AWS Support** - they can help identify charges
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
## Prevention Checklist
|
|
562
|
+
|
|
563
|
+
Before leaving AWS for the day:
|
|
564
|
+
|
|
565
|
+
- [ ] Stop or terminate ALL EC2 instances
|
|
566
|
+
- [ ] Delete ALL unattached EBS volumes
|
|
567
|
+
- [ ] Release ALL unused Elastic IPs
|
|
568
|
+
- [ ] Delete NAT Gateways if not needed
|
|
569
|
+
- [ ] Delete or stop RDS instances
|
|
570
|
+
- [ ] Check ALL regions (not just default)
|
|
571
|
+
- [ ] Set up billing alerts
|
|
572
|
+
- [ ] Use AWS Free Tier Dashboard to monitor usage
|
|
573
|
+
|
|
574
|
+
**Rule of thumb:** If you're not actively using AWS, your monthly bill should be $0-2 (maybe Route 53 or minimal S3).
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## Useful Links
|
|
579
|
+
|
|
580
|
+
- AWS Cost Explorer: https://console.aws.amazon.com/cost-management/home
|
|
581
|
+
- AWS Free Tier: https://console.aws.amazon.com/billing/home#/freetier
|
|
582
|
+
- AWS Budgets: https://console.aws.amazon.com/billing/home#/budgets
|
|
583
|
+
- IAM Console: https://console.aws.amazon.com/iam
|
|
584
|
+
- Support Center: https://console.aws.amazon.com/support/home
|
|
585
|
+
|
|
586
|
+
---
|
|
587
|
+
|
|
588
|
+
**Good luck, detective! 🕵️**
|