diff --git a/scripts/ci/credscan/CredScanSuppressions.json b/scripts/ci/credscan/CredScanSuppressions.json index 33ef042fb0e..9669a81f362 100644 --- a/scripts/ci/credscan/CredScanSuppressions.json +++ b/scripts/ci/credscan/CredScanSuppressions.json @@ -385,14 +385,12 @@ ], "_justification": "[Network] Ignore test certs." }, - { "file": [ "src/azure-cli/azure/cli/command_modules/network/tests/latest/recordings/test_vpn_client_package.yaml" ], "_justification": "[Network] response body contains random value recognized as secret" }, - { "file": [ "src\\azure-cli\\azure\\cli\\command_modules\\keyvault\\tests\\hybrid_2018_03_01\\ec256.pem", @@ -559,6 +557,12 @@ "src\\azure-cli\\azure\\cli\\command_modules\\vm\\tests\\latest\\recordings\\test_vm_trusted_launch_os_disk_secure_upload.yaml" ], "_justification": "[VM] the SAS tokens come from the temporary test resources" + }, + { + "file": [ + "src\\azure-cli\\azure\\cli\\command_modules\\acs\\tests\\latest\\data\\setup_proxy.sh" + ], + "_justification": "Dummy self-signed certificate + private key used for testing only." } ] -} +} \ No newline at end of file diff --git a/src/azure-cli/azure/cli/command_modules/acs/_help.py b/src/azure-cli/azure/cli/command_modules/acs/_help.py index 3838ae5f6e5..b1ae0a2b96c 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/_help.py +++ b/src/azure-cli/azure/cli/command_modules/acs/_help.py @@ -544,6 +544,9 @@ - name: --azure-keyvault-kms-key-vault-resource-id type: string short-summary: Resource ID of Azure Key Vault. + - name: --http-proxy-config + type: string + short-summary: HTTP Proxy configuration for this cluster. examples: - name: Create a Kubernetes cluster with an existing SSH public key. @@ -790,6 +793,9 @@ - name: --azure-keyvault-kms-key-vault-resource-id type: string short-summary: Resource ID of Azure Key Vault. + - name: --http-proxy-config + type: string + short-summary: HTTP Proxy configuration for this cluster. examples: - name: Update a kubernetes cluster with standard SKU load balancer to use two AKS created IPs for the load balancer outbound connection usage. diff --git a/src/azure-cli/azure/cli/command_modules/acs/_params.py b/src/azure-cli/azure/cli/command_modules/acs/_params.py index fa28147f49d..4aafba9f4e4 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/_params.py +++ b/src/azure-cli/azure/cli/command_modules/acs/_params.py @@ -325,6 +325,7 @@ def load_arguments(self, _): c.argument('linux_os_config') c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true') c.argument('host_group_id', validator=validate_host_group_id) + c.argument('http_proxy_config') with self.argument_context('aks update') as c: # managed cluster paramerters @@ -382,6 +383,7 @@ def load_arguments(self, _): "--update-cluster-autoscaler", "-u"], action='store_true') c.argument('min_count', type=int, validator=validate_nodes_count) c.argument('max_count', type=int, validator=validate_nodes_count) + c.argument('http_proxy_config') c.argument('nodepool_labels', nargs='*', validator=validate_nodepool_labels, help='space-separated labels: key[=value] [key[=value] ...]. See https://aka.ms/node-labels for syntax of labels.') c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true') diff --git a/src/azure-cli/azure/cli/command_modules/acs/custom.py b/src/azure-cli/azure/cli/command_modules/acs/custom.py index 1c4ed9d4008..afd7d5f8e7c 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/custom.py +++ b/src/azure-cli/azure/cli/command_modules/acs/custom.py @@ -1570,6 +1570,7 @@ def aks_create( vm_set_type=None, zones=None, ppg=None, + http_proxy_config=None, max_pods=0, enable_encryption_at_host=False, enable_ultra_ssd=False, @@ -1659,6 +1660,7 @@ def aks_update( min_count=None, max_count=None, nodepool_labels=None, + http_proxy_config=None, no_wait=False, yes=False, aks_custom_headers=None, diff --git a/src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py b/src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py index 6fd47edfa58..2a1cb5c5dff 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py +++ b/src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py @@ -91,6 +91,7 @@ ContainerServiceClient = TypeVar("ContainerServiceClient") Identity = TypeVar("Identity") ManagedCluster = TypeVar("ManagedCluster") +ManagedClusterHTTPProxyConfig = TypeVar("ManagedClusterHTTPProxyConfig") ManagedClusterLoadBalancerProfile = TypeVar("ManagedClusterLoadBalancerProfile") ManagedClusterPropertiesAutoScalerProfile = TypeVar("ManagedClusterPropertiesAutoScalerProfile") ResourceReference = TypeVar("ResourceReference") @@ -1341,6 +1342,44 @@ def get_detach_acr(self) -> Union[str, None]: # this parameter does not need validation return detach_acr + def get_http_proxy_config(self) -> Union[Dict, ManagedClusterHTTPProxyConfig, None]: + """Obtain the value of http_proxy_config. + + :return: dictionary, ManagedClusterHTTPProxyConfig or None + """ + # read the original value passed by the command + http_proxy_config = None + http_proxy_config_file_path = self.raw_param.get("http_proxy_config") + # validate user input + if http_proxy_config_file_path: + if not os.path.isfile(http_proxy_config_file_path): + raise InvalidArgumentValueError( + "{} is not valid file, or not accessable.".format( + http_proxy_config_file_path + ) + ) + http_proxy_config = get_file_json(http_proxy_config_file_path) + if not isinstance(http_proxy_config, dict): + raise InvalidArgumentValueError( + "Error reading Http Proxy Config from {}. " + "Please see https://aka.ms/HttpProxyConfig for correct format.".format( + http_proxy_config_file_path + ) + ) + + # In create mode, try to read the property value corresponding to the parameter from the `mc` object + if self.decorator_mode == DecoratorMode.CREATE: + if ( + self.mc and + hasattr(self.mc, "http_proxy_config") and + self.mc.http_proxy_config is not None + ): + http_proxy_config = self.mc.http_proxy_config + + # this parameter does not need dynamic completion + # this parameter does not need validation + return http_proxy_config + def get_assignee_from_identity_or_sp_profile(self) -> Tuple[str, bool]: """Helper function to obtain the value of assignee from identity_profile or service_principal_profile. @@ -4954,6 +4993,16 @@ def set_up_identity_profile(self, mc: ManagedCluster) -> ManagedCluster: mc.identity_profile = identity_profile return mc + def set_up_http_proxy_config(self, mc: ManagedCluster) -> ManagedCluster: + """Set up http proxy config for the ManagedCluster object. + + :return: the ManagedCluster object + """ + self._ensure_mc(mc) + + mc.http_proxy_config = self.context.get_http_proxy_config() + return mc + def set_up_auto_upgrade_profile(self, mc: ManagedCluster) -> ManagedCluster: """Set up auto upgrade profile for the ManagedCluster object. @@ -5071,6 +5120,7 @@ def construct_mc_profile_default(self, bypass_restore_defaults: bool = False) -> mc = self.set_up_defender(mc) # set up azure keyvalut kms mc = self.set_up_azure_keyvault_kms(mc) + mc = self.set_up_http_proxy_config(mc) # DO NOT MOVE: keep this at the bottom, restore defaults if not bypass_restore_defaults: @@ -5677,6 +5727,16 @@ def update_auto_upgrade_profile(self, mc: ManagedCluster) -> ManagedCluster: mc.auto_upgrade_profile.upgrade_channel = auto_upgrade_channel return mc + def update_http_proxy_config(self, mc: ManagedCluster) -> ManagedCluster: + """Set up http proxy config for the ManagedCluster object. + + :return: the ManagedCluster object + """ + self._ensure_mc(mc) + + mc.http_proxy_config = self.context.get_http_proxy_config() + return mc + def update_identity(self, mc: ManagedCluster) -> ManagedCluster: """Update identity for the ManagedCluster object. @@ -6008,6 +6068,8 @@ def update_mc_profile_default(self) -> ManagedCluster: mc = self.update_azure_keyvault_kms(mc) # update identity mc = self.update_identity_profile(mc) + # set up http proxy config + mc = self.update_http_proxy_config(mc) return mc # pylint: disable=unused-argument diff --git a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/data/README.md b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/data/README.md new file mode 100644 index 00000000000..0093568587f --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/data/README.md @@ -0,0 +1,37 @@ +# CLI test data folder + +This folder contains test data for some AKS CLI commands. + +For HTTP proxy testing, we need a preknown certificate which we will present to AKS +and also inject to a VM for use in a proxy server. We can't generate the certificate +at VM deploy time because we won't be able to extract it easily to pass back to AKS +without e.g. VM run-command which is slow. So we generate the certificate here and +hardcode the key/cert into a VM provisioning script. + +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 +proxy server hostname. + +You can regenerate it with the following openssl commands in bash. + +After regenerating it, update the certificate in httpproxyconfig.json used for cluster creation, +and the hardcoded key/cert in setup_proxy.sh. + +The cert in httpproxyconfig_update.json can be generated the same way, but it should not need to be updated. + +```bash +# Name of the VM on which proxy is hosted +HOST="cli-proxy-vm" + +CONFIG=" +[req] +distinguished_name=dn +[ dn ] +[ ext ] +basicConstraints=CA:TRUE,pathlen:0 +" + +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" + +# update cert in testdata file +jq --arg cert "$(cat squidc.pem | base64 -w 0)" '.trustedCa=$cert' httpproxyconfig.json | sponge httpproxyconfig.json +``` diff --git a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/data/httpproxyconfig.json b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/data/httpproxyconfig.json new file mode 100644 index 00000000000..83a4781dd5e --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/data/httpproxyconfig.json @@ -0,0 +1,9 @@ +{ + "httpProxy": "http://cli-proxy-vm:3128/", + "httpsProxy": "https://cli-proxy-vm:3129/", + "noProxy": [ + "localhost", + "127.0.0.1" + ], + "trustedCa": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZHekNDQXdPZ0F3SUJBZ0lVT1FvajhDTFpkc2Vscjk3cnZJd3g1T0xEc3V3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd0Z6RVZNQk1HQTFVRUF3d01ZMnhwTFhCeWIzaDVMWFp0TUI0WERUSXlNRE13T0RFMk5EUTBOMW9YRFRNeQpNRE13TlRFMk5EUTBOMW93RnpFVk1CTUdBMVVFQXd3TVkyeHBMWEJ5YjNoNUxYWnRNSUlDSWpBTkJna3Foa2lHCjl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUEvTVB0VjVCVFB0NmNxaTRSZE1sbXIzeUlzYTJ1anpjaHh2NGgKanNDMUR0blJnb3M1UzQxUEgwcmkrM3RUU1ZYMzJ5cndzWStyRDFZUnVwbTZsbUU3R2hVNUkwR2k5b3prU0YwWgpLS2FKaTJveXBVL0ZCK1FQcXpvQ1JzTUV3R0NibUtGVmw4VnVoeW5kWEs0YjRrYmxyOWJsL2V1d2Q3TThTYnZ6CldVam5lRHJRc2lJc3J6UFQ0S0FaTHFjdHpEZTRsbFBUN1lLYTMzaGlFUE9mdldpWitkcWthUUE5UDY0eFhTeW4KZkhYOHVWQUozdUJWSmVHeEQwcGtOSjdqT3J5YVV1SEh1Y1U4UzltSWpuS2pBQjVhUGpMSDV4QXM2bG1iMzEyMgp5KzF0bkVBbVhNNTBEK1VvRWpmUzZIT2I1cmRpcVhHdmMxS2JvS2p6a1BDUnh4MmE3MmN2ZWdVajZtZ0FKTHpnClRoRTFsbGNtVTRpemd4b0lNa1ZwR1RWT0xMbjFWRkt1TmhNWkN2RnZLZ25Lb0F2M0cwRlVuZldFYVJSalNObUQKTFlhTURUNUg5WnQycERJVWpVR1N0Q2w3Z1J6TUVuWXdKTzN5aURwZzQzbzVkUnlzVXlMOUpmRS9OaDdUZzYxOApuOGNKL1c3K1FZYllsanVyYXA4cjdRRlNyb2wzVkNoRkIrT29yNW5pK3ZvaFNBd0pmMFVsTXBHM3hXbXkxVUk0ClRGS2ZGR1JSVHpyUCs3Yk53WDVoSXZJeTVWdGd5YU9xSndUeGhpL0pkeHRPcjJ0QTVyQ1c3K0N0Z1N2emtxTkUKWHlyN3ZrWWdwNlk1TFpneTR0VWpLMEswT1VnVmRqQk9oRHBFenkvRkY4dzFGRVZnSjBxWS9yV2NMa0JIRFQ4Ugp2SmtoaW84Q0F3RUFBYU5mTUYwd0Z3WURWUjBSQkJBd0RvSU1ZMnhwTFhCeWIzaDVMWFp0TUJJR0ExVWRFd0VCCi93UUlNQVlCQWY4Q0FRQXdEd1lEVlIwUEFRSC9CQVVEQXdmbmdEQWRCZ05WSFNVRUZqQVVCZ2dyQmdFRkJRY0QKQWdZSUt3WUJCUVVIQXdFd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dJQkFBb21qQ3lYdmFRT3hnWUs1MHNYTEIyKwp3QWZkc3g1bm5HZGd5Zmc0dXJXMlZtMTVEaEd2STdDL250cTBkWXkyNE4vVWJHN1VEWHZseUxJSkZxMVhQN25mCnBaRzBWQ2paNjlibXhLbTNaOG0wL0F3TXZpOGU5ZWR5OHY5a05CQ3dMR2tIYkE4WW85Q0lpUWdlbGZwcDF2VWgKYm5OQmhhRCtpdTZDZmlDTHdnSmIvaXc3ZW8vQ3lvWnF4K3RqWGFPMnpYdm00cC8rUUlmQU9ndEdRTEZVOGNmWgovZ1VyVHE1Z0ZxMCtQOUd5V3NBVEpGNnE3TDZXWlpqME91VHNlN2Y0Q1NpajZNbk9NTXhBK0pvYWhKejdsc1NpClRKSEl3RXA1ci9SeWhweWVwUXhGWWNVSDVKSmY5cmFoWExXWmkrOVRqeFNNMll5aHhmUlBzaVVFdUdEb2s3OFEKbS9RUGlDaTlKSmIxb2NtVGpBVjh4RFNob2NpdlhPRnlobjZMbjc3dkxqWStBYXZ0V0RoUXRocHVQeHNMdFZ6bQplMFNIMTFkRUxSdGI3NG1xWE9yTzdmdS8rSUJzM0pxTEUvVSt4dXhRdHZHOHZHMXlES0hIU1pxUzJoL1dzNGw0Ck5pQXNoSGdlaFFEUEJjWTl3WVl6ZkJnWnBPVU16ZERmNTB4K0ZTbFk0M1dPSkp6U3VRaDR5WjArM2t5Z3VDRjgKcm5NTFNjZXlTNGNpNExtSi9LQ1N1R2RmNlhWWXo4QkU5Z2pqanBDUDZxeTBVbFJlZldzL2lnL3djSysyYkYxVApuL1l2KzZnWGVDVEhKNzVxRElQbHA3RFJVVWswZmJNajRiSWthb2dXV2s0emYydThteFpMYTBsZVBLTktaTi9tCkdDdkZ3cjNlaSt1LzhjenA1RjdUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" +} \ No newline at end of file diff --git a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/data/httpproxyconfig_update.json b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/data/httpproxyconfig_update.json new file mode 100644 index 00000000000..c94e9fccdb8 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/data/httpproxyconfig_update.json @@ -0,0 +1,9 @@ +{ + "httpProxy": "http://cli-proxy-vm:3128/", + "httpsProxy": "https://cli-proxy-vm:3129/", + "noProxy": [ + "localhost", + "127.0.0.1" + ], + "trustedCa": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZERENDQXZTZ0F3SUJBZ0lVQlJ3cGs1eTh5ckdrNmtYTjhkSHlMRUNvaHBrd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0VqRVFNQTRHQTFVRUF3d0habTl2TFdKaGNqQWVGdzB5TVRFd01UTXdNekU1TlRoYUZ3MHpNVEV3TVRFdwpNekU1TlRoYU1CSXhFREFPQmdOVkJBTU1CMlp2YnkxaVlYSXdnZ0lpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElDCkR3QXdnZ0lLQW9JQ0FRRFcwRE9sVC9yci9xUEZIUU9lNndBNDkyVGh3VWxZaDhCQkszTW9VWVZLNjEvL2xXekEKeFkrYzlmazlvckUrZXhMSVpwdUg1VnNZR21MNUFyc05sVmNBMkU4MWgwSlBPYUo1eEpiZG40YldpZG9vdXRVVwpXeDNhYUJLSEt0RWdZbUNmTjliWXlZMlNWRWQvNS9HeGh0akVabHJ1aEtRdkZVa3hwR0xKK1JRQ25oNklZakQwCnNpQ0YyTjJhVUJ4RE5KaUdmeHlHSVIrY2p4Vlcrd01md05CQ0l6QVkxMnY4WmpzUXdmUWlhOE5oWEx3M0tuRm0KdzUrcHN2bU1HL1FFUUtZMXNOTnk2dS9DZkI3cmIxQ0EwcjdNNnFsNFMrWHJjZUVRcXpDUWR6NWJueGNYbmFkbwp5MDlhdm5OSGRqbmpvcHNPSkxhd2hzb3RGNWFrL1FLdjYzdU9yVFFlOHlPSWlCZ3JSUzdwejcxbVlhRGNMcXFtCmtmdDVLYnFnMHNZYmo0M09LSm5aZ3crTUtackhoSFJKNi9BcWxOclZML3pFUytHU0ozQ1lSaE5nYXdDQ0Nqd1gKanZYZnkycWFEV2NQbWZaSWVVMVNzdE05THBVRWFQNjJzUVNmb3NEdnZFbUFyUVgwcmd1WGhvZ3pRUFdGWVlEKwo4SUNFYkNFc21hVnN3MzhVUzgzbFlGVCtyTHh3cm5UK1JXSUZ2WFRXbHhCNm5JeWpsOXBhNzlkdU5ocjJxN2RzCjVOU3ZWWHg5UGNqVTQ2VUZ6QnVTbUl0Q0M0Y1NadFRWc3l6ZnpMd2hKbGlqV0czTkp5TnpHUkZQcUpQdTNJUzEKZ3VtKytqdWx4bXZNWm1vM1RqSE5JRm90a0kyd3d3ZUtIcWpYcW9STmwvVnZobE5CaXZRR2gxeGovd0lEQVFBQgpvMW93V0RBU0JnTlZIUkVFQ3pBSmdnZG1iMjh0WW1GeU1CSUdBMVVkRXdFQi93UUlNQVlCQWY4Q0FRQXdEd1lEClZSMFBBUUgvQkFVREF3Zm5nREFkQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQWdZSUt3WUJCUVVIQXdFd0RRWUoKS29aSWh2Y05BUUVMQlFBRGdnSUJBTDF3RlpTdUw4NTM3aHpUTXhSUWJjcWdEU2F4RUd0ZDJaNTVCcnVWQVloagpxQjR6STd1UVZ2SkNpeXdmQm5BNnZmejh2UDBzdGJJbkVtajh1dS9CSS81NzZqR0tWUWRQSDhqMnQvN1NQWjFKClhBWk9wc1hoVll2RmtpQlhVeW1RMnAvRjFqb2ZRRE1JQ0htdHhRUSthakJQNjBpcnFnVnpsRi95NlQySUgzOHYKbGordndIam52WW5vVmhGNEY0TlE5amp6S3Y1NUhVTk0xUEJKZkFaOTJqeXovczdPMmN2cjhNWlNkT2s5QVk1RQp5RXRlQjBTSjdLS0tUZklBVmVMQzdrRnBHR3FsRkRBNzhPSS9YakNZViswRjk4MHdNOVkxTEVUa3ZMamVSMEFyCnVzZDNIS1Vtd2EwTVEwUTNZNGxma0ZtNjJTclhvcjJURC9WZHpFZWNOTnVmV1VJTVNuaEJDNTVHWjBOTVYvR0QKRXhGZTVWQkhUZEZVNlIwb3JCOVFjVll1Mzk0MEt5NXhkbHNaUHZlMmRJNS9WOXhzY0Zad3cxWWs4K21RK3NVeQp2UVBoL2ZmK0tTQjdVVkdvTVNXUlg3YjFFMGVzZSs4QzZlaVV2OXpDR0VRbkVCcnFIQWxSUDJ2ZzQ0bXFJSnRzCjN2NUt1NW0ySmJoeWNsQVR3VUNQZkN3a2tLRTg0MzZGRitDK0ZUVTJ1OWVpL2t5QTAxYi9zRFl2cWdsS2FWK3MKbEVHRkhjd05Ea2VrS1BFUEZxNkpnZ3R0WlNidE5SMnFadzl3cExIbDVuVlVXdnBGa2hvcW1KVkphK0VBSTQ1LwpqRkh4VG9PMHp1NlBxc1p5SnM2TC84Z3BhbTcwMDV6b0VETVRjcFltMlduMFBKcEg3NE9zUHJVRDVJWVA5ZEt5Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" +} \ No newline at end of file diff --git a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/data/setup_proxy.sh b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/data/setup_proxy.sh new file mode 100644 index 00000000000..879a0988688 --- /dev/null +++ b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/data/setup_proxy.sh @@ -0,0 +1,139 @@ +#!/usr/bin/env bash +set -x + +echo "setting up" +WORKDIR="${1:-$(mktemp -d)}" +echo "setting up ${WORKDIR}" + +pushd "$WORKDIR" + +apt update -y && apt install -y apt-transport-https curl gnupg make gcc < /dev/null + +# add diladele apt key +wget -qO - https://packages.diladele.com/diladele_pub.asc | apt-key add - + +# add new repo +tee /etc/apt/sources.list.d/squid413-ubuntu20.diladele.com.list < /dev/null < /dev/null <