-
Notifications
You must be signed in to change notification settings - Fork 7
/
apotheosis
172 lines (157 loc) · 5.92 KB
/
apotheosis
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import sys
import argparse
from select import select
from oauth2client.client import GoogleCredentials
import oauth2client
from googleapiclient import discovery
from termcolor import colored
# to use these change the values,
# and then run sudo `python setup.py install` to reinstall with the new values
default_resource = ""
default_role = ""
default_member = ""
default_duration = 300
default_service_account = ""
MAX_DURATION = 21000 #the highest value allowed by the API
parser = argparse.ArgumentParser(description="Google Cloud Platform Security Tool")
parser.add_argument(
"--member",
"-m",
default=default_member,
help="Entity to assign the permissions to.",
)
parser.add_argument(
"--role", "-r", default=default_role, help="Role to assign to the member"
)
parser.add_argument(
"--resource",
"-res",
default=default_resource,
help="Resource to assign the permissions on.",
)
parser.add_argument(
"--duration",
"-d",
default=default_duration,
help="Amount of time before revoking permissions. Maximum is 21000 seconds.",
)
parser.add_argument(
"--serviceAccount",
"-sa",
default=default_service_account,
help="The service account that will grant permissions.",
)
args = parser.parse_args()
def get_token(serviceAccount):
try:
creds = GoogleCredentials.get_application_default()
except Exception as e:
print("Error getting application default credentials.")
sys.exit()
service = discovery.build("iamcredentials", "v1", credentials=creds)
scope = [
"https://www.googleapis.com/auth/iam",
"https://www.googleapis.com/auth/cloud-platform",
]
serviceAccount = serviceAccount
name = "projects/-/serviceAccounts/" + serviceAccount
req = (
service.projects()
.serviceAccounts()
.generateAccessToken(name=name, body={"scope": scope})
)
res = req.execute()
return res["accessToken"]
def add_role(role, member, resource, serviceAccount):
creds = oauth2client.client.AccessTokenCredentials(
get_token(serviceAccount), "apotheosis"
)
service = discovery.build("cloudresourcemanager", "v1", credentials=creds)
if str.isdigit(args.resource): # given an organization id
resource = "organizations/" + resource
attr = getattr(service, "organizations")()
elif "folder" in args.resource:
service = discovery.build("cloudresourcemanager", "v2", credentials=creds)
resource = "folders/" + resource.split(":")[1]
attr = getattr(service, "folders")()
else: # given a project or lower
attr = getattr(service, "projects")()
# first get the policy
request = attr.getIamPolicy(resource=resource, body={})
policy = request.execute()
# then modify it
policy_with_addition = modify_policy_add_member(policy, role, member)
if policy_with_addition.get("version"):
del policy_with_addition["version"]
if policy_with_addition.get("etag"):
del policy_with_addition["etag"]
add_request = attr.setIamPolicy(
resource=resource, body={"policy": policy_with_addition}
)
add_request.execute()
print colored("Added ", "green") + colored(args.role, "yellow") + " to " + colored(
args.member, "cyan"
) + " for " + str(args.duration) + " seconds"
remove_role(policy_with_addition, role, member, resource, creds)
return True
def remove_role(policy, role, member, resource, creds):
service = discovery.build("cloudresourcemanager", "v1", credentials=creds)
if str.isdigit(args.resource): # given an organization id
attr = getattr(service, "organizations")()
elif "folder" in args.resource:
service = discovery.build("cloudresourcemanager", "v2", credentials=creds)
resource = "folders/" + args.resource.split(":")[1]
attr = getattr(service, "folders")()
else: # given a project or lower
attr = getattr(service, "projects")()
if float(args.duration) > MAX_DURATION:
args.duration = MAX_DURATION
print "Duration reduced to the maximum"
select([sys.stdin], [], [], float(args.duration))#TODO revoke on SIGINT
policy_with_removal = modify_policy_remove_member(policy, role, member)
if policy_with_removal.get("version"):
del policy_with_removal["version"]
if policy_with_removal.get("etag"):
del policy_with_removal["etag"]
try:
if not str.isdigit(args.resource):
remove_request = attr.setIamPolicy(
resource=resource, body={"policy": policy_with_removal}
)
else:
remove_request = attr.setIamPolicy(
resource=resource, body={"policy": policy_with_removal}
)
remove_request.execute()
except Exception as e:
print e
return
print colored("Removed ", "green") + colored(
args.role, "yellow"
) + " from " + colored(args.member, "cyan")
return
def modify_policy_add_member(policy, role, member):
try:
binding = next(b for b in policy["bindings"] if b["role"] == role)
binding["members"].append(member)
except:
policy["bindings"].append({u"role": role, u"members": [member]})
return policy
def modify_policy_remove_member(policy, role, member):
for binding in policy["bindings"]:
if binding["role"] == role:
while member in binding["members"]:
del binding["members"][(binding["members"].index(member))]
return policy
def get_current_user():
res = subprocess.check_output(
['gcloud auth list --filter=status:ACTIVE --format="value(account)"'],
shell=True,
)
return res[:-1]
if ":" not in args.member:
print "Make sure the member is specified with the user:, or serviceAccount:, etc. prefix"
elif not "roles/" in args.role:
print "Make sure the role is specified with the roles/ or roles/x. prefix"
else:
add_role(args.role, args.member, args.resource, args.serviceAccount)