Skip to content

Commit 0484b85

Browse files
authored
Merge pull request #29 from kosty-cloud/fix/profile-session-comprehensive-scanner
v1.6.4 - Profile authentication fix Fixed profile authentication bug where audits used wrong AWS account. New feature: aws_profile config option to reference AWS CLI profiles Bug fix: Profile sessions now correctly used across all services and commands Breaking changes: None Upgrade: pip install --upgrade kosty
2 parents b924f1a + d229141 commit 0484b85

6 files changed

Lines changed: 134 additions & 63 deletions

File tree

README.md

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ AWS costs and security risks can spiral out of control quickly. Kosty helps you:
5555
- 🔐 **Detect** security misconfigurations and compliance issues
5656
-**Optimize** with prioritized recommendations by financial impact
5757
- 🏢 **Scale** across entire AWS Organizations with parallel processing
58-
- 📊 **Track** ROI with comprehensive cost reporting
58+
- 📊 Track ROI with detailed cost reporting
5959

6060

6161
## 🎯 Quick Start
@@ -491,8 +491,18 @@ default:
491491
profiles:
492492
customer01:
493493
regions: [us-east-1]
494+
# Option 1: AssumeRole (recommended for multi-account)
494495
role_arn: "arn:aws:iam::123456789012:role/MyRole"
495496
mfa_serial: "arn:aws:iam::123456789012:mfa/device"
497+
498+
customer02:
499+
regions: [eu-west-1]
500+
# Option 2: AWS CLI profile (for local development)
501+
aws_profile: "customer02-prod"
502+
503+
customer03:
504+
regions: [ap-southeast-1]
505+
# Option 3: Default credentials (env vars, instance role)
496506
```
497507

498508
See [Configuration Guide](docs/CONFIGURATION.md) for complete documentation.
@@ -514,13 +524,13 @@ See [Configuration Guide](docs/CONFIGURATION.md) for complete documentation.
514524

515525
## 🤝 Contributing
516526

517-
We welcome contributions! Here's how you can help:
527+
We welcome contributions:
518528

519-
1. **🐛 Report Issues** - Found a bug? [Open an issue](https://github.com/kosty-cloud/kosty/issues)
520-
2. **💡 Feature Requests** - Have an idea? [Start a discussion](https://github.com/kosty-cloud/kosty/discussions)
521-
3. **🔧 Add Services** - Implement new AWS service checks
522-
4. **📖 Improve Docs** - Help make documentation better
523-
5. **Star the Repo** - Show your support!
529+
1. **Report Issues** - Found a bug? [Open an issue](https://github.com/kosty-cloud/kosty/issues)
530+
2. **Feature Requests** - Have an idea? [Start a discussion](https://github.com/kosty-cloud/kosty/discussions)
531+
3. **Add Services** - Implement new AWS service checks
532+
4. **Improve Docs** - Help make documentation better
533+
5. **Star the Repo** - Show your support!
524534

525535
### Adding New Services
526536

@@ -549,7 +559,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
549559

550560
## 💼 Professional Services
551561

552-
Kosty is free and open-source for self-service optimization. For teams who prefer expert guidance to maximize results and ensure safe implementation, I offer professional audits.
562+
Kosty is free and open-source. For teams who want expert guidance to maximize results and safe implementation, I offer professional audits.
553563

554564
### What's Included
555565

docs/CONFIGURATION.md

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ kosty audit --profile production
120120
| `cross_account_role` | string | Role name for cross-account | `OrganizationAccountAccessRole` |
121121
| `org_admin_account_id` | string | Org admin account ID | `null` |
122122
| `role_arn` | string | Role ARN to assume | `null` |
123+
| `aws_profile` | string | AWS CLI profile name | `null` |
123124
| `mfa_serial` | string | MFA device ARN | `null` |
124125
| `duration_seconds` | integer | AssumeRole session duration | `3600` |
125126

@@ -334,37 +335,70 @@ profiles:
334335

335336
## AWS Authentication
336337

337-
### Default Credentials
338+
Kosty supports three authentication methods (in priority order):
338339

339-
If no `role_arn` is configured, Kosty uses default AWS credentials:
340+
### 1. AssumeRole (Recommended for Multi-Account)
341+
342+
Best for managing multiple customer accounts securely:
340343

341344
```yaml
342-
default:
343-
regions:
344-
- us-east-1
345-
# No role_arn = uses default credentials
345+
profiles:
346+
customer01:
347+
role_arn: "arn:aws:iam::123456789012:role/MyRole"
348+
duration_seconds: 3600 # 1 hour
346349
```
347350

348-
Kosty will use credentials from:
349-
1. Environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`)
350-
2. `~/.aws/credentials`
351-
3. `~/.aws/config`
352-
4. IAM role (if running on EC2/Lambda)
351+
```bash
352+
kosty audit --profile customer01
353+
# → Assumes role without MFA prompt
354+
```
353355

354-
### AssumeRole (without MFA)
356+
### 2. AWS CLI Profile
357+
358+
Best for local development with multiple AWS accounts:
355359

356360
```yaml
357361
profiles:
358362
customer01:
359-
role_arn: "arn:aws:iam::123456789012:role/MyRole"
360-
duration_seconds: 3600 # 1 hour
363+
aws_profile: "customer01-prod" # References ~/.aws/credentials
364+
regions:
365+
- us-east-1
361366
```
362367

363368
```bash
364369
kosty audit --profile customer01
365-
# → Assumes role without MFA prompt
370+
# → Uses credentials from ~/.aws/credentials profile "customer01-prod"
371+
```
372+
373+
**Setup AWS CLI profile:**
374+
```bash
375+
# Configure profile
376+
aws configure --profile customer01-prod
377+
378+
# Or edit ~/.aws/credentials
379+
[customer01-prod]
380+
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
381+
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
382+
```
383+
384+
### 3. Default Credentials
385+
386+
Best for CI/CD pipelines or EC2 instances with IAM roles:
387+
388+
```yaml
389+
profiles:
390+
customer01:
391+
regions:
392+
- us-east-1
393+
# No role_arn or aws_profile = uses default credentials
366394
```
367395

396+
Kosty will use credentials from:
397+
1. Environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`)
398+
2. `~/.aws/credentials` (default profile)
399+
3. `~/.aws/config` (default profile)
400+
4. IAM role (if running on EC2/Lambda/ECS)
401+
368402
### AssumeRole with MFA
369403

370404
```yaml

kosty.yaml.example

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ default:
6060

6161
# Profile definitions
6262
profiles:
63-
# Customer 1 profile
63+
# Customer 1 profile - Using AssumeRole (recommended for multi-account)
6464
customer01:
6565
regions:
6666
- us-east-1
@@ -75,18 +75,25 @@ profiles:
7575
ec2_cpu: 15
7676
rds_cpu: 15
7777

78-
# Customer 2 profile
78+
# Customer 2 profile - Using AWS CLI profile (for local development)
7979
customer02:
8080
regions:
8181
- eu-west-1
8282
max_workers: 8
83-
role_arn: "arn:aws:iam::987654321098:role/KostyAuditRole"
83+
aws_profile: "customer02-prod" # References ~/.aws/credentials profile
8484
exclude:
8585
services:
8686
- "route53"
8787
tags:
8888
- key: "DoNotAudit"
8989

90+
# Customer 3 profile - Using default credentials (env vars, instance role)
91+
customer03:
92+
regions:
93+
- ap-southeast-1
94+
max_workers: 5
95+
# No role_arn or aws_profile = uses default credentials
96+
9097
# Production environment
9198
production:
9299
regions:

kosty/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
__version__ = "1.6.3"
1+
__version__ = "1.6.4"
22

kosty/core/config.py

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
'org_admin_account_id': None,
3636
'save_to': None,
3737
'role_arn': None,
38+
'aws_profile': None,
3839
'mfa_serial': None,
3940
'duration_seconds': 3600
4041
}
@@ -272,42 +273,61 @@ def get_all_profiles(self) -> List[str]:
272273
def get_aws_session(self) -> boto3.Session:
273274
"""Create AWS session with AssumeRole/MFA if configured"""
274275
role_arn = self.get('role_arn')
276+
aws_profile = self.get('aws_profile')
275277
mfa_serial = self.get('mfa_serial')
276278
duration = self.get('duration_seconds', 3600)
277279

278-
if not role_arn:
279-
return boto3.Session()
280-
281-
mfa_token = None
282-
if mfa_serial:
283-
mfa_token = input(f"🔐 Enter MFA token for {mfa_serial}: ")
284-
285-
sts = boto3.client('sts')
286-
287-
assume_role_params = {
288-
'RoleArn': role_arn,
289-
'RoleSessionName': f'kosty-{self.profile}',
290-
'DurationSeconds': duration
291-
}
292-
293-
if mfa_serial and mfa_token:
294-
assume_role_params['SerialNumber'] = mfa_serial
295-
assume_role_params['TokenCode'] = mfa_token
296-
297-
try:
298-
response = sts.assume_role(**assume_role_params)
280+
# Priority: role_arn > aws_profile > default credentials
281+
if role_arn:
282+
# AssumeRole flow
283+
mfa_token = None
284+
if mfa_serial:
285+
mfa_token = input(f"🔐 Enter MFA token for {mfa_serial}: ")
299286

300-
return boto3.Session(
301-
aws_access_key_id=response['Credentials']['AccessKeyId'],
302-
aws_secret_access_key=response['Credentials']['SecretAccessKey'],
303-
aws_session_token=response['Credentials']['SessionToken']
304-
)
305-
except Exception as e:
306-
config_file = self._find_config_file() or 'No config file'
307-
print(f"\nError: Failed to assume role")
308-
print(f" Profile: {self.profile}")
309-
print(f" Config: {config_file}")
310-
print(f" Role ARN: {role_arn}")
311-
print(f" Reason: {e}")
312-
print("\nCannot proceed without valid role access. Aborting.\n")
313-
raise SystemExit(1)
287+
sts = boto3.client('sts')
288+
289+
assume_role_params = {
290+
'RoleArn': role_arn,
291+
'RoleSessionName': f'kosty-{self.profile}',
292+
'DurationSeconds': duration
293+
}
294+
295+
if mfa_serial and mfa_token:
296+
assume_role_params['SerialNumber'] = mfa_serial
297+
assume_role_params['TokenCode'] = mfa_token
298+
299+
try:
300+
response = sts.assume_role(**assume_role_params)
301+
302+
return boto3.Session(
303+
aws_access_key_id=response['Credentials']['AccessKeyId'],
304+
aws_secret_access_key=response['Credentials']['SecretAccessKey'],
305+
aws_session_token=response['Credentials']['SessionToken']
306+
)
307+
except Exception as e:
308+
config_file = self._find_config_file() or 'No config file'
309+
print(f"\nError: Failed to assume role")
310+
print(f" Profile: {self.profile}")
311+
print(f" Config: {config_file}")
312+
print(f" Role ARN: {role_arn}")
313+
print(f" Reason: {e}")
314+
print("\nCannot proceed without valid role access. Aborting.\n")
315+
raise SystemExit(1)
316+
317+
elif aws_profile:
318+
# Use AWS CLI profile
319+
try:
320+
return boto3.Session(profile_name=aws_profile)
321+
except Exception as e:
322+
config_file = self._find_config_file() or 'No config file'
323+
print(f"\nError: Failed to use AWS profile")
324+
print(f" Profile: {self.profile}")
325+
print(f" Config: {config_file}")
326+
print(f" AWS Profile: {aws_profile}")
327+
print(f" Reason: {e}")
328+
print(f"\nMake sure '{aws_profile}' exists in ~/.aws/credentials or ~/.aws/config\n")
329+
raise SystemExit(1)
330+
331+
else:
332+
# Use default credentials (env vars, instance role, default profile)
333+
return boto3.Session()

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setup(
77
name='kosty',
8-
version='1.6.3',
8+
version='1.6.4',
99
author='Yassir Kachri',
1010
author_email='yassir@kosty.cloud',
1111
description='AWS Cost Optimization & Security Audit CLI Tool - Identify cost waste, security vulnerabilities, and compliance issues across 16 core AWS services',

0 commit comments

Comments
 (0)