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
2 changes: 2 additions & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Pending
* `az aks create` and `az aks nodepool add`: Add `--enable-osdisk-full-caching` (preview) to enable the full-cache ephemeral OS disk feature for a node pool. Requires AFEC registration `Microsoft.ContainerService/FullCachePreview`. Property is immutable after node pool creation.
* Clean up unused disk driver version constants and remove obsolete CSI driver v2 tests following the removal of `--disk-driver-version` in 21.0.0b1.

* `az aks create/update`: Add `--enable-fips` (preview) to enable FIPS mode at the cluster level and `az aks update --disable-fips` to disable it. Requires Kubernetes version 1.34 or later and AFEC registration `Microsoft.ContainerService/EnableFIPSPreview`.

21.0.0b1
++++++
* [BREAKING CHANGE] `az aks create/update`: Remove `--disk-driver-version` option as the `version` field has been removed from the API spec for `ManagedClusterStorageProfileDiskCSIDriver`.
Expand Down
37 changes: 37 additions & 0 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,20 @@
- name: --enable-fips-image
type: bool
short-summary: Use FIPS-enabled OS on agent nodes.
- name: --enable-fips
type: bool
short-summary: Enable FIPS mode at the cluster level.
long-summary: |-
Enables FIPS compliance for all AKS-managed components, such as the node
operating system, addons, and managed containerized components
(https://aka.ms/aks/components/docs). See Enable cluster-wide FIPS
(https://aka.ms/aks/fips) for more details.
Requires Kubernetes version 1.34 or later and the
Microsoft.ContainerService/EnableFIPSPreview feature to be registered
on the subscription. All node pools must be FIPS-enabled; this command
enables FIPS on the default node pool during cluster creation. Some
addons and extensions aren't supported with cluster-wide FIPS. Verify
addon and extension compatibility before enabling this preview feature.
- name: --workspace-resource-id
type: string
short-summary: The resource ID of an existing Log Analytics Workspace to use for storing monitoring data. If not specified, uses the default Log Analytics Workspace if it exists, otherwise creates one.
Expand Down Expand Up @@ -1251,6 +1265,27 @@
- name: --disable-image-integrity
type: bool
short-summary: Disable ImageIntegrity Service.
- name: --enable-fips
type: bool
short-summary: Enable FIPS mode at the cluster level.
long-summary: |-
Enables FIPS compliance for all AKS-managed components, such as the node
operating system, addons, and managed containerized components
(https://aka.ms/aks/components/docs). See Enable cluster-wide FIPS
(https://aka.ms/aks/fips) for more details.
Requires Kubernetes version 1.34 or later and the
Microsoft.ContainerService/EnableFIPSPreview feature to be registered
on the subscription. Existing node pools must already be FIPS-enabled
before enabling this cluster-level setting, and future node pools must
also be created with FIPS enabled. Some addons and extensions aren't
supported with cluster-wide FIPS. Verify addon and extension
compatibility before enabling this preview feature.
- name: --disable-fips
type: bool
short-summary: Disable FIPS mode at the cluster level.
long-summary: |-
Disables cluster-wide FIPS enforcement for AKS-managed components.
This doesn't disable FIPS on existing node pools.
- name: --enable-service-account-image-pull
type: bool
short-summary: Enable service account based image pull. For more information, see https://aka.ms/aks/identity-binding/acr-image-pull/docs.
Expand Down Expand Up @@ -1505,6 +1540,8 @@
text: az aks update --enable-cluster-autoscaler --min-count 1 --max-count 5 -g MyResourceGroup -n MyManagedCluster
- name: Disable cluster-autoscaler for an existing cluster
text: az aks update --disable-cluster-autoscaler -g MyResourceGroup -n MyManagedCluster
- name: Disable FIPS mode at the cluster level.
text: az aks update -g MyResourceGroup -n MyManagedCluster --disable-fips
- name: Update min-count or max-count for cluster autoscaler.
text: az aks update --update-cluster-autoscaler --min-count 1 --max-count 10 -g MyResourceGroup -n MyManagedCluster
- name: Upgrade load balancer sku to standard
Expand Down
3 changes: 3 additions & 0 deletions src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,7 @@ def load_arguments(self, _):
c.argument("enable_encryption_at_host", action="store_true")
c.argument("enable_ultra_ssd", action="store_true")
c.argument("enable_fips_image", action="store_true")
c.argument("enable_fips", action="store_true", is_preview=True)
c.argument("kubelet_config")
c.argument("linux_os_config")
c.argument("host_group_id", validator=validate_host_group_id)
Expand Down Expand Up @@ -1549,6 +1550,8 @@ def load_arguments(self, _):
)
c.argument("image_cleaner_interval_hours", type=int)
c.argument("disable_image_integrity", action="store_true", is_preview=True)
c.argument("enable_fips", action="store_true", is_preview=True)
c.argument("disable_fips", action="store_true", is_preview=True)
c.argument("enable_service_account_image_pull", action="store_true", is_preview=True)
c.argument("disable_service_account_image_pull", action="store_true", is_preview=True)
c.argument("service_account_image_pull_default_managed_identity_id", is_preview=True)
Expand Down
3 changes: 3 additions & 0 deletions src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,7 @@ def aks_create(
enable_encryption_at_host=False,
enable_ultra_ssd=False,
enable_fips_image=False,
enable_fips=False,
kubelet_config=None,
linux_os_config=None,
host_group_id=None,
Expand Down Expand Up @@ -1343,6 +1344,8 @@ def aks_update(
image_cleaner_interval_hours=None,
enable_image_integrity=False,
disable_image_integrity=False,
enable_fips=False,
disable_fips=False,
enable_service_account_image_pull=False,
disable_service_account_image_pull=False,
service_account_image_pull_default_managed_identity_id=None,
Expand Down
95 changes: 95 additions & 0 deletions src/aks-preview/azext_aks_preview/managed_cluster_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -1821,6 +1821,61 @@ def get_kubernetes_version(self) -> str:
"""
return self._get_kubernetes_version(read_only=False)

def _validate_enable_fips_kubernetes_version(self) -> None:
kubernetes_version = self._get_kubernetes_version(read_only=True)
if not kubernetes_version:
return

version_parts = str(kubernetes_version).lstrip("v").split(".")
if len(version_parts) < 2:
return
try:
major = int(version_parts[0])
minor = int(version_parts[1].split("-")[0])
except ValueError:
return
if (major, minor) < (1, 34):
raise InvalidArgumentValueError("--enable-fips requires Kubernetes version 1.34 or later.")

def _get_enable_fips_from_mc(self) -> Optional[bool]:
if not self.mc:
return None
if hasattr(self.mc, "enable_fips") and self.mc.enable_fips is not None:
return self.mc.enable_fips
properties = getattr(self.mc, "properties", None)
if properties is not None:
return properties.get("enableFIPS")
return None

def get_enable_fips(self) -> bool:
"""Obtain the value of enable_fips.
:return: bool
"""
enable_fips = self.raw_param.get("enable_fips", False)
if enable_fips and self.get_disable_fips():
raise MutuallyExclusiveArgumentError(
"Cannot specify --enable-fips and --disable-fips at the same time."
)
if self.decorator_mode == DecoratorMode.CREATE:
value_obtained_from_mc = self._get_enable_fips_from_mc()
if value_obtained_from_mc is not None:
enable_fips = value_obtained_from_mc

if enable_fips:
self._validate_enable_fips_kubernetes_version()
return bool(enable_fips)

def get_disable_fips(self) -> bool:
"""Obtain the value of disable_fips.
:return: bool
"""
disable_fips = self.raw_param.get("disable_fips", False)
if disable_fips and self.raw_param.get("enable_fips", False):
raise MutuallyExclusiveArgumentError(
"Cannot specify --enable-fips and --disable-fips at the same time."
)
return bool(disable_fips)

def get_disk_driver(self) -> Optional[ManagedClusterStorageProfileDiskCSIDriver]:
"""Obtain the value of storage_profile.disk_csi_driver

Expand Down Expand Up @@ -4282,6 +4337,17 @@ def set_up_image_integrity(self, mc: ManagedCluster) -> ManagedCluster:

return mc

def set_up_enable_fips(self, mc: ManagedCluster) -> ManagedCluster:
"""Set up FIPS mode at the cluster level for the ManagedCluster object."""
self._ensure_mc(mc)

if self.context.get_enable_fips():
mc.enable_fips = True
if mc.agent_pool_profiles:
for agentpool in mc.agent_pool_profiles:
agentpool.enable_fips = True
return mc

def set_up_service_account_image_pull(self, mc: ManagedCluster) -> ManagedCluster:
"""Set up security profile serviceAccountImagePullProfile for the ManagedCluster object.

Expand Down Expand Up @@ -5174,6 +5240,8 @@ def construct_mc_profile_preview(self, bypass_restore_defaults: bool = False) ->
mc = self.set_up_image_cleaner(mc)
# set up image integrity
mc = self.set_up_image_integrity(mc)
# set up FIPS mode at the cluster level
mc = self.set_up_enable_fips(mc)
# set up service account image pull
mc = self.set_up_service_account_image_pull(mc)
# set up KMS infrastructure encryption
Expand Down Expand Up @@ -6684,6 +6752,31 @@ def update_image_integrity(self, mc: ManagedCluster) -> ManagedCluster:

return mc

def update_enable_fips(self, mc: ManagedCluster) -> ManagedCluster:
"""Update FIPS mode at the cluster level for the ManagedCluster object."""
self._ensure_mc(mc)

if self.context.get_disable_fips():
mc.enable_fips = False
return mc

if not self.context.get_enable_fips():
return mc

non_fips_nodepools = [
agentpool.name
for agentpool in (mc.agent_pool_profiles or [])
if agentpool.enable_fips is not True
]
if non_fips_nodepools:
raise InvalidArgumentValueError(
"--enable-fips requires all node pools in the cluster to be FIPS-enabled. "
"Enable FIPS on these node pools first: {}.".format(", ".join(non_fips_nodepools))
)

mc.enable_fips = True
return mc

def update_service_account_image_pull(self, mc: ManagedCluster) -> ManagedCluster:
"""Update security profile serviceAccountImagePullProfile for the ManagedCluster object.

Expand Down Expand Up @@ -8091,6 +8184,8 @@ def update_mc_profile_preview(self) -> ManagedCluster:
mc = self.update_image_cleaner(mc)
# update image integrity
mc = self.update_image_integrity(mc)
# update FIPS mode at the cluster level
mc = self.update_enable_fips(mc)
# update service account image pull
mc = self.update_service_account_image_pull(mc)
# update KMS infrastructure encryption
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7140,6 +7140,97 @@ def test_aks_create_with_fips(self, resource_group, resource_group_location):
checks=[self.is_empty()],
)

# FIPS mode at the cluster level is gated by EnableFIPSPreview AFEC and requires K8s 1.34+,
Comment thread
ttruongatl marked this conversation as resolved.
# so this scenario is live-only until the preview is broadly available.
@live_only()
@AllowLargeResponse()
@AKSCustomResourceGroupPreparer(
random_name_length=17, name_prefix="clitest", location="eastus2euap"
)
def test_aks_create_with_cluster_fips(
self, resource_group, resource_group_location
):
self.test_resources_count = 0
aks_name = self.create_random_name("cliakstest", 16)
self.kwargs.update(
{
"resource_group": resource_group,
"name": aks_name,
"location": resource_group_location,
"ssh_key_value": self.generate_ssh_keys(),
}
)

self.cmd(
"aks create --resource-group={resource_group} --name={name} "
"--location={location} --kubernetes-version 1.34 "
"--enable-fips --ssh-key-value={ssh_key_value}",
checks=[
self.check("provisioningState", "Succeeded"),
self.check("enableFips", True),
self.check("agentPoolProfiles[0].enableFips", True),
],
)

self.cmd(
"aks delete -g {resource_group} -n {name} --yes --no-wait",
checks=[self.is_empty()],
)

@live_only()
@AllowLargeResponse()
@AKSCustomResourceGroupPreparer(
random_name_length=17, name_prefix="clitest", location="eastus2euap"
)
def test_aks_update_with_cluster_fips(
self, resource_group, resource_group_location
):
self.test_resources_count = 0
aks_name = self.create_random_name("cliakstest", 16)
self.kwargs.update(
{
"resource_group": resource_group,
"name": aks_name,
"location": resource_group_location,
"ssh_key_value": self.generate_ssh_keys(),
}
)

self.cmd(
"aks create --resource-group={resource_group} --name={name} "
"--location={location} --kubernetes-version 1.34 "
"--enable-fips-image --ssh-key-value={ssh_key_value}",
checks=[
self.check("provisioningState", "Succeeded"),
self.check("agentPoolProfiles[0].enableFips", True),
],
)

self.cmd(
"aks update --resource-group={resource_group} --name={name} "
"--enable-fips",
checks=[
self.check("provisioningState", "Succeeded"),
self.check("enableFips", True),
self.check("agentPoolProfiles[0].enableFips", True),
],
)

self.cmd(
"aks update --resource-group={resource_group} --name={name} "
"--disable-fips",
checks=[
self.check("provisioningState", "Succeeded"),
self.check("enableFips", False),
self.check("agentPoolProfiles[0].enableFips", True),
],
)

self.cmd(
"aks delete -g {resource_group} -n {name} --yes --no-wait",
checks=[self.is_empty()],
)

# the availability of features is controlled by a toggle and cannot be fully tested yet,
# however, existing test results show that the client side works as expected, so exclude it at this moment
@live_only()
Expand Down
Loading
Loading