kopia lustrzana https://github.com/simonw/s3-credentials
s3-credentials delete-user command, closes #10
rodzic
217f790089
commit
eec24e0866
17
README.md
17
README.md
|
@ -132,6 +132,23 @@ You can pass any number of usernames here. If you don't specify a username the t
|
||||||
|
|
||||||
s3-credentials list-user-policies
|
s3-credentials list-user-policies
|
||||||
|
|
||||||
|
### delete-user
|
||||||
|
|
||||||
|
In trying out this tool it's possible you will create several different user accounts that you later decide to clean up.
|
||||||
|
|
||||||
|
Deleting AWS users is a little fiddly: you first need to delete their access keys, then their inline policies and finally the user themselves.
|
||||||
|
|
||||||
|
The `s3-credentials delete-user` handles this for you:
|
||||||
|
|
||||||
|
```
|
||||||
|
% s3-credentials delete-user s3.read-write.simonw-test-bucket-10
|
||||||
|
User: s3.read-write.simonw-test-bucket-10
|
||||||
|
Deleted policy: s3.read-write.simonw-test-bucket-10
|
||||||
|
Deleted access key: AKIAWXFXAIOZK3GPEIWR
|
||||||
|
Deleted user
|
||||||
|
```
|
||||||
|
You can pass it multiple usernames to delete multiple users at a time.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
To contribute to this tool, first checkout the code. Then create a new virtual environment:
|
To contribute to this tool, first checkout the code. Then create a new virtual environment:
|
||||||
|
|
|
@ -233,3 +233,38 @@ def list_buckets(array, nl):
|
||||||
click.echo(json.dumps(bucket, indent=4, default=str))
|
click.echo(json.dumps(bucket, indent=4, default=str))
|
||||||
if gathered:
|
if gathered:
|
||||||
click.echo(json.dumps(gathered, indent=4, default=str))
|
click.echo(json.dumps(gathered, indent=4, default=str))
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command()
|
||||||
|
@click.argument("usernames", nargs=-1, required=True)
|
||||||
|
def delete_user(usernames):
|
||||||
|
"Delete specified users, their access keys and their inline policies"
|
||||||
|
iam = boto3.client("iam")
|
||||||
|
policy_paginator = iam.get_paginator("list_user_policies")
|
||||||
|
access_key_paginator = iam.get_paginator("list_access_keys")
|
||||||
|
for username in usernames:
|
||||||
|
click.echo("User: {}".format(username))
|
||||||
|
# Fetch and delete their policies
|
||||||
|
policy_names = []
|
||||||
|
for response in policy_paginator.paginate(UserName=username):
|
||||||
|
for policy_name in response["PolicyNames"]:
|
||||||
|
policy_names.append(policy_name)
|
||||||
|
for policy_name in policy_names:
|
||||||
|
iam.delete_user_policy(
|
||||||
|
UserName=username,
|
||||||
|
PolicyName=policy_name,
|
||||||
|
)
|
||||||
|
click.echo(" Deleted policy: {}".format(policy_name))
|
||||||
|
# Fetch and delete their access keys
|
||||||
|
access_key_ids = []
|
||||||
|
for response in access_key_paginator.paginate(UserName=username):
|
||||||
|
for access_key in response["AccessKeyMetadata"]:
|
||||||
|
access_key_ids.append(access_key["AccessKeyId"])
|
||||||
|
for access_key_id in access_key_ids:
|
||||||
|
iam.delete_access_key(
|
||||||
|
UserName=username,
|
||||||
|
AccessKeyId=access_key_id,
|
||||||
|
)
|
||||||
|
click.echo(" Deleted access key: {}".format(access_key_id))
|
||||||
|
iam.delete_user(UserName=username)
|
||||||
|
click.echo(" Deleted user")
|
||||||
|
|
|
@ -141,3 +141,44 @@ def test_list_user_policies(mocker):
|
||||||
call().get_user_policy(UserName="two", PolicyName="policy-one"),
|
call().get_user_policy(UserName="two", PolicyName="policy-one"),
|
||||||
call().get_user_policy(UserName="two", PolicyName="policy-two"),
|
call().get_user_policy(UserName="two", PolicyName="policy-two"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete_user(mocker):
|
||||||
|
boto3 = mocker.patch("boto3.client")
|
||||||
|
boto3.return_value = Mock()
|
||||||
|
boto3.return_value.get_user_policy.return_value = {
|
||||||
|
"PolicyDocument": {"policy": "here"}
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_paginator(type):
|
||||||
|
m = Mock()
|
||||||
|
if type == "list_access_keys":
|
||||||
|
m.paginate.return_value = [
|
||||||
|
{"AccessKeyMetadata": [{"AccessKeyId": "one"}, {"AccessKeyId": "two"}]}
|
||||||
|
]
|
||||||
|
elif type == "list_user_policies":
|
||||||
|
m.paginate.return_value = [{"PolicyNames": ["policy-one"]}]
|
||||||
|
return m
|
||||||
|
|
||||||
|
boto3().get_paginator.side_effect = get_paginator
|
||||||
|
runner = CliRunner()
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
result = runner.invoke(cli, ["delete-user", "user-123"], catch_exceptions=False)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
assert result.output == (
|
||||||
|
"User: user-123\n"
|
||||||
|
" Deleted policy: policy-one\n"
|
||||||
|
" Deleted access key: one\n"
|
||||||
|
" Deleted access key: two\n"
|
||||||
|
" Deleted user\n"
|
||||||
|
)
|
||||||
|
assert boto3.mock_calls == [
|
||||||
|
call(),
|
||||||
|
call("iam"),
|
||||||
|
call().get_paginator("list_user_policies"),
|
||||||
|
call().get_paginator("list_access_keys"),
|
||||||
|
call().delete_user_policy(UserName="user-123", PolicyName="policy-one"),
|
||||||
|
call().delete_access_key(UserName="user-123", AccessKeyId="one"),
|
||||||
|
call().delete_access_key(UserName="user-123", AccessKeyId="two"),
|
||||||
|
call().delete_user(UserName="user-123"),
|
||||||
|
]
|
||||||
|
|
Ładowanie…
Reference in New Issue