list-user-policies command, closes #5

pull/16/head
Simon Willison 2021-11-02 19:07:00 -07:00
rodzic 1f0cc51142
commit a8e10fb148
3 zmienionych plików z 120 dodań i 2 usunięć

Wyświetl plik

@ -29,6 +29,7 @@ In this example I create credentials for reading and writing files in my `static
```
% s3-credentials create static.niche-museums.com
Created user: s3.read-write.static.niche-museums.com with permissions boundary: arn:aws:iam::aws:policy/AmazonS3FullAccess
Attached policy s3.read-write.static.niche-museums.com to user s3.read-write.static.niche-museums.com
Created access key for user: s3.read-write.static.niche-museums.com
@ -64,7 +65,7 @@ Here's the full sequence of events that take place when you run this command:
To see which user you are authenticated as:
$ s3-credentials whoami
s3-credentials whoami
This will output JSON representing the currently authenticated user.
@ -72,7 +73,7 @@ This will output JSON representing the currently authenticated user.
To see a list of all users that exist for your AWS account:
$ s3-credentials list-users
s3-credentials list-users
This will return pretty-printed JSON objects by default.
@ -80,6 +81,43 @@ Add `--nl` to collapse these to single lines as valid newline-delimited JSON.
Add `--array` to output a valid JSON array of objects instead.
### list-user-policies
To see a list of inline policies belonging to users:
```
% s3-credentials list-user-policies s3.read-write.static.niche-museums.com
User: s3.read-write.static.niche-museums.com
PolicyName: s3.read-write.static.niche-museums.com
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListObjectsInBucket",
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::static.niche-museums.com"
]
},
{
"Sid": "AllObjectActions",
"Effect": "Allow",
"Action": "s3:*Object",
"Resource": [
"arn:aws:s3:::static.niche-museums.com/*"
]
}
]
}
```
You can pass any number of usernames here. If you don't specify a username the tool will loop through every user belonging to your account:
s3-credentials list-user-policies
## Development
To contribute to this tool, first checkout the code. Then create a new virtual environment:

Wyświetl plik

@ -188,3 +188,29 @@ def list_users(array, nl):
click.echo(json.dumps(user, indent=4, default=str))
if gathered:
click.echo(json.dumps(gathered, indent=4, default=str))
@cli.command()
@click.argument("usernames", nargs=-1)
def list_user_policies(usernames):
"List inline policies for specified user"
iam = boto3.client("iam")
if not usernames:
usernames = []
paginator = iam.get_paginator("list_users")
for response in paginator.paginate():
for user in response["Users"]:
usernames.append(user["UserName"])
paginator = iam.get_paginator("list_user_policies")
for username in usernames:
click.echo("User: {}".format(username))
for response in paginator.paginate(UserName=username):
for policy_name in response["PolicyNames"]:
click.echo("PolicyName: {}".format(policy_name))
policy_response = iam.get_user_policy(
UserName=username, PolicyName=policy_name
)
click.echo(
json.dumps(policy_response["PolicyDocument"], indent=4, default=str)
)

Wyświetl plik

@ -65,3 +65,57 @@ def test_create(mocker):
'call().put_user_policy(PolicyDocument=\'{"Version": "2012-10-17", "Statement": [{"Sid": "ListObjectsInBucket", "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": ["arn:aws:s3:::pytest-bucket-simonw-1"]}, {"Sid": "AllObjectActions", "Effect": "Allow", "Action": "s3:*Object", "Resource": ["arn:aws:s3:::pytest-bucket-simonw-1/*"]}]}\', PolicyName=\'s3.read-write.pytest-bucket-simonw-1\', UserName=\'s3.read-write.pytest-bucket-simonw-1\')',
"call().create_access_key(UserName='s3.read-write.pytest-bucket-simonw-1')",
]
def test_list_user_policies(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_users":
m.paginate.return_value = [
{"Users": [{"UserName": "one"}, {"UserName": "two"}]}
]
elif type == "list_user_policies":
m.paginate.return_value = [{"PolicyNames": ["policy-one", "policy-two"]}]
return m
boto3().get_paginator.side_effect = get_paginator
runner = CliRunner()
with runner.isolated_filesystem():
result = runner.invoke(cli, ["list-user-policies"], catch_exceptions=False)
assert result.exit_code == 0
assert result.output == (
"User: one\n"
"PolicyName: policy-one\n"
"{\n"
' "policy": "here"\n'
"}\n"
"PolicyName: policy-two\n"
"{\n"
' "policy": "here"\n'
"}\n"
"User: two\n"
"PolicyName: policy-one\n"
"{\n"
' "policy": "here"\n'
"}\n"
"PolicyName: policy-two\n"
"{\n"
' "policy": "here"\n'
"}\n"
)
assert [str(c) for c in boto3.mock_calls] == [
"call()",
"call('iam')",
"call().get_paginator('list_users')",
"call().get_paginator('list_user_policies')",
"call().get_user_policy(UserName='one', PolicyName='policy-one')",
"call().get_user_policy(UserName='one', PolicyName='policy-two')",
"call().get_user_policy(UserName='two', PolicyName='policy-one')",
"call().get_user_policy(UserName='two', PolicyName='policy-two')",
]