Skip to content

Commit 82c8a85

Browse files
Merge branch 'release-1.44.76'
* release-1.44.76: Bumping version to 1.44.76 Update changelog based on model updates Allow SSEC bucket decryption in s3 integ tests (#10203) Tighten file permissions for virtual MFA bootstrap output (#10194) Tighten file permissions when writing credentials in CodeArtifact login.py (#10191)
2 parents f646153 + 1601f3b commit 82c8a85

11 files changed

Lines changed: 256 additions & 33 deletions

File tree

.changes/1.44.76.json

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
[
2+
{
3+
"category": "``backup``",
4+
"description": "Adding EKS specific backup vault notification types for AWS Backup.",
5+
"type": "api-change"
6+
},
7+
{
8+
"category": "``drs``",
9+
"description": "This changes adds support for modifying the replication configuration to support data replication using IPv6.",
10+
"type": "api-change"
11+
},
12+
{
13+
"category": "``ecr``",
14+
"description": "Add UnableToListUpstreamImageReferrersException in ListImageReferrers",
15+
"type": "api-change"
16+
},
17+
{
18+
"category": "``endpoint-rules``",
19+
"description": "Update endpoint-rules command to latest version",
20+
"type": "api-change"
21+
},
22+
{
23+
"category": "``ivs-realtime``",
24+
"description": "Adds support for Amazon IVS real-time streaming redundant ingest.",
25+
"type": "api-change"
26+
},
27+
{
28+
"category": "``marketplace-discovery``",
29+
"description": "AWS Marketplace Discovery API provides an interface that enables programmatic access to the AWS Marketplace catalog, including searching and browsing listings, retrieving product details and fulfillment options, and accessing public and private offer pricing and terms.",
30+
"type": "api-change"
31+
},
32+
{
33+
"category": "``medialive``",
34+
"description": "MediaLive is adding support for MediaConnect Router by supporting a new output type called MEDIACONNECT ROUTER. This new output type will provide seamless encrypted transport between your MediaLive channel and MediaConnect Router.",
35+
"type": "api-change"
36+
},
37+
{
38+
"category": "``outposts``",
39+
"description": "Add AWS Outposts APIs to view renewal pricing options and submit renewal requests for Outpost contracts",
40+
"type": "api-change"
41+
},
42+
{
43+
"category": "CodeArtifact",
44+
"description": "Tighten file permissions when writing credentials in CodeArtifact login",
45+
"type": "bugfix"
46+
},
47+
{
48+
"category": "``iam``",
49+
"description": "Tighten file permissions for virtual MFA bootstrap output",
50+
"type": "bugfix"
51+
}
52+
]

CHANGELOG.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,21 @@
22
CHANGELOG
33
=========
44

5+
1.44.76
6+
=======
7+
8+
* api-change:``backup``: Adding EKS specific backup vault notification types for AWS Backup.
9+
* api-change:``drs``: This changes adds support for modifying the replication configuration to support data replication using IPv6.
10+
* api-change:``ecr``: Add UnableToListUpstreamImageReferrersException in ListImageReferrers
11+
* api-change:``endpoint-rules``: Update endpoint-rules command to latest version
12+
* api-change:``ivs-realtime``: Adds support for Amazon IVS real-time streaming redundant ingest.
13+
* api-change:``marketplace-discovery``: AWS Marketplace Discovery API provides an interface that enables programmatic access to the AWS Marketplace catalog, including searching and browsing listings, retrieving product details and fulfillment options, and accessing public and private offer pricing and terms.
14+
* api-change:``medialive``: MediaLive is adding support for MediaConnect Router by supporting a new output type called MEDIACONNECT ROUTER. This new output type will provide seamless encrypted transport between your MediaLive channel and MediaConnect Router.
15+
* api-change:``outposts``: Add AWS Outposts APIs to view renewal pricing options and submit renewal requests for Outpost contracts
16+
* bugfix:CodeArtifact: Tighten file permissions when writing credentials in CodeArtifact login
17+
* bugfix:``iam``: Tighten file permissions for virtual MFA bootstrap output
18+
19+
520
1.44.75
621
=======
722

awscli/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import os
2020

21-
__version__ = '1.44.75'
21+
__version__ = '1.44.76'
2222

2323
#
2424
# Get our data path to be added to botocore's search path

awscli/customizations/codeartifact/login.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,17 @@ def _update_netrc_entry(self, hostname, new_entry, netrc_path):
183183
if new_contents == contents:
184184
new_contents = self._append_netrc_entry(new_contents, new_entry)
185185

186-
with open(netrc_path, 'w') as f:
186+
fd = os.open(netrc_path,
187+
os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
188+
189+
try:
190+
os.chmod(netrc_path, 0o600) # Ensure secure perms on pre-existing files
191+
except OSError as e:
192+
uni_print('Unable to set file permissions '
193+
'for %s: %s%s' % (netrc_path, e, os.linesep),
194+
sys.stderr)
195+
196+
with os.fdopen(fd, 'w') as f:
187197
f.write(new_contents)
188198

189199
def _create_netrc_file(self, netrc_path, new_entry):
@@ -631,7 +641,17 @@ def login(self, dry_run=False):
631641
sys.stdout.write(pypi_rc_str)
632642
sys.stdout.write(os.linesep)
633643
else:
634-
with open(self.pypi_rc_path, 'w+') as fp:
644+
fd = os.open(self.pypi_rc_path,
645+
os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
646+
647+
try:
648+
os.chmod(self.pypi_rc_path, 0o600) # Ensure secure perms on pre-existing files
649+
except OSError as e:
650+
uni_print('Unable to set file permissions '
651+
'for %s: %s%s' % (self.pypi_rc_path, e, os.linesep),
652+
sys.stderr)
653+
654+
with os.fdopen(fd, 'w') as fp:
635655
fp.write(pypi_rc_str)
636656

637657
self._write_success_message('twine')

awscli/customizations/iamvirtmfa.py

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,43 +22,55 @@
2222
to the specified file. It will also remove the two bootstrap data
2323
fields from the response.
2424
"""
25-
import base64
2625

27-
from awscli.customizations.arguments import StatefulArgument
28-
from awscli.customizations.arguments import resolve_given_outfile_path
29-
from awscli.customizations.arguments import is_parsed_result_successful
26+
import base64
27+
import os
3028

29+
from awscli.compat import compat_open
30+
from awscli.customizations.arguments import (
31+
StatefulArgument,
32+
is_parsed_result_successful,
33+
resolve_given_outfile_path,
34+
)
3135

3236
CHOICES = ('QRCodePNG', 'Base32StringSeed')
33-
OUTPUT_HELP = ('The output path and file name where the bootstrap '
34-
'information will be stored.')
35-
BOOTSTRAP_HELP = ('Method to use to seed the virtual MFA. '
36-
'Valid values are: %s | %s' % CHOICES)
37+
OUTPUT_HELP = (
38+
'The output path and file name where the bootstrap '
39+
'information will be stored.'
40+
)
41+
BOOTSTRAP_HELP = (
42+
'Method to use to seed the virtual MFA. '
43+
'Valid values are: %s | %s' % CHOICES
44+
)
3745

3846

3947
class FileArgument(StatefulArgument):
40-
4148
def add_to_params(self, parameters, value):
4249
# Validate the file here so we can raise an error prior
4350
# calling the service.
4451
value = resolve_given_outfile_path(value)
4552
super(FileArgument, self).add_to_params(parameters, value)
4653

4754

48-
class IAMVMFAWrapper(object):
49-
55+
class IAMVMFAWrapper:
5056
def __init__(self, event_handler):
5157
self._event_handler = event_handler
5258
self._outfile = FileArgument(
53-
'outfile', help_text=OUTPUT_HELP, required=True)
59+
'outfile', help_text=OUTPUT_HELP, required=True
60+
)
5461
self._method = StatefulArgument(
55-
'bootstrap-method', help_text=BOOTSTRAP_HELP,
56-
choices=CHOICES, required=True)
62+
'bootstrap-method',
63+
help_text=BOOTSTRAP_HELP,
64+
choices=CHOICES,
65+
required=True,
66+
)
5767
self._event_handler.register(
5868
'building-argument-table.iam.create-virtual-mfa-device',
59-
self._add_options)
69+
self._add_options,
70+
)
6071
self._event_handler.register(
61-
'after-call.iam.CreateVirtualMFADevice', self._save_file)
72+
'after-call.iam.CreateVirtualMFADevice', self._save_file
73+
)
6274

6375
def _add_options(self, argument_table, **kwargs):
6476
argument_table['outfile'] = self._outfile
@@ -71,7 +83,9 @@ def _save_file(self, parsed, **kwargs):
7183
outfile = self._outfile.value
7284
if method in parsed['VirtualMFADevice']:
7385
body = parsed['VirtualMFADevice'][method]
74-
with open(outfile, 'wb') as fp:
86+
with compat_open(outfile, 'wb', access_permissions=0o600) as fp:
87+
if hasattr(os, 'fchmod'):
88+
os.fchmod(fp.fileno(), 0o600)
7589
fp.write(base64.b64decode(body))
7690
for choice in CHOICES:
7791
if choice in parsed['VirtualMFADevice']:

doc/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
# The short X.Y version.
5353
version = '1.44.'
5454
# The full version, including alpha/beta/rc tags.
55-
release = '1.44.75'
55+
release = '1.44.76'
5656

5757
# The language for content autogenerated by Sphinx. Refer to documentation
5858
# for a list of supported languages.

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ universal = 0
33

44
[metadata]
55
requires_dist =
6-
botocore==1.42.85
6+
botocore==1.42.86
77
docutils>=0.18.1,<=0.19
88
s3transfer>=0.16.0,<0.17.0
99
PyYAML>=3.10,<6.1

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def find_version(*file_paths):
2424

2525

2626
install_requires = [
27-
'botocore==1.42.85',
27+
'botocore==1.42.86',
2828
'docutils>=0.18.1,<=0.19',
2929
's3transfer>=0.16.0,<0.17.0',
3030
'PyYAML>=3.10,<6.1',

tests/functional/iam/test_create_virtual_mfa_device.py

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,26 @@
1111
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
1212
# ANY KIND, either express or implied. See the License for the specific
1313
# language governing permissions and limitations under the License.
14-
from awscli.testutils import BaseAWSCommandParamsTest
1514
import os
1615

16+
from awscli.testutils import BaseAWSCommandParamsTest, skip_if_windows
1717

18-
class TestCreateVirtualMFADevice(BaseAWSCommandParamsTest):
1918

19+
class TestCreateVirtualMFADevice(BaseAWSCommandParamsTest):
2020
prefix = 'iam create-virtual-mfa-device'
2121

2222
def setUp(self):
2323
super(TestCreateVirtualMFADevice, self).setUp()
2424
self.parsed_response = {
2525
'ResponseMetadata': {
2626
'HTTPStatusCode': 200,
27-
'RequestId': 'requset-id'
27+
'RequestId': 'requset-id',
2828
},
2929
"VirtualMFADevice": {
3030
"Base32StringSeed": (
3131
"VFpYTVc2V1lIUFlFRFczSVhLUlpRUTJRVFdUSFRNRDNTQ0c3"
32-
"TkZDUVdQWDVETlNWM0IyUENaQVpWTEpQTlBOTA=="),
32+
"TkZDUVdQWDVETlNWM0IyUENaQVpWTEpQTlBOTA=="
33+
),
3334
"SerialNumber": "arn:aws:iam::419278470775:mfa/fiebaz",
3435
"QRCodePNG": (
3536
"iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6CAIAAAAHjs1qAAAFi"
@@ -74,12 +75,13 @@ def setUp(self):
7475
"R3EVwF8FdBHcR3EVwF8Fd5F/+AgASajf850wfAAAAAElFTkSu"
7576
"QmCC"
7677
),
77-
}
78+
},
7879
}
7980

8081
def getpath(self, filename):
81-
return os.path.join(os.path.abspath(os.path.dirname(__file__)),
82-
filename)
82+
return os.path.join(
83+
os.path.abspath(os.path.dirname(__file__)), filename
84+
)
8385

8486
def remove_file_if_exists(self, filename):
8587
if os.path.isfile(filename):
@@ -91,7 +93,8 @@ def test_base32(self):
9193
cmdline = self.prefix
9294
cmdline += ' --virtual-mfa-device-name fiebaz'
9395
cmdline += (
94-
' --outfile %s --bootstrap-method Base32StringSeed' % outfile)
96+
' --outfile %s --bootstrap-method Base32StringSeed' % outfile
97+
)
9598
result = {"VirtualMFADeviceName": 'fiebaz'}
9699
self.assert_params_for_cmd(cmdline, result)
97100
self.assertTrue(os.path.exists(outfile))
@@ -145,7 +148,8 @@ def test_bad_response(self):
145148
},
146149
'ResponseMetadata': {
147150
'HTTPStatusCode': 409,
148-
'RequestId': 'requset-id'}
151+
'RequestId': 'requset-id',
152+
},
149153
}
150154
self.http_response.status_code = 409
151155
cmdline = self.prefix
@@ -155,4 +159,34 @@ def test_bad_response(self):
155159
self.assert_params_for_cmd(
156160
cmdline,
157161
stderr_contains=self.parsed_response['Error']['Message'],
158-
expected_rc=255)
162+
expected_rc=255,
163+
)
164+
165+
@skip_if_windows("Permissions test not valid on Windows.")
166+
def test_output_file_permissions(self):
167+
outfile = self.getpath('fiebaz_perms.b32')
168+
self.addCleanup(self.remove_file_if_exists, outfile)
169+
cmdline = self.prefix
170+
cmdline += ' --virtual-mfa-device-name fiebaz'
171+
cmdline += (
172+
' --outfile %s --bootstrap-method Base32StringSeed' % outfile
173+
)
174+
result = {"VirtualMFADeviceName": 'fiebaz'}
175+
self.assert_params_for_cmd(cmdline, result)
176+
self.assertEqual(os.stat(outfile).st_mode & 0xFFF, 0o600)
177+
178+
@skip_if_windows("Permissions test not valid on Windows.")
179+
def test_output_file_permissions_existing_file(self):
180+
outfile = self.getpath('fiebaz_perms_existing.b32')
181+
self.addCleanup(self.remove_file_if_exists, outfile)
182+
with open(outfile, 'wb') as f:
183+
f.write(b'existing')
184+
os.chmod(outfile, 0o644)
185+
cmdline = self.prefix
186+
cmdline += ' --virtual-mfa-device-name fiebaz'
187+
cmdline += (
188+
' --outfile %s --bootstrap-method Base32StringSeed' % outfile
189+
)
190+
result = {"VirtualMFADeviceName": 'fiebaz'}
191+
self.assert_params_for_cmd(cmdline, result)
192+
self.assertEqual(os.stat(outfile).st_mode & 0xFFF, 0o600)

tests/integration/customizations/s3/test_plugin.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,21 @@ def setup_module():
8787
s3.delete_public_access_block(
8888
Bucket=_SHARED_BUCKET
8989
)
90+
s3.put_bucket_encryption(
91+
Bucket=_SHARED_BUCKET,
92+
ServerSideEncryptionConfiguration={
93+
'Rules': [
94+
{
95+
'ApplyServerSideEncryptionByDefault': {
96+
'SSEAlgorithm': 'AES256',
97+
},
98+
'BlockedEncryptionTypes': {
99+
'EncryptionType': ['NONE'],
100+
},
101+
}
102+
],
103+
},
104+
)
90105

91106
# Validate that "_NON_EXISTENT_BUCKET" doesn't exist.
92107
waiter = s3.get_waiter('bucket_not_exists')

0 commit comments

Comments
 (0)