Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ To release a new version, please select a new version number (usually plus 1 to
Pending
+++++++

22.0.0b1
++++++++
* [BREAKING CHANGE]: `az aks bastion`: This command does not connect to Azure Bastion anymore. A new subcommand is introduced for this purpose: `az aks bastion tunnel`. The `az aks bastion` command is now used to manage Azure Bastion resources for AKS clusters.
* `az aks bastion tunnel`: Connect to Azure Bastion for AKS clusters. All the parameters from old `az aks bastion` are supported.
* `az aks bastion enable`: Enable managed Azure Bastion for AKS clusters.
* `az aks bastion disable`: Disable managed Azure Bastion for AKS clusters.
* `az aks bastion update`: Update managed Azure Bastion for AKS clusters.

21.0.0b17
+++++++++
* `az aks update`: Add parameters `--enable-hosted-system`, `--system-node-subnet-id` and `--node-subnet-id` to support converting an existing Automatic cluster to a Managed System Pool cluster, optionally with BYO VNet.
Expand Down
4 changes: 4 additions & 0 deletions src/aks-preview/azext_aks_preview/_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@
CONST_LOAD_BALANCER_SKU_BASIC = "basic"
CONST_LOAD_BALANCER_SKU_STANDARD = "standard"

# bastion sku
CONST_BASTION_SKU_STANDARD = "Standard"
CONST_BASTION_SKU_PREMIUM = "Premium"

# ManagedClusterSKU Tier
CONST_MANAGED_CLUSTER_SKU_TIER_FREE = "free"
CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD = "standard"
Expand Down
73 changes: 71 additions & 2 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -4829,6 +4829,75 @@
"""

helps['aks bastion'] = """
type: group
short-summary: Commands to manage or connect to Azure Bastion for a managed Kubernetes cluster.
"""

helps['aks bastion enable'] = """
type: command
short-summary: Enable managed Azure Bastion host for a managed Kubernetes cluster.
parameters:
- name: --aks-custom-headers
type: string
short-summary: Send custom headers. When specified, format should be Key1=Value1,Key2=Value2
- name: --bastion-sku -s
type: string
short-summary: Specify the SKU of the managed Azure Bastion host.
- name: --bastion-public-ip
type: string
short-summary: The resource ID of an existing public IP address to be assigned to the managed Azure Bastion host.
long-summary: When not specified, a new public IP address will be created and assigned to the managed Azure Bastion host.
- name: --bastion-scale-units
type: int
short-summary: The number of scale units for the managed Azure Bastion host.
examples:
- name: Enable managed Azure Bastion host for a managed Kubernetes cluster with default settings.
text: az aks bastion enable --name MyManagedCluster --resource-group MyResourceGroup
crafted: true
- name: Enable managed Azure Bastion host with premium sku and custom scale units.
text: az aks bastion enable --name MyManagedCluster --resource-group MyResourceGroup --bastion-sku premium --bastion-scale-units 7
crafted: true
- name: Enable managed Azure Bastion host with BYO public IP address.
text: az aks bastion enable --name MyManagedCluster --resource-group MyResourceGroup --bastion-public-ip /subscriptions/{subscription-id}/resourceGroups/MyResourceGroup/providers/Microsoft.Network/publicIPAddresses/MyPublicIP
crafted: true
"""

helps['aks bastion disable'] = """
type: command
short-summary: Disable managed Azure Bastion host for a managed Kubernetes cluster.
parameters:
- name: --aks-custom-headers
type: string
short-summary: Send custom headers. When specified, format should be Key1=Value1,Key2=Value2
examples:
- name: Disable managed Azure Bastion host for a managed Kubernetes cluster.
text: az aks bastion disable --name MyManagedCluster --resource-group MyResourceGroup
crafted: true
"""

helps['aks bastion update'] = """
type: command
short-summary: Update managed Azure Bastion host for a managed Kubernetes cluster.
parameters:
- name: --aks-custom-headers
type: string
short-summary: Send custom headers. When specified, format should be Key1=Value1,Key2=Value2
- name: --bastion-sku -s
type: string
short-summary: Specify the SKU of the managed Azure Bastion host.
- name: --bastion-scale-units
type: int
short-summary: The number of scale units for the managed Azure Bastion host.
examples:
- name: Upgrade managed Azure Bastion host to Premium SKU.
text: az aks bastion update --name MyManagedCluster --resource-group MyResourceGroup --bastion-sku premium
crafted: true
- name: Scale managed Azure Bastion host.
text: az aks bastion update --name MyManagedCluster --resource-group MyResourceGroup --bastion-scale-units 7
crafted: true
"""

helps['aks bastion tunnel'] = """
type: command
short-summary: Connect to a managed Kubernetes cluster using Azure Bastion.
long-summary: The command will launch a subshell with the kubeconfig set to connect to the cluster via Bastion. Use exit or Ctrl-D (i.e. EOF) to exit the subshell.
Expand All @@ -4850,9 +4919,9 @@
long-summary: If specified, uses this kubeconfig file at its original location instead of fetching credentials from Azure.
examples:
- name: Connect to a managed Kubernetes cluster using Azure Bastion with custom port and admin credentials.
text: az aks bastion -g MyResourceGroup --name MyManagedCluster --bastion MyBastionResource --port 50001 --admin
text: az aks bastion tunnel -g MyResourceGroup --name MyManagedCluster --bastion MyBastionResource --port 50001 --admin
- name: Connect using an existing kubeconfig file.
text: az aks bastion -g MyResourceGroup --name MyManagedCluster --kubeconfig-path ~/.kube/config
text: az aks bastion tunnel -g MyResourceGroup --name MyManagedCluster --kubeconfig-path ~/.kube/config
"""

helps['aks identity-binding'] = """
Expand Down
36 changes: 35 additions & 1 deletion src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@
CONST_GPU_INSTANCE_PROFILE_MIG7_G,
CONST_LOAD_BALANCER_SKU_BASIC,
CONST_LOAD_BALANCER_SKU_STANDARD,
CONST_BASTION_SKU_STANDARD,
CONST_BASTION_SKU_PREMIUM,
CONST_MANAGED_CLUSTER_SKU_TIER_FREE,
CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD,
CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM,
Expand Down Expand Up @@ -216,6 +218,7 @@
validate_message_of_the_day,
validate_node_public_ip_prefix_ids,
validate_node_public_ip_tags,
validate_bastion_public_ip_id,
validate_nodepool_id,
validate_nodepool_labels,
validate_nodepool_taints,
Expand Down Expand Up @@ -601,6 +604,11 @@ def _deprecate_option(c, target, redirect):
CONST_UPGRADE_STRATEGY_BLUE_GREEN,
]

bastion_skus = [
CONST_BASTION_SKU_STANDARD,
CONST_BASTION_SKU_PREMIUM,
]

# AKS backup strategy presets exposed by --backup-strategy.
# NOTE: must mirror CONST_AKS_BACKUP_STRATEGIES in azext_dataprotection.manual._consts.
aks_backup_strategies = ["Week", "Month", "DisasterRecovery", "Custom"]
Expand Down Expand Up @@ -3750,7 +3758,33 @@ def load_arguments(self, _):
help="Name of the load balancer configuration. Required.",
)

with self.argument_context("aks bastion") as c:
for scope in ['aks bastion enable',
'aks bastion update']:
with self.argument_context(scope) as c:
c.argument(
"bastion_sku",
options_list=["--bastion-sku", "-s"],
arg_type=get_enum_type(bastion_skus),
help="set bastion sku for Azure Bastion host",
)
c.argument(
"bastion_scale_units",
options_list=["--bastion-scale-units"],
type=int,
help="Scale units for the Azure Bastion host.",
)
c.argument("aks_custom_headers")

for scope in ['aks bastion enable']:
with self.argument_context(scope) as c:
c.argument(
"bastion_public_ip",
options_list=["--bastion-public-ip"],
validator=validate_bastion_public_ip_id,
help="Optional public IP address for the Azure Bastion host.",
)

with self.argument_context("aks bastion tunnel") as c:
c.argument("bastion")
c.argument("port", type=int)
c.argument("admin", action="store_true")
Expand Down
8 changes: 8 additions & 0 deletions src/aks-preview/azext_aks_preview/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,14 @@ def validate_node_public_ip_prefix_ids(ns):
)


def validate_bastion_public_ip_id(namespace):
if namespace.bastion_public_ip is None or namespace.bastion_public_ip == '':
return
if not is_valid_resource_id(namespace.bastion_public_ip):
raise InvalidArgumentValueError(
"--bastion-public-ip is not a valid Azure resource ID.")


def validate_nodepool_labels(namespace):
"""Validates that provided node labels is a valid format"""

Expand Down
10 changes: 9 additions & 1 deletion src/aks-preview/azext_aks_preview/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ def load_command_table(self, _):
g.custom_command(
"operation-abort", "aks_operation_abort", supports_no_wait=True
)
g.custom_command("bastion", "aks_bastion")

# AKS maintenance configuration commands
with self.command_group(
Expand Down Expand Up @@ -619,6 +618,15 @@ def load_command_table(self, _):
g.custom_show_command("show", "aks_identity_binding_show")
g.custom_command("list", "aks_identity_binding_list")

# AKS bastion
with self.command_group(
"aks bastion", managed_clusters_sdk, client_factory=cf_managed_clusters
) as g:
g.custom_command("enable", "aks_bastion_enable", supports_no_wait=True)
g.custom_command("disable", "aks_bastion_disable", supports_no_wait=True)
g.custom_command("update", "aks_bastion_update", supports_no_wait=True)
g.custom_command("tunnel", "aks_bastion_tunnel")

# AKS jwt authenticator commands
with self.command_group(
"aks jwtauthenticator", jwt_authenticators_sdk, client_factory=cf_jwt_authenticators,
Expand Down
89 changes: 88 additions & 1 deletion src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -5972,7 +5972,88 @@ def aks_loadbalancer_rebalance_nodes(
return aks_loadbalancer_rebalance_internal(managed_clusters_client, parameters)


def aks_bastion(cmd, client, resource_group_name, name, bastion=None, port=None, admin=False, kubeconfig_path=None, yes=False):
def aks_bastion_enable(
cmd,
client,
resource_group_name,
name,
no_wait=False,
aks_custom_headers=None,
bastion_sku=None,
bastion_public_ip=None,
bastion_scale_units=None,
):
from azext_aks_preview.managedbastion import (
update_managed_bastion_profile,
)
headers = get_aks_custom_headers(aks_custom_headers)
return update_managed_bastion_profile(
cmd,
client,
resource_group_name,
name,
no_wait=no_wait,
aks_custom_headers=headers,
enabled=True,
enabling=True,
bastion_sku=bastion_sku,
bastion_public_ip=bastion_public_ip,
bastion_scale_units=bastion_scale_units,
)


def aks_bastion_disable(
cmd,
client,
resource_group_name,
name,
no_wait=False,
aks_custom_headers=None,
):
from azext_aks_preview.managedbastion import (
update_managed_bastion_profile,
)
headers = get_aks_custom_headers(aks_custom_headers)
return update_managed_bastion_profile(
cmd,
client,
resource_group_name,
name,
no_wait=no_wait,
aks_custom_headers=headers,
enabled=False
)


def aks_bastion_update(
cmd,
client,
resource_group_name,
name,
no_wait=False,
aks_custom_headers=None,
bastion_sku=None,
bastion_scale_units=None,
):
from azext_aks_preview.managedbastion import (
update_managed_bastion_profile,
)
headers = get_aks_custom_headers(aks_custom_headers)
return update_managed_bastion_profile(
cmd,
client,
resource_group_name,
name,
no_wait=no_wait,
aks_custom_headers=headers,
enabled=True,
require_enabled=True,
bastion_sku=bastion_sku,
bastion_scale_units=bastion_scale_units,
)


def aks_bastion_tunnel(cmd, client, resource_group_name, name, bastion=None, port=None, admin=False, kubeconfig_path=None, yes=False):
import asyncio
import tempfile

Expand Down Expand Up @@ -6000,6 +6081,12 @@ def aks_bastion(cmd, client, resource_group_name, name, bastion=None, port=None,
mc = client.get(resource_group_name, name)
mc_id = mc.id
nrg = mc.node_resource_group

# Use managed bastion if not explicitly provided
if not bastion and mc.network_profile and mc.network_profile.bastion_profile and mc.network_profile.bastion_profile.enabled:
logger.info("using managed bastion with id: %s", mc.network_profile.bastion_profile.bastion_id)
bastion = mc.network_profile.bastion_profile.bastion_id

bastion_resource = aks_bastion_parse_bastion_resource(bastion, [nrg], subscription_id)
port = aks_bastion_get_local_port(port)

Expand Down
70 changes: 70 additions & 0 deletions src/aks-preview/azext_aks_preview/managedbastion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from knack.util import CLIError
from azure.cli.core.util import sdk_no_wait
from azext_aks_preview._client_factory import CUSTOM_MGMT_AKS_PREVIEW


def update_managed_bastion_profile(
cmd,
client,
resource_group_name,
name,
no_wait=False,
aks_custom_headers=None,
enabled=False,
require_enabled=False,
enabling=False,
bastion_sku=None,
bastion_public_ip=None,
bastion_scale_units=None
):
instance = client.get(resource_group_name, name, headers=aks_custom_headers)

NetworkProfile = cmd.get_models(
"NetworkProfile",
resource_type=CUSTOM_MGMT_AKS_PREVIEW,
operation_group="managed_clusters",
)
BastionProfile = cmd.get_models(
"BastionProfile",
resource_type=CUSTOM_MGMT_AKS_PREVIEW,
operation_group="managed_clusters",
)

network_profile = instance.network_profile
if network_profile is None:
network_profile = NetworkProfile()

bastion_profile = network_profile.bastion_profile
if bastion_profile is None:
bastion_profile = BastionProfile()

if enabling and bastion_profile.enabled:
raise CLIError('Bastion is already enabled, please use "az aks bastion update" to update it.')
if require_enabled and not bastion_profile.enabled:
raise CLIError('Bastion is not enabled, please use "az aks bastion enable" to enable it first.')

bastion_profile.enabled = enabled
if bastion_sku is not None:
bastion_profile.sku = bastion_sku
if bastion_public_ip is not None:
bastion_profile.public_ip_address_id = bastion_public_ip
if bastion_scale_units is not None:
bastion_profile.scale_units = bastion_scale_units

network_profile.bastion_profile = bastion_profile
instance.network_profile = network_profile

result = sdk_no_wait(
no_wait,
client.begin_create_or_update,
resource_group_name,
name,
instance,
headers=aks_custom_headers)

return result
Loading
Loading