Skip to content

Commit d8cc92f

Browse files
Merge branch 'release-1.40.0'
* release-1.40.0: Bumping version to 1.40.0 Update changelog based on model updates Add assume-role-arn option to update-kubeconfig command for cross-account access (#9443)
2 parents 7c5cdbc + ff979aa commit d8cc92f

File tree

9 files changed

+156
-27
lines changed

9 files changed

+156
-27
lines changed

.changes/1.40.0.json

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[
2+
{
3+
"category": "``codebuild``",
4+
"description": "Add support for custom instance type for reserved capacity fleets",
5+
"type": "api-change"
6+
},
7+
{
8+
"category": "``ecs``",
9+
"description": "Add support to roll back an In_Progress ECS Service Deployment",
10+
"type": "api-change"
11+
},
12+
{
13+
"category": "``resource-explorer-2``",
14+
"description": "Documentation-only update for CreateView option correction",
15+
"type": "api-change"
16+
},
17+
{
18+
"category": "``eks``",
19+
"description": "Add assume-role-arn option to update-kubeconfig command for cross-account access",
20+
"type": "feature"
21+
}
22+
]

CHANGELOG.rst

+9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
CHANGELOG
33
=========
44

5+
1.40.0
6+
======
7+
8+
* api-change:``codebuild``: Add support for custom instance type for reserved capacity fleets
9+
* api-change:``ecs``: Add support to roll back an In_Progress ECS Service Deployment
10+
* api-change:``resource-explorer-2``: Documentation-only update for CreateView option correction
11+
* feature:``eks``: Add assume-role-arn option to update-kubeconfig command for cross-account access
12+
13+
514
1.39.0
615
======
716

awscli/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import os
2020

21-
__version__ = '1.39.0'
21+
__version__ = '1.40.0'
2222

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

awscli/customizations/eks/update_kubeconfig.py

+44-21
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,14 @@ class UpdateKubeconfigCommand(BasicCommand):
103103
'help_text': ("Alias for the generated user name. "
104104
"Defaults to match cluster ARN."),
105105
'required': False
106+
},
107+
{
108+
'name': 'assume-role-arn',
109+
'help_text': ('To assume a role for retrieving cluster information, '
110+
'specify an IAM role ARN with this option. '
111+
'Use this for cross-account access to get cluster details '
112+
'from the account where the cluster resides.'),
113+
'required': False
106114
}
107115
]
108116

@@ -249,27 +257,42 @@ def cluster_description(self):
249257
Cache the response in self._cluster_description.
250258
describe-cluster will only be called once.
251259
"""
252-
if self._cluster_description is None:
253-
if self._parsed_globals is None:
254-
client = self._session.create_client("eks")
255-
else:
256-
client = self._session.create_client(
257-
"eks",
258-
region_name=self._parsed_globals.region,
259-
endpoint_url=self._parsed_globals.endpoint_url,
260-
verify=self._parsed_globals.verify_ssl
261-
)
262-
full_description = client.describe_cluster(name=self._cluster_name)
263-
self._cluster_description = full_description["cluster"]
264-
265-
if "status" not in self._cluster_description:
266-
raise EKSClusterError("Cluster not found")
267-
if self._cluster_description["status"] not in ["ACTIVE", "UPDATING"]:
268-
raise EKSClusterError("Cluster status is {0}".format(
269-
self._cluster_description["status"]
270-
))
271-
272-
return self._cluster_description
260+
if self._cluster_description is not None:
261+
return self._cluster_description
262+
263+
client_kwargs = {}
264+
if self._parsed_globals:
265+
client_kwargs.update({
266+
"region_name": self._parsed_globals.region,
267+
"endpoint_url": self._parsed_globals.endpoint_url,
268+
"verify": self._parsed_globals.verify_ssl,
269+
})
270+
271+
# Handle role assumption if needed
272+
if getattr(self._parsed_args, 'assume_role_arn', None):
273+
sts_client = self._session.create_client('sts')
274+
credentials = sts_client.assume_role(
275+
RoleArn=self._parsed_args.assume_role_arn,
276+
RoleSessionName='EKSDescribeClusterSession'
277+
)["Credentials"]
278+
279+
client_kwargs.update({
280+
"aws_access_key_id": credentials["AccessKeyId"],
281+
"aws_secret_access_key": credentials["SecretAccessKey"],
282+
"aws_session_token": credentials["SessionToken"],
283+
})
284+
285+
client = self._session.create_client("eks", **client_kwargs)
286+
full_description = client.describe_cluster(name=self._cluster_name)
287+
cluster = full_description.get("cluster")
288+
289+
if not cluster or "status" not in cluster:
290+
raise EKSClusterError("Cluster not found")
291+
if cluster["status"] not in ["ACTIVE", "UPDATING"]:
292+
raise EKSClusterError(f"Cluster status is {cluster['status']}")
293+
294+
self._cluster_description = cluster
295+
return cluster
273296

274297
def get_cluster_entry(self):
275298
"""

doc/source/conf.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@
5050
# built documents.
5151
#
5252
# The short X.Y version.
53-
version = '1.39'
53+
version = '1.40'
5454
# The full version, including alpha/beta/rc tags.
55-
release = '1.39.0'
55+
release = '1.40.0'
5656

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

setup.cfg

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ universal = 0
33

44
[metadata]
55
requires_dist =
6-
botocore==1.38.0
6+
botocore==1.38.1
77
docutils>=0.18.1,<=0.19
88
s3transfer>=0.12.0,<0.13.0
99
PyYAML>=3.10,<6.1

setup.py

+1-1
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.38.0',
27+
'botocore==1.38.1',
2828
'docutils>=0.18.1,<=0.19',
2929
's3transfer>=0.12.0,<0.13.0',
3030
'PyYAML>=3.10,<6.1',

tests/functional/eks/test_update_kubeconfig.py

+67-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
KubeconfigInaccessableError)
3333
from tests.functional.eks.test_util import (describe_cluster_response,
3434
describe_cluster_creating_response,
35-
get_testdata)
35+
get_testdata,
36+
assume_role_response)
3637

3738
def sanitize_output(output):
3839
"""
@@ -66,6 +67,15 @@ def setUp(self):
6667
self.client.describe_cluster.return_value = describe_cluster_response()
6768
self.mock_create_client.return_value = self.client
6869

70+
# Set up the sts_client_mock
71+
self.sts_client_mock = mock.Mock()
72+
self.sts_client_mock.assume_role.return_value = assume_role_response()
73+
74+
# Ensure the mock_create_client correctly returns the appropriate mock
75+
self.mock_create_client.side_effect = lambda service_name, **kwargs: (
76+
self.sts_client_mock if service_name == "sts" else self.client
77+
)
78+
6979
self.command = UpdateKubeconfigCommand(self.session)
7080
self.maxDiff = None
7181

@@ -422,3 +432,59 @@ def test_update_old_api_version(self):
422432

423433
self.assert_cmd(configs, passed, environment)
424434
self.assert_config_state("valid_old_api_version", "valid_old_api_version_updated")
435+
436+
def test_assume_role(self):
437+
"""
438+
Test that assume_role_arn is handled correctly when provided.
439+
"""
440+
configs = ["valid_existing"]
441+
self.initialize_tempfiles(configs)
442+
443+
# Include the --assume-role-arn argument
444+
args = [
445+
"--name", "ExampleCluster",
446+
"--assume-role-arn", "arn:aws:iam::123456789012:role/test-role"
447+
]
448+
449+
# Mock environment variables and paths
450+
kubeconfig_path = self._get_temp_config("valid_existing")
451+
default_path = self._get_temp_config("default_temp")
452+
453+
with mock.patch.dict(os.environ, {'KUBECONFIG': kubeconfig_path}):
454+
with mock.patch("awscli.customizations.eks.update_kubeconfig.DEFAULT_PATH", default_path):
455+
self.command(args, None)
456+
457+
# Verify that assume_role was called with the correct parameters
458+
self.sts_client_mock.assume_role.assert_called_once_with(
459+
RoleArn="arn:aws:iam::123456789012:role/test-role",
460+
RoleSessionName="EKSDescribeClusterSession"
461+
)
462+
463+
# Verify that the EKS client was created with the assumed credentials
464+
self.mock_create_client.assert_any_call(
465+
"eks",
466+
aws_access_key_id="test-access-key",
467+
aws_secret_access_key="test-secret-key",
468+
aws_session_token="test-session-token"
469+
)
470+
471+
# Verify that the cluster was described
472+
self.client.describe_cluster.assert_called_once_with(name="ExampleCluster")
473+
474+
# Assert the configuration state
475+
self.assert_config_state("valid_existing", "output_combined")
476+
477+
def test_no_assume_role(self):
478+
"""
479+
Test that assume_role_arn is not used when not provided.
480+
"""
481+
configs = ["valid_existing"]
482+
passed = "valid_existing"
483+
environment = []
484+
485+
self.client.describe_cluster = mock.Mock(return_value=describe_cluster_response())
486+
self.assert_cmd(configs, passed, environment)
487+
488+
# Verify that assume_role was not called
489+
self.mock_create_client.assert_called_once_with("eks")
490+
self.client.describe_cluster.assert_called_once_with(name="ExampleCluster")

tests/functional/eks/test_util.py

+9
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,12 @@ def describe_cluster_deleting_response():
176176
"createdAt": 1500000000.000
177177
}
178178
}
179+
180+
def assume_role_response():
181+
return {
182+
"Credentials": {
183+
"AccessKeyId": "test-access-key",
184+
"SecretAccessKey": "test-secret-key",
185+
"SessionToken": "test-session-token"
186+
}
187+
}

0 commit comments

Comments
 (0)