kopia lustrzana https://github.com/simonw/s3-credentials
s3-credentials list-buckets --details option, closes #22
rodzic
6d0b5da65d
commit
8e207980a2
86
README.md
86
README.md
|
@ -143,9 +143,91 @@ Add `--array` to output a valid JSON array of objects instead.
|
|||
|
||||
Shows a list of all buckets in your AWS account.
|
||||
|
||||
s3-credentials list-buckets
|
||||
% s3-credentials list-buckets
|
||||
{
|
||||
"Name": "aws-cloudtrail-logs-462092780466-f2c900d3",
|
||||
"CreationDate": "2021-03-25 22:19:54+00:00"
|
||||
}
|
||||
{
|
||||
"Name": "simonw-test-bucket-for-s3-credentials",
|
||||
"CreationDate": "2021-11-03 21:46:12+00:00"
|
||||
}
|
||||
|
||||
Accepts the same `--nl` and `--array` options as `list-users`.
|
||||
With no extra arguments this will show all available buckets - you can also add one or more explicit bucket names to see just those buckets:
|
||||
|
||||
% s3-credentials list-buckets simonw-test-bucket-for-s3-credentials
|
||||
{
|
||||
"Name": "simonw-test-bucket-for-s3-credentials",
|
||||
"CreationDate": "2021-11-03 21:46:12+00:00"
|
||||
}
|
||||
|
||||
This accepts the same `--nl` and `--array` options as `list-users`.
|
||||
|
||||
Add `--details` to include details of the bucket ACL, website configuration and public access block settings. This is useful for running a security audit of your buckets.
|
||||
|
||||
Using `--details` adds three additional API calls for each bucket, so it is advisable to use it with one or more explicit bucket names.
|
||||
```
|
||||
% s3-credentials list-buckets simonw-test-public-website-bucket --details
|
||||
{
|
||||
"Name": "simonw-test-public-website-bucket",
|
||||
"CreationDate": "2021-11-08 22:53:30+00:00",
|
||||
"bucket_acl": {
|
||||
"Owner": {
|
||||
"DisplayName": "simon",
|
||||
"ID": "abcdeabcdeabcdeabcdeabcdeabcde0001"
|
||||
},
|
||||
"Grants": [
|
||||
{
|
||||
"Grantee": {
|
||||
"DisplayName": "simon",
|
||||
"ID": "abcdeabcdeabcdeabcdeabcdeabcde0001",
|
||||
"Type": "CanonicalUser"
|
||||
},
|
||||
"Permission": "FULL_CONTROL"
|
||||
}
|
||||
]
|
||||
},
|
||||
"public_access_block": null,
|
||||
"bucket_website": {
|
||||
"IndexDocument": {
|
||||
"Suffix": "index.html"
|
||||
},
|
||||
"ErrorDocument": {
|
||||
"Key": "error.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
A bucket with `public_access_block` might look like this:
|
||||
```json
|
||||
{
|
||||
"Name": "aws-cloudtrail-logs-462092780466-f2c900d3",
|
||||
"CreationDate": "2021-03-25 22:19:54+00:00",
|
||||
"bucket_acl": {
|
||||
"Owner": {
|
||||
"DisplayName": "simon",
|
||||
"ID": "abcdeabcdeabcdeabcdeabcdeabcde0001"
|
||||
},
|
||||
"Grants": [
|
||||
{
|
||||
"Grantee": {
|
||||
"DisplayName": "simon",
|
||||
"ID": "abcdeabcdeabcdeabcdeabcdeabcde0001",
|
||||
"Type": "CanonicalUser"
|
||||
},
|
||||
"Permission": "FULL_CONTROL"
|
||||
}
|
||||
]
|
||||
},
|
||||
"public_access_block": {
|
||||
"BlockPublicAcls": true,
|
||||
"IgnorePublicAcls": true,
|
||||
"BlockPublicPolicy": true,
|
||||
"RestrictPublicBuckets": true
|
||||
},
|
||||
"bucket_website": null
|
||||
}
|
||||
```
|
||||
|
||||
### list-user-policies
|
||||
|
||||
|
|
|
@ -289,14 +289,47 @@ def list_user_policies(usernames, access_key, secret_key, session_token, endpoin
|
|||
|
||||
|
||||
@cli.command()
|
||||
@click.argument("buckets", nargs=-1)
|
||||
@click.option("--details", help="Include extra bucket details (slower)", is_flag=True)
|
||||
@click.option("--array", help="Output a valid JSON array", is_flag=True)
|
||||
@click.option("--nl", help="Output newline-delimited JSON", is_flag=True)
|
||||
@common_boto3_options
|
||||
def list_buckets(array, nl, access_key, secret_key, session_token, endpoint_url):
|
||||
"List all buckets"
|
||||
def list_buckets(
|
||||
buckets, details, array, nl, access_key, secret_key, session_token, endpoint_url
|
||||
):
|
||||
"List buckets - defaults to all, or pass one or more bucket names"
|
||||
s3 = make_client("s3", access_key, secret_key, session_token, endpoint_url)
|
||||
gathered = []
|
||||
for bucket in s3.list_buckets()["Buckets"]:
|
||||
if buckets and (bucket["Name"] not in buckets):
|
||||
continue
|
||||
if details:
|
||||
bucket_acl = dict(
|
||||
(key, value)
|
||||
for key, value in s3.get_bucket_acl(
|
||||
Bucket=bucket["Name"],
|
||||
).items()
|
||||
if key != "ResponseMetadata"
|
||||
)
|
||||
try:
|
||||
pab = s3.get_public_access_block(
|
||||
Bucket=bucket["Name"],
|
||||
)["PublicAccessBlockConfiguration"]
|
||||
except s3.exceptions.ClientError:
|
||||
pab = None
|
||||
try:
|
||||
bucket_website = dict(
|
||||
(key, value)
|
||||
for key, value in s3.get_bucket_website(
|
||||
Bucket=bucket["Name"],
|
||||
).items()
|
||||
if key != "ResponseMetadata"
|
||||
)
|
||||
except s3.exceptions.ClientError:
|
||||
bucket_website = None
|
||||
bucket["bucket_acl"] = bucket_acl
|
||||
bucket["public_access_block"] = pab
|
||||
bucket["bucket_website"] = bucket_website
|
||||
if array:
|
||||
gathered.append(bucket)
|
||||
else:
|
||||
|
|
|
@ -130,10 +130,10 @@ def test_list_users(mocker, option, expected, stub_iam):
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"option,expected",
|
||||
"options,expected",
|
||||
(
|
||||
(
|
||||
"",
|
||||
[],
|
||||
"{\n"
|
||||
' "Name": "bucket-one",\n'
|
||||
' "CreationDate": "2020-01-01 00:00:00+00:00"\n'
|
||||
|
@ -144,7 +144,7 @@ def test_list_users(mocker, option, expected, stub_iam):
|
|||
"}\n",
|
||||
),
|
||||
(
|
||||
"--array",
|
||||
["--array"],
|
||||
"[\n"
|
||||
" {\n"
|
||||
' "Name": "bucket-one",\n'
|
||||
|
@ -157,13 +157,17 @@ def test_list_users(mocker, option, expected, stub_iam):
|
|||
"\n]\n",
|
||||
),
|
||||
(
|
||||
"--nl",
|
||||
["--nl"],
|
||||
'{"Name": "bucket-one", "CreationDate": "2020-01-01 00:00:00+00:00"}\n'
|
||||
'{"Name": "bucket-two", "CreationDate": "2020-02-01 00:00:00+00:00"}\n',
|
||||
),
|
||||
(
|
||||
["--nl", "bucket-one"],
|
||||
'{"Name": "bucket-one", "CreationDate": "2020-01-01 00:00:00+00:00"}\n',
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_list_buckets(stub_s3, option, expected):
|
||||
def test_list_buckets(stub_s3, options, expected):
|
||||
stub_s3.add_response(
|
||||
"list_buckets",
|
||||
{
|
||||
|
@ -181,11 +185,103 @@ def test_list_buckets(stub_s3, option, expected):
|
|||
)
|
||||
runner = CliRunner()
|
||||
with runner.isolated_filesystem():
|
||||
result = runner.invoke(cli, ["list-buckets"] + ([option] if option else []))
|
||||
result = runner.invoke(cli, ["list-buckets"] + options)
|
||||
assert result.exit_code == 0
|
||||
assert result.output == expected
|
||||
|
||||
|
||||
def test_list_buckets_details(stub_s3):
|
||||
stub_s3.add_response(
|
||||
"list_buckets",
|
||||
{
|
||||
"Buckets": [
|
||||
{
|
||||
"Name": "bucket-one",
|
||||
"CreationDate": "2020-01-01 00:00:00+00:00",
|
||||
}
|
||||
]
|
||||
},
|
||||
)
|
||||
stub_s3.add_response(
|
||||
"get_bucket_acl",
|
||||
{
|
||||
"Owner": {
|
||||
"DisplayName": "swillison",
|
||||
"ID": "36b2eeee501c5952a8ac119f9e5212277a4c01eccfa8d6a9d670bba1e2d5f441",
|
||||
},
|
||||
"Grants": [
|
||||
{
|
||||
"Grantee": {
|
||||
"DisplayName": "swillison",
|
||||
"ID": "36b2eeee501c5952a8ac119f9e5212277a4c01eccfa8d6a9d670bba1e2d5f441",
|
||||
"Type": "CanonicalUser",
|
||||
},
|
||||
"Permission": "FULL_CONTROL",
|
||||
}
|
||||
],
|
||||
"ResponseMetadata": {},
|
||||
},
|
||||
)
|
||||
stub_s3.add_response(
|
||||
"get_public_access_block",
|
||||
{
|
||||
"PublicAccessBlockConfiguration": {
|
||||
"BlockPublicAcls": True,
|
||||
"IgnorePublicAcls": True,
|
||||
"BlockPublicPolicy": True,
|
||||
"RestrictPublicBuckets": True,
|
||||
},
|
||||
},
|
||||
)
|
||||
stub_s3.add_response(
|
||||
"get_bucket_website",
|
||||
{
|
||||
"IndexDocument": {"Suffix": "index.html"},
|
||||
"ErrorDocument": {"Key": "error.html"},
|
||||
},
|
||||
)
|
||||
runner = CliRunner()
|
||||
with runner.isolated_filesystem():
|
||||
result = runner.invoke(cli, ["list-buckets", "--details"])
|
||||
assert result.exit_code == 0
|
||||
assert result.output == (
|
||||
"{\n"
|
||||
' "Name": "bucket-one",\n'
|
||||
' "CreationDate": "2020-01-01 00:00:00+00:00",\n'
|
||||
' "bucket_acl": {\n'
|
||||
' "Owner": {\n'
|
||||
' "DisplayName": "swillison",\n'
|
||||
' "ID": "36b2eeee501c5952a8ac119f9e5212277a4c01eccfa8d6a9d670bba1e2d5f441"\n'
|
||||
" },\n"
|
||||
' "Grants": [\n'
|
||||
" {\n"
|
||||
' "Grantee": {\n'
|
||||
' "DisplayName": "swillison",\n'
|
||||
' "ID": "36b2eeee501c5952a8ac119f9e5212277a4c01eccfa8d6a9d670bba1e2d5f441",\n'
|
||||
' "Type": "CanonicalUser"\n'
|
||||
" },\n"
|
||||
' "Permission": "FULL_CONTROL"\n'
|
||||
" }\n"
|
||||
" ]\n"
|
||||
" },\n"
|
||||
' "public_access_block": {\n'
|
||||
' "BlockPublicAcls": true,\n'
|
||||
' "IgnorePublicAcls": true,\n'
|
||||
' "BlockPublicPolicy": true,\n'
|
||||
' "RestrictPublicBuckets": true\n'
|
||||
" },\n"
|
||||
' "bucket_website": {\n'
|
||||
' "IndexDocument": {\n'
|
||||
' "Suffix": "index.html"\n'
|
||||
" },\n"
|
||||
' "ErrorDocument": {\n'
|
||||
' "Key": "error.html"\n'
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
)
|
||||
|
||||
|
||||
CUSTOM_POLICY = '{"custom": "policy", "bucket": "$!BUCKET_NAME!$"}'
|
||||
READ_WRITE_POLICY = '{"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": ["arn:aws:s3:::pytest-bucket-simonw-1"]}, {"Effect": "Allow", "Action": "s3:*Object", "Resource": ["arn:aws:s3:::pytest-bucket-simonw-1/*"]}]}'
|
||||
READ_ONLY_POLICY = '{"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": ["arn:aws:s3:::pytest-bucket-simonw-1"]}, {"Effect": "Allow", "Action": "s3:GetObject*", "Resource": ["arn:aws:s3:::pytest-bucket-simonw-1/*"]}]}'
|
||||
|
|
Ładowanie…
Reference in New Issue