Skip to content

Commit 48f8cd9

Browse files
committed
refactor code
1 parent 8e38d8a commit 48f8cd9

21 files changed

+878
-657
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ crudActions/
1111
finalUserPolicies/
1212
userPolicies*/
1313
presentPolicies*/
14-
logs*/
14+
logs*/

CONTRIBUTING.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Contributing to AWSZeroTrustPolicy
2+
23
We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's:
34

45
- Reporting a bug
@@ -8,9 +9,11 @@ We love your input! We want to make contributing to this project as easy and tra
89
- Becoming a maintainer
910

1011
## We Develop with Github
12+
1113
We use github to host code, to track issues and feature requests, as well as accept pull requests.
1214

1315
## We Use [Github Flow](https://docs.github.com/en/get-started/quickstart/github-flow), So All Code Changes Happen Through Pull Requests
16+
1417
Pull requests are the best way to propose changes to the codebase (we use [Github Flow](https://docs.github.com/en/get-started/quickstart/github-flow)). We actively welcome your pull requests:
1518

1619
1. Fork the repo and create your branch from `master`.
@@ -21,14 +24,15 @@ Pull requests are the best way to propose changes to the codebase (we use [Githu
2124
6. Issue that pull request!
2225

2326
## Any contributions you make will be under the MIT Software License
27+
2428
In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers the project. Feel free to contact the maintainers if that's a concern.
2529

2630
## Report bugs using Github's [issues](https://github.com/CloudDefenseAI/AWSZeroTrustPolicy/issues)
31+
2732
We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/CloudDefenseAI/AWSZeroTrustPolicy/issues/new); it's that easy!
2833

2934
## Write bug reports with detail, background, and sample code
3035

31-
3236
**Great Bug Reports** tend to have:
3337

3438
- A quick summary and/or background
@@ -39,14 +43,15 @@ We use GitHub issues to track public bugs. Report a bug by [opening a new issue]
3943
- What actually happens
4044
- Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)
4145

42-
People *love* thorough bug reports. I'm not even kidding.
43-
46+
People _love_ thorough bug reports. I'm not even kidding.
4447

45-
* 2 spaces for indentation rather than tabs
46-
* You can try running `npm run lint` for style unification
48+
- 2 spaces for indentation rather than tabs
49+
- You can try running `npm run lint` for style unification
4750

4851
## License
52+
4953
By contributing, you agree that your contributions will be licensed under its MIT License.
5054

5155
## References
56+
5257
This document was adapted from the open-source contribution guidelines for [Facebook's Draft](https://github.com/facebook/draft-js/blob/a9316a723f9e918afde44dea68b5f9f39b7d9b00/CONTRIBUTING.md)

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ RUN apk add --no-cache python3-dev gcc musl-dev libffi-dev libpq-dev openssl-dev
66
WORKDIR /app
77
COPY requirements.txt ./
88
RUN pip install --no-cache-dir -r requirements.txt
9+
910
COPY . .
1011
EXPOSE 8000
1112
CMD ["sh", "-c", "redis-server & uvicorn app:app --reload --host 0.0.0.0"]

LICENSE

Lines changed: 183 additions & 183 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ If you want to help and wish to contribute, please review our contribution guide
6969

7070
## License
7171

72-
This project is released under the [Apache-2.0 License]([url](https://github.com/CloudDefenseAI/AWSZeroTrustPolicy/blob/master/LICENSE)).
72+
This project is released under the [Apache-2.0 License](<[url](https://github.com/CloudDefenseAI/AWSZeroTrustPolicy/blob/master/LICENSE)>).
7373

7474
## Disclaimer:
7575

app.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,30 @@
77

88
app = FastAPI()
99

10+
1011
@app.post("/run")
1112
def run_script(script: Script):
1213
print(f"Timestamp: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
1314
print("Payload:")
1415
print(json.dumps(script.dict(), indent=4))
1516

1617
try:
17-
resp = runner(script.accountType, script.accessKey, script.secretKey, script.accountId, script.days
18-
, script.bucketData, script.roleArn, script.externalId)
18+
resp = runner(
19+
script.accountType,
20+
script.accessKey,
21+
script.secretKey,
22+
script.accountId,
23+
script.days,
24+
script.bucketData,
25+
script.roleArn,
26+
script.externalId,
27+
)
1928
except Exception as e:
2029
raise HTTPException(status_code=500, detail=str(e))
2130

22-
return {"accountId": resp['accountId'], "generatedPolicies": resp['generatedPolicies'], "consolidatedPolicies": resp['consolidatedPolicies'], "excessivePolicies": resp['excessivePolicies']}
23-
31+
return {
32+
"accountId": resp["accountId"],
33+
"generatedPolicies": resp["generatedPolicies"],
34+
"consolidatedPolicies": resp["consolidatedPolicies"],
35+
"excessivePolicies": resp["excessivePolicies"],
36+
}

aws/awsOps.py

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,100 +4,110 @@
44
from botocore.exceptions import ClientError, NoCredentialsError, BotoCoreError
55
from fastapi import HTTPException
66

7+
78
class AWSOperations:
89
def connect_to_iam_with_assumed_role(self, aws_credentials):
910
# Create a new session with the temporary credentials
1011
session = boto3.Session(
1112
aws_access_key_id=aws_credentials.access_key,
1213
aws_secret_access_key=aws_credentials.secret_key,
13-
aws_session_token=aws_credentials.token
14+
aws_session_token=aws_credentials.token,
1415
)
1516
# Use the new session to connect to IAM
16-
iam_client = session.client('iam')
17+
iam_client = session.client("iam")
1718
return iam_client
1819

1920
def get_iam_connection(self):
2021
try:
2122
with open("config.json", "r") as f:
2223
data = json.loads(f.read())
23-
if data['accountType'] == "CloudFormation":
24+
if data["accountType"] == "CloudFormation":
2425
aws_credentials = self.get_assume_role_credentials(data)
2526
iam_client = self.connect_to_iam_with_assumed_role(aws_credentials)
26-
elif data['accountType'] == "Credential":
27-
iam_client = self.connect("iam", data['aws_access_key_id'], data['aws_secret_access_key'])
27+
elif data["accountType"] == "Credential":
28+
iam_client = self.connect(
29+
"iam", data["aws_access_key_id"], data["aws_secret_access_key"]
30+
)
2831
return iam_client
2932
except (FileNotFoundError, json.JSONDecodeError) as e:
30-
raise HTTPException(status_code=500, detail=f"Error reading or parsing config.json: {e}")
33+
raise HTTPException(
34+
status_code=500, detail=f"Error reading or parsing config.json: {e}"
35+
)
3136

3237
except (ClientError, NoCredentialsError, BotoCoreError) as e:
3338
raise HTTPException(status_code=500, detail=f"Error connecting to IAM: {e}")
3439

35-
36-
def connect(self,serviceName,aws_access_key_id,aws_secret_access_key):
37-
s3Client = boto3.client(serviceName,aws_access_key_id=aws_access_key_id,aws_secret_access_key=aws_secret_access_key)
40+
def connect(self, serviceName, aws_access_key_id, aws_secret_access_key):
41+
s3Client = boto3.client(
42+
serviceName,
43+
aws_access_key_id=aws_access_key_id,
44+
aws_secret_access_key=aws_secret_access_key,
45+
)
3846
return s3Client
3947

40-
def connect_to_s3_with_assumed_role(self,aws_credentials):
48+
def connect_to_s3_with_assumed_role(self, aws_credentials):
4149
# Create a new session with the temporary credentials
4250
session = boto3.Session(
4351
aws_access_key_id=aws_credentials.access_key,
4452
aws_secret_access_key=aws_credentials.secret_key,
45-
aws_session_token=aws_credentials.token
53+
aws_session_token=aws_credentials.token,
4654
)
4755
# Use the new session to connect to S3
48-
s3_client = session.client('s3')
56+
s3_client = session.client("s3")
4957
return s3_client
5058

5159
def getConnection(self):
5260
try:
5361
with open("config.json", "r") as f:
5462
data = json.loads(f.read())
55-
if data['accountType'] == "CloudFormation":
63+
if data["accountType"] == "CloudFormation":
5664
aws_credentials = self.get_assume_role_credentials(data)
5765
s3_client = self.connect_to_s3_with_assumed_role(aws_credentials)
58-
elif data['accountType'] == "Credential":
59-
s3_client = self.connect("s3", data['aws_access_key_id'], data['aws_secret_access_key'])
66+
elif data["accountType"] == "Credential":
67+
s3_client = self.connect(
68+
"s3", data["aws_access_key_id"], data["aws_secret_access_key"]
69+
)
6070
return s3_client
6171
except (FileNotFoundError, json.JSONDecodeError) as e:
62-
raise HTTPException(status_code=500, detail=f"Error reading or parsing config.json: {e}")
72+
raise HTTPException(
73+
status_code=500, detail=f"Error reading or parsing config.json: {e}"
74+
)
6375
except (ClientError, NoCredentialsError, BotoCoreError) as e:
6476
raise HTTPException(status_code=500, detail=f"Error connecting to S3: {e}")
6577

6678
def get_assume_role_credentials(self, account):
6779
try:
68-
# Create an STS client with the IAM user's access and secret keys
80+
# Create an STS client with the IAM user's access and secret keys
6981
sts_client = boto3.client(
70-
'sts',
71-
aws_access_key_id=account['aws_access_key_id'],
72-
aws_secret_access_key=account['aws_secret_access_key']
82+
"sts",
83+
aws_access_key_id=account["aws_access_key_id"],
84+
aws_secret_access_key=account["aws_secret_access_key"],
7385
)
7486

7587
# Assume the IAM role
7688
response = sts_client.assume_role(
77-
RoleArn=account['role_arn'],
78-
RoleSessionName='Assume_Role_Session',
89+
RoleArn=account["role_arn"],
90+
RoleSessionName="Assume_Role_Session",
7991
DurationSeconds=43200,
80-
ExternalId=account['externalid']
92+
ExternalId=account["externalid"],
8193
)
8294

8395
# Extract the temporary credentials
84-
creds = response['Credentials']
96+
creds = response["Credentials"]
8597
session_credentials = boto3.Session(
86-
aws_access_key_id=creds['AccessKeyId'],
87-
aws_secret_access_key=creds['SecretAccessKey'],
88-
aws_session_token=creds['SessionToken']
98+
aws_access_key_id=creds["AccessKeyId"],
99+
aws_secret_access_key=creds["SecretAccessKey"],
100+
aws_session_token=creds["SessionToken"],
89101
).get_credentials()
90102

91103
# Create an AwsCredentials object with the temporary credentials
92104
aws_credentials = Credentials(
93105
access_key=session_credentials.access_key,
94106
secret_key=session_credentials.secret_key,
95-
token=session_credentials.token
107+
token=session_credentials.token,
96108
)
97109

98110
return aws_credentials
99111

100112
except (ClientError, NoCredentialsError, BotoCoreError) as e:
101113
raise HTTPException(status_code=500, detail=f"Error assuming role: {e}")
102-
103-

aws/comparePolicies.py

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
# hdServices = ['a4b','account','amplify','apprunner','appsync','aps','billing','codebuild','codecommit','connect','databrew','eks','emrcontainers','forecast','frauddetector','fsx','gamelift','greengrassv2','health','iot','iotanalytics','iotevents','iotfleethub','iotthingsgraph','kafka','kendra','kinesisvideo','lakeformation','licensemanager','lookoutvision','macie','managedblockchain','marketplacecatalog','mediaconnect','mediaconvert','medialive','mediapackage','mediapackage-vod','mediastore','mediastore-data','mediatailor','meteringmarketplace','migrationhub-config','mobile','mq','neptune','networkmanager','outposts','personalize','pinpoint','pinpoint-email','pinpoint-sms-voice','polly','pricing','qldb','quicksight','ram','rds-data','robomaker','route53resolver','sagemaker','sagemaker-a2i-runtime','sagemaker-edge','sagemaker-featurestore-runtime','sagemaker-runtime','savingsplans','schemas','secretsmanager','securityhub','serverlessrepo','servicecatalog','servicecatalog-appregistry','servicequotas','sesv2','shield','signer','sms','snowball','snowball-edge','sso','sso-oidc','ssm','stepfunctions','storagegateway','synthetics','textract','transcribe','transfer','translate','waf-regional','wafv2','worklink','workmail','workmailmessageflow','workspaces','xray','autoscaling','iam','ec2','s3','rds','elasticache','elasticbeanstalk','elasticloadbalancing','elasticmapreduce','cloudfront','cloudtrail','cloudwatch','cloudwatchevents','cloudwatchlogs','config','datapipeline','directconnect','dynamodb','ecr','ecs','elasticfilesystem','elastictranscoder','glacier','kinesis','kms','lambda','opsworks','redshift','route53','route53domains','sdb','ses','sns','sqs','storagegateway','sts','support','swf','waf','workspaces','xray']
1515
# hdServices.extend(['acm','acm-pca','alexaforbusiness','amplifybackend','appconfig','appflow','appintegrations','appmesh','appstream','appsync','athena','auditmanager','autoscaling-plans','backup','batch','braket','budgets','ce','chime','cloud9','clouddirectory','cloudformation','cloudhsm','cloudhsmv2','cloudsearch','cloudsearchdomain','cloudtrail','cloudwatch','cloudwatchevents','cloudwatchlogs','codeartifact','codebuild','codecommit','codedeploy','codeguru-reviewer','codeguru-reviewer-runtime','codeguru-profiler','codeguru-profiler-runtime','codepipeline','codestar','codestar-connections','codestar-notifications','cognito-identity','cognito-idp','cognito-sync','comprehend','comprehendmedical','compute-optimizer','connect','connect-contact-lens','connectparticipant','cur','customer-profiles','dataexchange','datapipeline','datasync','dax','detective','devicefarm','devops-guru','directconnect','discovery','dlm','dms','docdb','ds','dynamodb','dynamodbstreams','ec2','ec2-instance-connect','ecr','ecr-public','ecs','eks','elastic-inference','elasticache','elasticbeanstalk','elasticfilesystem','elasticloadbalancing','elasticloadbalancingv2','elasticmapreduce','elastictranscoder','email','es','events','firehose','fms','forecast','forecastquery','frauddetector','fsx','gamelift','glacier','globalaccelerator','glue','greengrass','greengrassv2','groundstation','guardduty','health','healthlake','honeycode','iam','identitystore','imagebuilder','importexport','inspector','iot','iot-data','iot-jobs-data','iot1click-devices','iot1click-projects','iotanalytics','iotdeviceadvisor','iotevents','iotevents-data','iotfleethub','iotsecuretunneling','iotthingsgraph','iotwireless','ivs','kafka','kendra','kinesis','kinesis-video-archived-media','kinesis-video-media','kinesis-video-signaling','kinesisvideo','kinesisanalytics','kinesisanalyticsv2','kinesisvideoarchivedmedia','kinesis'])
1616

17+
1718
def create_services_list(actions_data):
1819
for action in actions_data:
1920
action_data = json.loads(action)
2021
event_source = action_data["eventSource"]
2122
service = event_source.split(".")[0]
2223
services[service].add(service)
2324

25+
2426
def create_service_actions_cache(services):
2527
service_actions_cache = {}
2628

@@ -37,19 +39,25 @@ def create_service_actions_cache(services):
3739

3840
return service_actions_cache
3941

42+
4043
def write_service_actions_cache_to_file(service_actions_cache, file_path):
41-
with open(file_path, 'w') as f:
44+
with open(file_path, "w") as f:
4245
json.dump(service_actions_cache, f, indent=2)
4346

47+
4448
def load_policy(filepath):
4549
with open(filepath, "r") as f:
4650
policy = json.load(f)
4751
return policy
4852

53+
4954
def is_valid_action(action):
50-
return re.match(r'^[a-zA-Z0-9_]+:(\*|[a-zA-Z0-9_\*]+)$', action)
55+
return re.match(r"^[a-zA-Z0-9_]+:(\*|[a-zA-Z0-9_\*]+)$", action)
5156

52-
def compare_policy_worker(present_policy_filepath, user_policy_filepath, output_filepath):
57+
58+
def compare_policy_worker(
59+
present_policy_filepath, user_policy_filepath, output_filepath
60+
):
5361
print(f"Started thread for {user_policy_filepath}")
5462

5563
current_policy = load_policy(present_policy_filepath)
@@ -59,7 +67,10 @@ def compare_policy_worker(present_policy_filepath, user_policy_filepath, output_
5967

6068
with open(output_filepath, "w") as f_write:
6169
f_write.write(json.dumps(excessive_permissions, indent=2))
62-
print(f"Generated excessive policy for {os.path.basename(user_policy_filepath)}")
70+
print(
71+
f"Generated excessive policy for {os.path.basename(user_policy_filepath)}"
72+
)
73+
6374

6475
# def expand_wildcard_actions(actions_list, service_actions_cache=None):
6576
# if service_actions_cache is None:
@@ -84,6 +95,7 @@ def compare_policy_worker(present_policy_filepath, user_policy_filepath, output_
8495

8596
# return expanded_actions
8697

98+
8799
def expand_wildcard_actions(actions_list, service_actions_cache=None):
88100
if service_actions_cache is None:
89101
with open("service_actions_cache.json", "r") as f:
@@ -98,35 +110,43 @@ def expand_wildcard_actions(actions_list, service_actions_cache=None):
98110
if is_valid_action(action):
99111
service, action_name = action.split(":")
100112
if "*" in action_name:
101-
expanded_actions.extend([f"{a}" for a in service_actions_cache.get(service, []) if action_name.replace("*", "") in a])
113+
expanded_actions.extend(
114+
[
115+
f"{a}"
116+
for a in service_actions_cache.get(service, [])
117+
if action_name.replace("*", "") in a
118+
]
119+
)
102120
else:
103121
expanded_actions.append(action)
104122

105-
elif action == '*':
123+
elif action == "*":
106124
for service in service_actions_cache:
107-
expanded_actions.extend([f"{a}" for a in service_actions_cache[service]])
125+
expanded_actions.extend(
126+
[f"{a}" for a in service_actions_cache[service]]
127+
)
108128

109129
return expanded_actions
110130

131+
111132
def compare_policy(current_policy, generated_policy):
112-
excessive_permissions = {
113-
"Version": "2012-10-17",
114-
"Statement": []
115-
}
133+
excessive_permissions = {"Version": "2012-10-17", "Statement": []}
116134

117135
for current_statement in current_policy["Statement"]:
118136
excessive_statement = {
119137
"Effect": current_statement["Effect"],
120138
"Action": [],
121-
"Resource": current_statement["Resource"]
139+
"Resource": current_statement["Resource"],
122140
}
123141

124142
current_actions_expanded = expand_wildcard_actions(current_statement["Action"])
125143

126144
for action in current_actions_expanded:
127145
action_in_generated = False
128146
for generated_statement in generated_policy["Statement"]:
129-
generated_actions_expanded = expand_wildcard_actions(generated_statement["Action"])
147+
generated_actions_expanded = expand_wildcard_actions(
148+
generated_statement["Action"]
149+
)
130150

131151
# Check if the action and resource match in both policies
132152
if action in generated_actions_expanded:
@@ -145,14 +165,17 @@ def compare_policy(current_policy, generated_policy):
145165

146166
return excessive_permissions
147167

168+
148169
def compare_policies():
149170
crudKeys = crudConnection.get_all_keys()
150171
for user_arn in crudKeys:
151172
actions_data = crudConnection.get_list_items(user_arn)
152173
create_services_list(actions_data)
153174

154175
service_actions_cache = create_service_actions_cache(services)
155-
write_service_actions_cache_to_file(service_actions_cache, 'service_actions_cache.json')
176+
write_service_actions_cache_to_file(
177+
service_actions_cache, "service_actions_cache.json"
178+
)
156179
print("Service actions cache created successfully.")
157180

158181
# present_policies_dir = "presentPolicies"

0 commit comments

Comments
 (0)