1
# Copyright (c) 2010-2011 Mitch Garnaat http://garnaat.org/
2
# Copyright (c) 2010-2011, Eucalyptus Systems, Inc.
4
# Permission is hereby granted, free of charge, to any person obtaining a
5
# copy of this software and associated documentation files (the
6
# "Software"), to deal in the Software without restriction, including
7
# without limitation the rights to use, copy, modify, merge, publish, dis-
8
# tribute, sublicense, and/or sell copies of the Software, and to permit
9
# persons to whom the Software is furnished to do so, subject to the fol-
12
# The above copyright notice and this permission notice shall be included
13
# in all copies or substantial portions of the Software.
15
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
17
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
18
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24
import boto.jsonresponse
25
from boto.connection import AWSQueryConnection
27
#boto.set_stream_logger('iam')
29
class IAMConnection(AWSQueryConnection):
31
APIVersion = '2010-05-08'
33
def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
34
is_secure=True, port=None, proxy=None, proxy_port=None,
35
proxy_user=None, proxy_pass=None, host='iam.amazonaws.com',
36
debug=0, https_connection_factory=None, path='/'):
37
AWSQueryConnection.__init__(self, aws_access_key_id,
38
aws_secret_access_key,
39
is_secure, port, proxy,
40
proxy_port, proxy_user, proxy_pass,
41
host, debug, https_connection_factory, path)
43
def _required_auth_capability(self):
46
def get_response(self, action, params, path='/', parent=None,
47
verb='GET', list_marker='Set'):
49
Utility method to handle calls to IAM and parsing of responses.
53
response = self.make_request(action, params, path, verb)
54
body = response.read()
56
if response.status == 200:
57
e = boto.jsonresponse.Element(list_marker=list_marker,
59
h = boto.jsonresponse.XmlHandler(e, parent)
63
boto.log.error('%s %s' % (response.status, response.reason))
64
boto.log.error('%s' % body)
65
raise self.ResponseError(response.status, response.reason, body)
71
def get_all_groups(self, path_prefix='/', marker=None, max_items=None):
73
List the groups that have the specified path prefix.
75
:type path_prefix: string
76
:param path_prefix: If provided, only groups whose paths match
77
the provided prefix will be returned.
80
:param marker: Use this only when paginating results and only in
81
follow-up request after you've received a response
82
where the results are truncated. Set this to the
83
value of the Marker element in the response you
87
:param max_items: Use this only when paginating results to indicate
88
the maximum number of groups you want in the
93
params['PathPrefix'] = path_prefix
95
params['Marker'] = marker
97
params['MaxItems'] = max_items
98
return self.get_response('ListGroups', params,
101
def get_group(self, group_name, marker=None, max_items=None):
103
Return a list of users that are in the specified group.
105
:type group_name: string
106
:param group_name: The name of the group whose information should
109
:param marker: Use this only when paginating results and only in
110
follow-up request after you've received a response
111
where the results are truncated. Set this to the
112
value of the Marker element in the response you
116
:param max_items: Use this only when paginating results to indicate
117
the maximum number of groups you want in the
120
params = {'GroupName' : group_name}
122
params['Marker'] = marker
124
params['MaxItems'] = max_items
125
return self.get_response('GetGroup', params, list_marker='Users')
127
def create_group(self, group_name, path='/'):
131
:type group_name: string
132
:param group_name: The name of the new group
135
:param path: The path to the group (Optional). Defaults to /.
138
params = {'GroupName' : group_name,
140
return self.get_response('CreateGroup', params)
142
def delete_group(self, group_name):
144
Delete a group. The group must not contain any Users or
145
have any attached policies
147
:type group_name: string
148
:param group_name: The name of the group to delete.
151
params = {'GroupName' : group_name}
152
return self.get_response('DeleteGroup', params)
154
def update_group(self, group_name, new_group_name=None, new_path=None):
156
Updates name and/or path of the specified group.
158
:type group_name: string
159
:param group_name: The name of the new group
161
:type new_group_name: string
162
:param new_group_name: If provided, the name of the group will be
163
changed to this name.
165
:type new_path: string
166
:param new_path: If provided, the path of the group will be
167
changed to this path.
170
params = {'GroupName' : group_name}
172
params['NewGroupName'] = new_group_name
174
params['NewPath'] = new_path
175
return self.get_response('UpdateGroup', params)
177
def add_user_to_group(self, group_name, user_name):
179
Add a user to a group
181
:type group_name: string
182
:param group_name: The name of the group
184
:type user_name: string
185
:param user_name: The to be added to the group.
188
params = {'GroupName' : group_name,
189
'UserName' : user_name}
190
return self.get_response('AddUserToGroup', params)
192
def remove_user_from_group(self, group_name, user_name):
194
Remove a user from a group.
196
:type group_name: string
197
:param group_name: The name of the group
199
:type user_name: string
200
:param user_name: The user to remove from the group.
203
params = {'GroupName' : group_name,
204
'UserName' : user_name}
205
return self.get_response('RemoveUserFromGroup', params)
207
def put_group_policy(self, group_name, policy_name, policy_json):
209
Adds or updates the specified policy document for the specified group.
211
:type group_name: string
212
:param group_name: The name of the group the policy is associated with.
214
:type policy_name: string
215
:param policy_name: The policy document to get.
217
:type policy_json: string
218
:param policy_json: The policy document.
221
params = {'GroupName' : group_name,
222
'PolicyName' : policy_name,
223
'PolicyDocument' : policy_json}
224
return self.get_response('PutGroupPolicy', params, verb='POST')
226
def get_all_group_policies(self, group_name, marker=None, max_items=None):
228
List the names of the policies associated with the specified group.
230
:type group_name: string
231
:param group_name: The name of the group the policy is associated with.
234
:param marker: Use this only when paginating results and only in
235
follow-up request after you've received a response
236
where the results are truncated. Set this to the
237
value of the Marker element in the response you
241
:param max_items: Use this only when paginating results to indicate
242
the maximum number of groups you want in the
245
params = {'GroupName' : group_name}
247
params['Marker'] = marker
249
params['MaxItems'] = max_items
250
return self.get_response('ListGroupPolicies', params,
251
list_marker='PolicyNames')
253
def get_group_policy(self, group_name, policy_name):
255
Retrieves the specified policy document for the specified group.
257
:type group_name: string
258
:param group_name: The name of the group the policy is associated with.
260
:type policy_name: string
261
:param policy_name: The policy document to get.
264
params = {'GroupName' : group_name,
265
'PolicyName' : policy_name}
266
return self.get_response('GetGroupPolicy', params, verb='POST')
268
def delete_group_policy(self, group_name, policy_name):
270
Deletes the specified policy document for the specified group.
272
:type group_name: string
273
:param group_name: The name of the group the policy is associated with.
275
:type policy_name: string
276
:param policy_name: The policy document to delete.
279
params = {'GroupName' : group_name,
280
'PolicyName' : policy_name}
281
return self.get_response('DeleteGroupPolicy', params, verb='POST')
283
def get_all_users(self, path_prefix='/', marker=None, max_items=None):
285
List the users that have the specified path prefix.
287
:type path_prefix: string
288
:param path_prefix: If provided, only users whose paths match
289
the provided prefix will be returned.
292
:param marker: Use this only when paginating results and only in
293
follow-up request after you've received a response
294
where the results are truncated. Set this to the
295
value of the Marker element in the response you
299
:param max_items: Use this only when paginating results to indicate
300
the maximum number of groups you want in the
303
params = {'PathPrefix' : path_prefix}
305
params['Marker'] = marker
307
params['MaxItems'] = max_items
308
return self.get_response('ListUsers', params, list_marker='Users')
314
def create_user(self, user_name, path='/'):
318
:type user_name: string
319
:param user_name: The name of the new user
322
:param path: The path in which the user will be created.
326
params = {'UserName' : user_name,
328
return self.get_response('CreateUser', params)
330
def delete_user(self, user_name):
332
Delete a user including the user's path, GUID and ARN.
334
If the user_name is not specified, the user_name is determined
335
implicitly based on the AWS Access Key ID used to sign the request.
337
:type user_name: string
338
:param user_name: The name of the user to delete.
341
params = {'UserName' : user_name}
342
return self.get_response('DeleteUser', params)
344
def get_user(self, user_name=None):
346
Retrieve information about the specified user.
348
If the user_name is not specified, the user_name is determined
349
implicitly based on the AWS Access Key ID used to sign the request.
351
:type user_name: string
352
:param user_name: The name of the user to delete.
353
If not specified, defaults to user making
359
params['UserName'] = user_name
360
return self.get_response('GetUser', params)
362
def update_user(self, user_name, new_user_name=None, new_path=None):
364
Updates name and/or path of the specified user.
366
:type user_name: string
367
:param user_name: The name of the user
369
:type new_user_name: string
370
:param new_user_name: If provided, the username of the user will be
371
changed to this username.
373
:type new_path: string
374
:param new_path: If provided, the path of the user will be
375
changed to this path.
378
params = {'UserName' : user_name}
380
params['NewUserName'] = new_user_name
382
params['NewPath'] = new_path
383
return self.get_response('UpdateUser', params)
385
def get_all_user_policies(self, user_name, marker=None, max_items=None):
387
List the names of the policies associated with the specified user.
389
:type user_name: string
390
:param user_name: The name of the user the policy is associated with.
393
:param marker: Use this only when paginating results and only in
394
follow-up request after you've received a response
395
where the results are truncated. Set this to the
396
value of the Marker element in the response you
400
:param max_items: Use this only when paginating results to indicate
401
the maximum number of groups you want in the
404
params = {'UserName' : user_name}
406
params['Marker'] = marker
408
params['MaxItems'] = max_items
409
return self.get_response('ListUserPolicies', params,
410
list_marker='PolicyNames')
412
def put_user_policy(self, user_name, policy_name, policy_json):
414
Adds or updates the specified policy document for the specified user.
416
:type user_name: string
417
:param user_name: The name of the user the policy is associated with.
419
:type policy_name: string
420
:param policy_name: The policy document to get.
422
:type policy_json: string
423
:param policy_json: The policy document.
426
params = {'UserName' : user_name,
427
'PolicyName' : policy_name,
428
'PolicyDocument' : policy_json}
429
return self.get_response('PutUserPolicy', params, verb='POST')
431
def get_user_policy(self, user_name, policy_name):
433
Retrieves the specified policy document for the specified user.
435
:type user_name: string
436
:param user_name: The name of the user the policy is associated with.
438
:type policy_name: string
439
:param policy_name: The policy document to get.
442
params = {'UserName' : user_name,
443
'PolicyName' : policy_name}
444
return self.get_response('GetUserPolicy', params, verb='POST')
446
def delete_user_policy(self, user_name, policy_name):
448
Deletes the specified policy document for the specified user.
450
:type user_name: string
451
:param user_name: The name of the user the policy is associated with.
453
:type policy_name: string
454
:param policy_name: The policy document to delete.
457
params = {'UserName' : user_name,
458
'PolicyName' : policy_name}
459
return self.get_response('DeleteUserPolicy', params, verb='POST')
461
def get_groups_for_user(self, user_name, marker=None, max_items=None):
463
List the groups that a specified user belongs to.
465
:type user_name: string
466
:param user_name: The name of the user to list groups for.
469
:param marker: Use this only when paginating results and only in
470
follow-up request after you've received a response
471
where the results are truncated. Set this to the
472
value of the Marker element in the response you
476
:param max_items: Use this only when paginating results to indicate
477
the maximum number of groups you want in the
480
params = {'UserName' : user_name}
482
params['Marker'] = marker
484
params['MaxItems'] = max_items
485
return self.get_response('ListGroupsForUser', params,
486
list_marker='Groups')
492
def get_all_access_keys(self, user_name, marker=None, max_items=None):
494
Get all access keys associated with an account.
496
:type user_name: string
497
:param user_name: The username of the user
500
:param marker: Use this only when paginating results and only in
501
follow-up request after you've received a response
502
where the results are truncated. Set this to the
503
value of the Marker element in the response you
507
:param max_items: Use this only when paginating results to indicate
508
the maximum number of groups you want in the
511
params = {'UserName' : user_name}
513
params['Marker'] = marker
515
params['MaxItems'] = max_items
516
return self.get_response('ListAccessKeys', params,
517
list_marker='AccessKeyMetadata')
519
def create_access_key(self, user_name=None):
521
Create a new AWS Secret Access Key and corresponding AWS Access Key ID
522
for the specified user. The default status for new keys is Active
524
If the user_name is not specified, the user_name is determined
525
implicitly based on the AWS Access Key ID used to sign the request.
527
:type user_name: string
528
:param user_name: The username of the user
531
params = {'UserName' : user_name}
532
return self.get_response('CreateAccessKey', params)
534
def update_access_key(self, access_key_id, status, user_name=None):
536
Changes the status of the specified access key from Active to Inactive
537
or vice versa. This action can be used to disable a user's key as
538
part of a key rotation workflow.
540
If the user_name is not specified, the user_name is determined
541
implicitly based on the AWS Access Key ID used to sign the request.
543
:type access_key_id: string
544
:param access_key_id: The ID of the access key.
547
:param status: Either Active or Inactive.
549
:type user_name: string
550
:param user_name: The username of user (optional).
553
params = {'AccessKeyId' : access_key_id,
556
params['UserName'] = user_name
557
return self.get_response('UpdateAccessKey', params)
559
def delete_access_key(self, access_key_id, user_name=None):
561
Delete an access key associated with a user.
563
If the user_name is not specified, it is determined implicitly based
564
on the AWS Access Key ID used to sign the request.
566
:type access_key_id: string
567
:param access_key_id: The ID of the access key to be deleted.
569
:type user_name: string
570
:param user_name: The username of the user
573
params = {'AccessKeyId' : access_key_id}
575
params['UserName'] = user_name
576
return self.get_response('DeleteAccessKey', params)
579
# Signing Certificates
582
def get_all_signing_certs(self, marker=None, max_items=None,
585
Get all signing certificates associated with an account.
587
If the user_name is not specified, it is determined implicitly based
588
on the AWS Access Key ID used to sign the request.
591
:param marker: Use this only when paginating results and only in
592
follow-up request after you've received a response
593
where the results are truncated. Set this to the
594
value of the Marker element in the response you
598
:param max_items: Use this only when paginating results to indicate
599
the maximum number of groups you want in the
602
:type user_name: string
603
:param user_name: The username of the user
608
params['Marker'] = marker
610
params['MaxItems'] = max_items
612
params['UserName'] = user_name
613
return self.get_response('ListSigningCertificates',
614
params, list_marker='Certificates')
616
def update_signing_cert(self, cert_id, status, user_name=None):
618
Change the status of the specified signing certificate from
619
Active to Inactive or vice versa.
621
If the user_name is not specified, it is determined implicitly based
622
on the AWS Access Key ID used to sign the request.
624
:type cert_id: string
625
:param cert_id: The ID of the signing certificate
628
:param status: Either Active or Inactive.
630
:type user_name: string
631
:param user_name: The username of the user
633
params = {'CertificateId' : cert_id,
636
params['UserName'] = user_name
637
return self.get_response('UpdateSigningCertificate', params)
639
def upload_signing_cert(self, cert_body, user_name=None):
641
Uploads an X.509 signing certificate and associates it with
644
If the user_name is not specified, it is determined implicitly based
645
on the AWS Access Key ID used to sign the request.
647
:type cert_body: string
648
:param cert_body: The body of the signing certificate.
650
:type user_name: string
651
:param user_name: The username of the user
654
params = {'CertificateBody' : cert_body}
656
params['UserName'] = user_name
657
return self.get_response('UploadSigningCertificate', params,
660
def delete_signing_cert(self, cert_id, user_name=None):
662
Delete a signing certificate associated with a user.
664
If the user_name is not specified, it is determined implicitly based
665
on the AWS Access Key ID used to sign the request.
667
:type user_name: string
668
:param user_name: The username of the user
670
:type cert_id: string
671
:param cert_id: The ID of the certificate.
674
params = {'CertificateId' : cert_id}
676
params['UserName'] = user_name
677
return self.get_response('DeleteSigningCertificate', params)
680
# Server Certificates
683
def get_all_server_certs(self, path_prefix='/',
684
marker=None, max_items=None):
686
Lists the server certificates that have the specified path prefix.
687
If none exist, the action returns an empty list.
689
:type path_prefix: string
690
:param path_prefix: If provided, only certificates whose paths match
691
the provided prefix will be returned.
694
:param marker: Use this only when paginating results and only in
695
follow-up request after you've received a response
696
where the results are truncated. Set this to the
697
value of the Marker element in the response you
701
:param max_items: Use this only when paginating results to indicate
702
the maximum number of groups you want in the
708
params['PathPrefix'] = path_prefix
710
params['Marker'] = marker
712
params['MaxItems'] = max_items
713
return self.get_response('ListServerCertificates',
715
list_marker='ServerCertificateMetadataList')
717
def update_server_cert(self, cert_name, new_cert_name=None,
720
Updates the name and/or the path of the specified server certificate.
722
:type cert_name: string
723
:param cert_name: The name of the server certificate that you want
726
:type new_cert_name: string
727
:param new_cert_name: The new name for the server certificate.
728
Include this only if you are updating the
729
server certificate's name.
731
:type new_path: string
732
:param new_path: If provided, the path of the certificate will be
733
changed to this path.
735
params = {'ServerCertificateName' : cert_name}
737
params['NewServerCertificateName'] = new_cert_name
739
params['NewPath'] = new_path
740
return self.get_response('UpdateServerCertificate', params)
742
def upload_server_cert(self, cert_name, cert_body, private_key,
743
cert_chain=None, path=None):
745
Uploads a server certificate entity for the AWS Account.
746
The server certificate entity includes a public key certificate,
747
a private key, and an optional certificate chain, which should
750
:type cert_name: string
751
:param cert_name: The name for the server certificate. Do not
752
include the path in this value.
754
:type cert_body: string
755
:param cert_body: The contents of the public key certificate
756
in PEM-encoded format.
758
:type private_key: string
759
:param private_key: The contents of the private key in
762
:type cert_chain: string
763
:param cert_chain: The contents of the certificate chain. This
764
is typically a concatenation of the PEM-encoded
765
public key certificates of the chain.
768
:param path: The path for the server certificate.
771
params = {'ServerCertificateName' : cert_name,
772
'CertificateBody' : cert_body,
773
'PrivateKey' : private_key}
775
params['CertificateChain'] = cert_chain
777
params['Path'] = path
778
return self.get_response('UploadServerCertificate', params,
781
def get_server_certificate(self, cert_name):
783
Retrieves information about the specified server certificate.
785
:type cert_name: string
786
:param cert_name: The name of the server certificate you want
787
to retrieve information about.
790
params = {'ServerCertificateName' : cert_name}
791
return self.get_response('GetServerCertificate', params)
793
def delete_server_cert(self, cert_name):
795
Delete the specified server certificate.
797
:type cert_name: string
798
:param cert_name: The name of the server certificate you want
802
params = {'ServerCertificateName' : cert_name}
803
return self.get_response('DeleteServerCertificate', params)
809
def get_all_mfa_devices(self, user_name, marker=None, max_items=None):
811
Get all MFA devices associated with an account.
813
:type user_name: string
814
:param user_name: The username of the user
817
:param marker: Use this only when paginating results and only in
818
follow-up request after you've received a response
819
where the results are truncated. Set this to the
820
value of the Marker element in the response you
824
:param max_items: Use this only when paginating results to indicate
825
the maximum number of groups you want in the
829
params = {'UserName' : user_name}
831
params['Marker'] = marker
833
params['MaxItems'] = max_items
834
return self.get_response('ListMFADevices',
835
params, list_marker='MFADevices')
837
def enable_mfa_device(self, user_name, serial_number,
838
auth_code_1, auth_code_2):
840
Enables the specified MFA device and associates it with the
843
:type user_name: string
844
:param user_name: The username of the user
846
:type serial_number: string
847
:param seriasl_number: The serial number which uniquely identifies
850
:type auth_code_1: string
851
:param auth_code_1: An authentication code emitted by the device.
853
:type auth_code_2: string
854
:param auth_code_2: A subsequent authentication code emitted
858
params = {'UserName' : user_name,
859
'SerialNumber' : serial_number,
860
'AuthenticationCode1' : auth_code_1,
861
'AuthenticationCode2' : auth_code_2}
862
return self.get_response('EnableMFADevice', params)
864
def deactivate_mfa_device(self, user_name, serial_number):
866
Deactivates the specified MFA device and removes it from
867
association with the user.
869
:type user_name: string
870
:param user_name: The username of the user
872
:type serial_number: string
873
:param seriasl_number: The serial number which uniquely identifies
877
params = {'UserName' : user_name,
878
'SerialNumber' : serial_number}
879
return self.get_response('DeactivateMFADevice', params)
881
def resync_mfa_device(self, user_name, serial_number,
882
auth_code_1, auth_code_2):
884
Syncronizes the specified MFA device with the AWS servers.
886
:type user_name: string
887
:param user_name: The username of the user
889
:type serial_number: string
890
:param seriasl_number: The serial number which uniquely identifies
893
:type auth_code_1: string
894
:param auth_code_1: An authentication code emitted by the device.
896
:type auth_code_2: string
897
:param auth_code_2: A subsequent authentication code emitted
901
params = {'UserName' : user_name,
902
'SerialNumber' : serial_number,
903
'AuthenticationCode1' : auth_code_1,
904
'AuthenticationCode2' : auth_code_2}
905
return self.get_response('ResyncMFADevice', params)
911
def get_login_profiles(self, user_name):
913
Retrieves the login profile for the specified user.
915
:type user_name: string
916
:param user_name: The username of the user
919
params = {'UserName' : user_name}
920
return self.get_response('GetLoginProfile', params)
922
def create_login_profile(self, user_name, password):
924
Creates a login profile for the specified user, give the user the
925
ability to access AWS services and the AWS Management Console.
927
:type user_name: string
928
:param user_name: The name of the user
930
:type password: string
931
:param password: The new password for the user
934
params = {'UserName' : user_name,
935
'Password' : password}
936
return self.get_response('CreateLoginProfile', params)
938
def delete_login_profile(self, user_name):
940
Deletes the login profile associated with the specified user.
942
:type user_name: string
943
:param user_name: The name of the user to delete.
946
params = {'UserName' : user_name}
947
return self.get_response('DeleteLoginProfile', params)
949
def update_login_profile(self, user_name, password):
951
Resets the password associated with the user's login profile.
953
:type user_name: string
954
:param user_name: The name of the user
956
:type password: string
957
:param password: The new password for the user
960
params = {'UserName' : user_name,
961
'Password' : password}
962
return self.get_response('UpdateLoginProfile', params)
964
def create_account_alias(self, alias):
966
Creates a new alias for the AWS account.
968
For more information on account id aliases, please see
972
:param alias: The alias to attach to the account.
974
params = {'AccountAlias': alias}
975
return self.get_response('CreateAccountAlias', params)
977
def delete_account_alias(self, alias):
979
Deletes an alias for the AWS account.
981
For more information on account id aliases, please see
985
:param alias: The alias to remove from the account.
987
params = {'AccountAlias': alias}
988
return self.get_response('DeleteAccountAlias', params)
990
def get_account_alias(self):
992
Get the alias for the current account.
994
This is referred to in the docs as list_account_aliases,
995
but it seems you can only have one account alias currently.
997
For more information on account id aliases, please see
1000
r = self.get_response('ListAccountAliases', {})
1001
response = r.get('ListAccountAliasesResponse')
1002
result = response.get('ListAccountAliasesResult')
1003
aliases = result.get('AccountAliases')
1004
return aliases.get('member', None)
1006
def get_signin_url(self, service='ec2'):
1008
Get the URL where IAM users can use their login profile to sign in
1009
to this account's console.
1011
:type service: string
1012
:param service: Default service to go to in the console.
1014
alias = self.get_account_alias()
1016
raise Exception('No alias associated with this account. Please use iam.create_account_alias() first.')
1018
return "https://%s.signin.aws.amazon.com/console/%s" % (alias, service)