Skip to content

Commit ffa778f

Browse files
author
Ace Eldeib
authored
[AKS] az aks create/update: Add parameter --http-proxy-config to support setting HTTP Proxy configuration (#23352)
1 parent 8916d48 commit ffa778f

File tree

12 files changed

+4661
-3
lines changed

12 files changed

+4661
-3
lines changed

scripts/ci/credscan/CredScanSuppressions.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,14 +385,12 @@
385385
],
386386
"_justification": "[Network] Ignore test certs."
387387
},
388-
389388
{
390389
"file": [
391390
"src/azure-cli/azure/cli/command_modules/network/tests/latest/recordings/test_vpn_client_package.yaml"
392391
],
393392
"_justification": "[Network] response body contains random value recognized as secret"
394393
},
395-
396394
{
397395
"file": [
398396
"src\\azure-cli\\azure\\cli\\command_modules\\keyvault\\tests\\hybrid_2018_03_01\\ec256.pem",
@@ -559,6 +557,12 @@
559557
"src\\azure-cli\\azure\\cli\\command_modules\\vm\\tests\\latest\\recordings\\test_vm_trusted_launch_os_disk_secure_upload.yaml"
560558
],
561559
"_justification": "[VM] the SAS tokens come from the temporary test resources"
560+
},
561+
{
562+
"file": [
563+
"src\\azure-cli\\azure\\cli\\command_modules\\acs\\tests\\latest\\data\\setup_proxy.sh"
564+
],
565+
"_justification": "Dummy self-signed certificate + private key used for testing only."
562566
}
563567
]
564-
}
568+
}

src/azure-cli/azure/cli/command_modules/acs/_help.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,9 @@
544544
- name: --azure-keyvault-kms-key-vault-resource-id
545545
type: string
546546
short-summary: Resource ID of Azure Key Vault.
547+
- name: --http-proxy-config
548+
type: string
549+
short-summary: HTTP Proxy configuration for this cluster.
547550
548551
examples:
549552
- name: Create a Kubernetes cluster with an existing SSH public key.
@@ -790,6 +793,9 @@
790793
- name: --azure-keyvault-kms-key-vault-resource-id
791794
type: string
792795
short-summary: Resource ID of Azure Key Vault.
796+
- name: --http-proxy-config
797+
type: string
798+
short-summary: HTTP Proxy configuration for this cluster.
793799
794800
examples:
795801
- name: Update a kubernetes cluster with standard SKU load balancer to use two AKS created IPs for the load balancer outbound connection usage.

src/azure-cli/azure/cli/command_modules/acs/_params.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ def load_arguments(self, _):
325325
c.argument('linux_os_config')
326326
c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true')
327327
c.argument('host_group_id', validator=validate_host_group_id)
328+
c.argument('http_proxy_config')
328329

329330
with self.argument_context('aks update') as c:
330331
# managed cluster paramerters
@@ -382,6 +383,7 @@ def load_arguments(self, _):
382383
"--update-cluster-autoscaler", "-u"], action='store_true')
383384
c.argument('min_count', type=int, validator=validate_nodes_count)
384385
c.argument('max_count', type=int, validator=validate_nodes_count)
386+
c.argument('http_proxy_config')
385387
c.argument('nodepool_labels', nargs='*', validator=validate_nodepool_labels,
386388
help='space-separated labels: key[=value] [key[=value] ...]. See https://aka.ms/node-labels for syntax of labels.')
387389
c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true')

src/azure-cli/azure/cli/command_modules/acs/custom.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,7 @@ def aks_create(
15701570
vm_set_type=None,
15711571
zones=None,
15721572
ppg=None,
1573+
http_proxy_config=None,
15731574
max_pods=0,
15741575
enable_encryption_at_host=False,
15751576
enable_ultra_ssd=False,
@@ -1659,6 +1660,7 @@ def aks_update(
16591660
min_count=None,
16601661
max_count=None,
16611662
nodepool_labels=None,
1663+
http_proxy_config=None,
16621664
no_wait=False,
16631665
yes=False,
16641666
aks_custom_headers=None,

src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
ContainerServiceClient = TypeVar("ContainerServiceClient")
9292
Identity = TypeVar("Identity")
9393
ManagedCluster = TypeVar("ManagedCluster")
94+
ManagedClusterHTTPProxyConfig = TypeVar("ManagedClusterHTTPProxyConfig")
9495
ManagedClusterLoadBalancerProfile = TypeVar("ManagedClusterLoadBalancerProfile")
9596
ManagedClusterPropertiesAutoScalerProfile = TypeVar("ManagedClusterPropertiesAutoScalerProfile")
9697
ResourceReference = TypeVar("ResourceReference")
@@ -1341,6 +1342,44 @@ def get_detach_acr(self) -> Union[str, None]:
13411342
# this parameter does not need validation
13421343
return detach_acr
13431344

1345+
def get_http_proxy_config(self) -> Union[Dict, ManagedClusterHTTPProxyConfig, None]:
1346+
"""Obtain the value of http_proxy_config.
1347+
1348+
:return: dictionary, ManagedClusterHTTPProxyConfig or None
1349+
"""
1350+
# read the original value passed by the command
1351+
http_proxy_config = None
1352+
http_proxy_config_file_path = self.raw_param.get("http_proxy_config")
1353+
# validate user input
1354+
if http_proxy_config_file_path:
1355+
if not os.path.isfile(http_proxy_config_file_path):
1356+
raise InvalidArgumentValueError(
1357+
"{} is not valid file, or not accessable.".format(
1358+
http_proxy_config_file_path
1359+
)
1360+
)
1361+
http_proxy_config = get_file_json(http_proxy_config_file_path)
1362+
if not isinstance(http_proxy_config, dict):
1363+
raise InvalidArgumentValueError(
1364+
"Error reading Http Proxy Config from {}. "
1365+
"Please see https://aka.ms/HttpProxyConfig for correct format.".format(
1366+
http_proxy_config_file_path
1367+
)
1368+
)
1369+
1370+
# In create mode, try to read the property value corresponding to the parameter from the `mc` object
1371+
if self.decorator_mode == DecoratorMode.CREATE:
1372+
if (
1373+
self.mc and
1374+
hasattr(self.mc, "http_proxy_config") and
1375+
self.mc.http_proxy_config is not None
1376+
):
1377+
http_proxy_config = self.mc.http_proxy_config
1378+
1379+
# this parameter does not need dynamic completion
1380+
# this parameter does not need validation
1381+
return http_proxy_config
1382+
13441383
def get_assignee_from_identity_or_sp_profile(self) -> Tuple[str, bool]:
13451384
"""Helper function to obtain the value of assignee from identity_profile or service_principal_profile.
13461385
@@ -4954,6 +4993,16 @@ def set_up_identity_profile(self, mc: ManagedCluster) -> ManagedCluster:
49544993
mc.identity_profile = identity_profile
49554994
return mc
49564995

4996+
def set_up_http_proxy_config(self, mc: ManagedCluster) -> ManagedCluster:
4997+
"""Set up http proxy config for the ManagedCluster object.
4998+
4999+
:return: the ManagedCluster object
5000+
"""
5001+
self._ensure_mc(mc)
5002+
5003+
mc.http_proxy_config = self.context.get_http_proxy_config()
5004+
return mc
5005+
49575006
def set_up_auto_upgrade_profile(self, mc: ManagedCluster) -> ManagedCluster:
49585007
"""Set up auto upgrade profile for the ManagedCluster object.
49595008
@@ -5071,6 +5120,7 @@ def construct_mc_profile_default(self, bypass_restore_defaults: bool = False) ->
50715120
mc = self.set_up_defender(mc)
50725121
# set up azure keyvalut kms
50735122
mc = self.set_up_azure_keyvault_kms(mc)
5123+
mc = self.set_up_http_proxy_config(mc)
50745124

50755125
# DO NOT MOVE: keep this at the bottom, restore defaults
50765126
if not bypass_restore_defaults:
@@ -5677,6 +5727,16 @@ def update_auto_upgrade_profile(self, mc: ManagedCluster) -> ManagedCluster:
56775727
mc.auto_upgrade_profile.upgrade_channel = auto_upgrade_channel
56785728
return mc
56795729

5730+
def update_http_proxy_config(self, mc: ManagedCluster) -> ManagedCluster:
5731+
"""Set up http proxy config for the ManagedCluster object.
5732+
5733+
:return: the ManagedCluster object
5734+
"""
5735+
self._ensure_mc(mc)
5736+
5737+
mc.http_proxy_config = self.context.get_http_proxy_config()
5738+
return mc
5739+
56805740
def update_identity(self, mc: ManagedCluster) -> ManagedCluster:
56815741
"""Update identity for the ManagedCluster object.
56825742
@@ -6008,6 +6068,8 @@ def update_mc_profile_default(self) -> ManagedCluster:
60086068
mc = self.update_azure_keyvault_kms(mc)
60096069
# update identity
60106070
mc = self.update_identity_profile(mc)
6071+
# set up http proxy config
6072+
mc = self.update_http_proxy_config(mc)
60116073
return mc
60126074

60136075
# pylint: disable=unused-argument
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# CLI test data folder
2+
3+
This folder contains test data for some AKS CLI commands.
4+
5+
For HTTP proxy testing, we need a preknown certificate which we will present to AKS
6+
and also inject to a VM for use in a proxy server. We can't generate the certificate
7+
at VM deploy time because we won't be able to extract it easily to pass back to AKS
8+
without e.g. VM run-command which is slow. So we generate the certificate here and
9+
hardcode the key/cert into a VM provisioning script.
10+
11+
The existing cert is a self-signed CA with a 10 year expiry (Not After: Mar 5 16:44:47 2032 GMT) with a SAN of the
12+
proxy server hostname.
13+
14+
You can regenerate it with the following openssl commands in bash.
15+
16+
After regenerating it, update the certificate in httpproxyconfig.json used for cluster creation,
17+
and the hardcoded key/cert in setup_proxy.sh.
18+
19+
The cert in httpproxyconfig_update.json can be generated the same way, but it should not need to be updated.
20+
21+
```bash
22+
# Name of the VM on which proxy is hosted
23+
HOST="cli-proxy-vm"
24+
25+
CONFIG="
26+
[req]
27+
distinguished_name=dn
28+
[ dn ]
29+
[ ext ]
30+
basicConstraints=CA:TRUE,pathlen:0
31+
"
32+
33+
openssl req -config <(echo "$CONFIG") -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout squidk.pem -out squidc.pem -subj "/CN=${HOST}" -addext "subjectAltName=DNS:${HOST}" -addext "basicConstraints=critical,CA:TRUE,pathlen:0" -addext "keyUsage=critical,keyCertSign,cRLSign,keyEncipherment,encipherOnly,decipherOnly,digitalSignature,nonRepudiation" -addext "extendedKeyUsage=clientAuth,serverAuth"
34+
35+
# update cert in testdata file
36+
jq --arg cert "$(cat squidc.pem | base64 -w 0)" '.trustedCa=$cert' httpproxyconfig.json | sponge httpproxyconfig.json
37+
```
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"httpProxy": "http://cli-proxy-vm:3128/",
3+
"httpsProxy": "https://cli-proxy-vm:3129/",
4+
"noProxy": [
5+
"localhost",
6+
"127.0.0.1"
7+
],
8+
"trustedCa": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZHekNDQXdPZ0F3SUJBZ0lVT1FvajhDTFpkc2Vscjk3cnZJd3g1T0xEc3V3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd0Z6RVZNQk1HQTFVRUF3d01ZMnhwTFhCeWIzaDVMWFp0TUI0WERUSXlNRE13T0RFMk5EUTBOMW9YRFRNeQpNRE13TlRFMk5EUTBOMW93RnpFVk1CTUdBMVVFQXd3TVkyeHBMWEJ5YjNoNUxYWnRNSUlDSWpBTkJna3Foa2lHCjl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUEvTVB0VjVCVFB0NmNxaTRSZE1sbXIzeUlzYTJ1anpjaHh2NGgKanNDMUR0blJnb3M1UzQxUEgwcmkrM3RUU1ZYMzJ5cndzWStyRDFZUnVwbTZsbUU3R2hVNUkwR2k5b3prU0YwWgpLS2FKaTJveXBVL0ZCK1FQcXpvQ1JzTUV3R0NibUtGVmw4VnVoeW5kWEs0YjRrYmxyOWJsL2V1d2Q3TThTYnZ6CldVam5lRHJRc2lJc3J6UFQ0S0FaTHFjdHpEZTRsbFBUN1lLYTMzaGlFUE9mdldpWitkcWthUUE5UDY0eFhTeW4KZkhYOHVWQUozdUJWSmVHeEQwcGtOSjdqT3J5YVV1SEh1Y1U4UzltSWpuS2pBQjVhUGpMSDV4QXM2bG1iMzEyMgp5KzF0bkVBbVhNNTBEK1VvRWpmUzZIT2I1cmRpcVhHdmMxS2JvS2p6a1BDUnh4MmE3MmN2ZWdVajZtZ0FKTHpnClRoRTFsbGNtVTRpemd4b0lNa1ZwR1RWT0xMbjFWRkt1TmhNWkN2RnZLZ25Lb0F2M0cwRlVuZldFYVJSalNObUQKTFlhTURUNUg5WnQycERJVWpVR1N0Q2w3Z1J6TUVuWXdKTzN5aURwZzQzbzVkUnlzVXlMOUpmRS9OaDdUZzYxOApuOGNKL1c3K1FZYllsanVyYXA4cjdRRlNyb2wzVkNoRkIrT29yNW5pK3ZvaFNBd0pmMFVsTXBHM3hXbXkxVUk0ClRGS2ZGR1JSVHpyUCs3Yk53WDVoSXZJeTVWdGd5YU9xSndUeGhpL0pkeHRPcjJ0QTVyQ1c3K0N0Z1N2emtxTkUKWHlyN3ZrWWdwNlk1TFpneTR0VWpLMEswT1VnVmRqQk9oRHBFenkvRkY4dzFGRVZnSjBxWS9yV2NMa0JIRFQ4Ugp2SmtoaW84Q0F3RUFBYU5mTUYwd0Z3WURWUjBSQkJBd0RvSU1ZMnhwTFhCeWIzaDVMWFp0TUJJR0ExVWRFd0VCCi93UUlNQVlCQWY4Q0FRQXdEd1lEVlIwUEFRSC9CQVVEQXdmbmdEQWRCZ05WSFNVRUZqQVVCZ2dyQmdFRkJRY0QKQWdZSUt3WUJCUVVIQXdFd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dJQkFBb21qQ3lYdmFRT3hnWUs1MHNYTEIyKwp3QWZkc3g1bm5HZGd5Zmc0dXJXMlZtMTVEaEd2STdDL250cTBkWXkyNE4vVWJHN1VEWHZseUxJSkZxMVhQN25mCnBaRzBWQ2paNjlibXhLbTNaOG0wL0F3TXZpOGU5ZWR5OHY5a05CQ3dMR2tIYkE4WW85Q0lpUWdlbGZwcDF2VWgKYm5OQmhhRCtpdTZDZmlDTHdnSmIvaXc3ZW8vQ3lvWnF4K3RqWGFPMnpYdm00cC8rUUlmQU9ndEdRTEZVOGNmWgovZ1VyVHE1Z0ZxMCtQOUd5V3NBVEpGNnE3TDZXWlpqME91VHNlN2Y0Q1NpajZNbk9NTXhBK0pvYWhKejdsc1NpClRKSEl3RXA1ci9SeWhweWVwUXhGWWNVSDVKSmY5cmFoWExXWmkrOVRqeFNNMll5aHhmUlBzaVVFdUdEb2s3OFEKbS9RUGlDaTlKSmIxb2NtVGpBVjh4RFNob2NpdlhPRnlobjZMbjc3dkxqWStBYXZ0V0RoUXRocHVQeHNMdFZ6bQplMFNIMTFkRUxSdGI3NG1xWE9yTzdmdS8rSUJzM0pxTEUvVSt4dXhRdHZHOHZHMXlES0hIU1pxUzJoL1dzNGw0Ck5pQXNoSGdlaFFEUEJjWTl3WVl6ZkJnWnBPVU16ZERmNTB4K0ZTbFk0M1dPSkp6U3VRaDR5WjArM2t5Z3VDRjgKcm5NTFNjZXlTNGNpNExtSi9LQ1N1R2RmNlhWWXo4QkU5Z2pqanBDUDZxeTBVbFJlZldzL2lnL3djSysyYkYxVApuL1l2KzZnWGVDVEhKNzVxRElQbHA3RFJVVWswZmJNajRiSWthb2dXV2s0emYydThteFpMYTBsZVBLTktaTi9tCkdDdkZ3cjNlaSt1LzhjenA1RjdUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"httpProxy": "http://cli-proxy-vm:3128/",
3+
"httpsProxy": "https://cli-proxy-vm:3129/",
4+
"noProxy": [
5+
"localhost",
6+
"127.0.0.1"
7+
],
8+
"trustedCa": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZERENDQXZTZ0F3SUJBZ0lVQlJ3cGs1eTh5ckdrNmtYTjhkSHlMRUNvaHBrd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0VqRVFNQTRHQTFVRUF3d0habTl2TFdKaGNqQWVGdzB5TVRFd01UTXdNekU1TlRoYUZ3MHpNVEV3TVRFdwpNekU1TlRoYU1CSXhFREFPQmdOVkJBTU1CMlp2YnkxaVlYSXdnZ0lpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElDCkR3QXdnZ0lLQW9JQ0FRRFcwRE9sVC9yci9xUEZIUU9lNndBNDkyVGh3VWxZaDhCQkszTW9VWVZLNjEvL2xXekEKeFkrYzlmazlvckUrZXhMSVpwdUg1VnNZR21MNUFyc05sVmNBMkU4MWgwSlBPYUo1eEpiZG40YldpZG9vdXRVVwpXeDNhYUJLSEt0RWdZbUNmTjliWXlZMlNWRWQvNS9HeGh0akVabHJ1aEtRdkZVa3hwR0xKK1JRQ25oNklZakQwCnNpQ0YyTjJhVUJ4RE5KaUdmeHlHSVIrY2p4Vlcrd01md05CQ0l6QVkxMnY4WmpzUXdmUWlhOE5oWEx3M0tuRm0KdzUrcHN2bU1HL1FFUUtZMXNOTnk2dS9DZkI3cmIxQ0EwcjdNNnFsNFMrWHJjZUVRcXpDUWR6NWJueGNYbmFkbwp5MDlhdm5OSGRqbmpvcHNPSkxhd2hzb3RGNWFrL1FLdjYzdU9yVFFlOHlPSWlCZ3JSUzdwejcxbVlhRGNMcXFtCmtmdDVLYnFnMHNZYmo0M09LSm5aZ3crTUtackhoSFJKNi9BcWxOclZML3pFUytHU0ozQ1lSaE5nYXdDQ0Nqd1gKanZYZnkycWFEV2NQbWZaSWVVMVNzdE05THBVRWFQNjJzUVNmb3NEdnZFbUFyUVgwcmd1WGhvZ3pRUFdGWVlEKwo4SUNFYkNFc21hVnN3MzhVUzgzbFlGVCtyTHh3cm5UK1JXSUZ2WFRXbHhCNm5JeWpsOXBhNzlkdU5ocjJxN2RzCjVOU3ZWWHg5UGNqVTQ2VUZ6QnVTbUl0Q0M0Y1NadFRWc3l6ZnpMd2hKbGlqV0czTkp5TnpHUkZQcUpQdTNJUzEKZ3VtKytqdWx4bXZNWm1vM1RqSE5JRm90a0kyd3d3ZUtIcWpYcW9STmwvVnZobE5CaXZRR2gxeGovd0lEQVFBQgpvMW93V0RBU0JnTlZIUkVFQ3pBSmdnZG1iMjh0WW1GeU1CSUdBMVVkRXdFQi93UUlNQVlCQWY4Q0FRQXdEd1lEClZSMFBBUUgvQkFVREF3Zm5nREFkQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQWdZSUt3WUJCUVVIQXdFd0RRWUoKS29aSWh2Y05BUUVMQlFBRGdnSUJBTDF3RlpTdUw4NTM3aHpUTXhSUWJjcWdEU2F4RUd0ZDJaNTVCcnVWQVloagpxQjR6STd1UVZ2SkNpeXdmQm5BNnZmejh2UDBzdGJJbkVtajh1dS9CSS81NzZqR0tWUWRQSDhqMnQvN1NQWjFKClhBWk9wc1hoVll2RmtpQlhVeW1RMnAvRjFqb2ZRRE1JQ0htdHhRUSthakJQNjBpcnFnVnpsRi95NlQySUgzOHYKbGordndIam52WW5vVmhGNEY0TlE5amp6S3Y1NUhVTk0xUEJKZkFaOTJqeXovczdPMmN2cjhNWlNkT2s5QVk1RQp5RXRlQjBTSjdLS0tUZklBVmVMQzdrRnBHR3FsRkRBNzhPSS9YakNZViswRjk4MHdNOVkxTEVUa3ZMamVSMEFyCnVzZDNIS1Vtd2EwTVEwUTNZNGxma0ZtNjJTclhvcjJURC9WZHpFZWNOTnVmV1VJTVNuaEJDNTVHWjBOTVYvR0QKRXhGZTVWQkhUZEZVNlIwb3JCOVFjVll1Mzk0MEt5NXhkbHNaUHZlMmRJNS9WOXhzY0Zad3cxWWs4K21RK3NVeQp2UVBoL2ZmK0tTQjdVVkdvTVNXUlg3YjFFMGVzZSs4QzZlaVV2OXpDR0VRbkVCcnFIQWxSUDJ2ZzQ0bXFJSnRzCjN2NUt1NW0ySmJoeWNsQVR3VUNQZkN3a2tLRTg0MzZGRitDK0ZUVTJ1OWVpL2t5QTAxYi9zRFl2cWdsS2FWK3MKbEVHRkhjd05Ea2VrS1BFUEZxNkpnZ3R0WlNidE5SMnFadzl3cExIbDVuVlVXdnBGa2hvcW1KVkphK0VBSTQ1LwpqRkh4VG9PMHp1NlBxc1p5SnM2TC84Z3BhbTcwMDV6b0VETVRjcFltMlduMFBKcEg3NE9zUHJVRDVJWVA5ZEt5Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
9+
}

0 commit comments

Comments
 (0)