diff --git a/docs/docsite/rst/guide_azure.rst b/docs/docsite/rst/guide_azure.rst index d5a6bc4350..265965261f 100644 --- a/docs/docsite/rst/guide_azure.rst +++ b/docs/docsite/rst/guide_azure.rst @@ -404,3 +404,15 @@ You can execute the playbook with something like: .. code-block:: bash $ ansible-playbook -i ./ansible/contrib/inventory/azure_rm.py test_azure_inventory.yml + + +Disabling certificate validation on Azure endpoints +................................................... + +When an HTTPS proxy is present, or when using Azure Stack, it may be necessary to disable certificate validation for +Azure endpoints in the Azure modules. This is not a recommended security practice, but may be necessary when the system +CA store cannot be altered to include the necessary CA certificate. Certificate validation can be controlled by setting +the "cert_validation_mode" value in a credential profile, via the "AZURE_CERT_VALIDATION_MODE" environment variable, or +by passing the "cert_validation_mode" argument to any Azure module. The default value is "validate"; setting the value +to "ignore" will prevent all certificate validation. The module argument takes precedence over a credential profile value, +which takes precedence over the environment value. diff --git a/lib/ansible/module_utils/azure_rm_common.py b/lib/ansible/module_utils/azure_rm_common.py index fb97da003d..2a256ba877 100644 --- a/lib/ansible/module_utils/azure_rm_common.py +++ b/lib/ansible/module_utils/azure_rm_common.py @@ -44,6 +44,7 @@ AZURE_COMMON_ARGS = dict( ad_user=dict(type='str', no_log=True), password=dict(type='str', no_log=True), cloud_environment=dict(type='str'), + cert_validation_mode=dict(type='str', choices=['validate', 'ignore']) # debug=dict(type='bool', default=False), ) @@ -57,6 +58,7 @@ AZURE_CREDENTIAL_ENV_MAPPING = dict( ad_user='AZURE_AD_USER', password='AZURE_PASSWORD', cloud_environment='AZURE_CLOUD_ENVIRONMENT', + cert_validation_mode='AZURE_CERT_VALIDATION_MODE', ) AZURE_TAG_ARGS = dict( @@ -255,6 +257,13 @@ class AzureRMModuleBase(object): self.fail("Failed to get credentials. Either pass as parameters, set environment variables, " "or define a profile in ~/.azure/credentials or be logged using AzureCLI.") + # cert validation mode precedence: module-arg, credential profile, env, "validate" + self._cert_validation_mode = self.module.params['cert_validation_mode'] or self.credentials.get('cert_validation_mode') or \ + os.environ.get('AZURE_CERT_VALIDATION_MODE') or 'validate' + + if self._cert_validation_mode not in ['validate', 'ignore']: + self.fail('invalid cert_validation_mode: {0}'.format(self._cert_validation_mode)) + # if cloud_environment specified, look up/build Cloud object raw_cloud_env = self.credentials.get('cloud_environment') if not raw_cloud_env: @@ -286,7 +295,8 @@ class AzureRMModuleBase(object): self.azure_credentials = ServicePrincipalCredentials(client_id=self.credentials['client_id'], secret=self.credentials['secret'], tenant=self.credentials['tenant'], - cloud_environment=self._cloud_environment) + cloud_environment=self._cloud_environment, + verify=self._cert_validation_mode == 'validate') elif self.credentials.get('ad_user') is not None and self.credentials.get('password') is not None: tenant = self.credentials.get('tenant') @@ -296,7 +306,8 @@ class AzureRMModuleBase(object): self.azure_credentials = UserPassCredentials(self.credentials['ad_user'], self.credentials['password'], tenant=tenant, - cloud_environment=self._cloud_environment) + cloud_environment=self._cloud_environment, + verify=self._cert_validation_mode == 'validate') else: self.fail("Failed to authenticate with provided credentials. Some attributes were missing. " "Credentials must include client_id, secret and tenant or ad_user and password or " @@ -718,6 +729,10 @@ class AzureRMModuleBase(object): return self.get_poller_result(poller) + @staticmethod + def _validation_ignore_callback(session, global_config, local_config, **kwargs): + session.verify = False + def get_mgmt_svc_client(self, client_type, base_url=None, api_version=None): self.log('Getting management service client {0}'.format(client_type.__name__)) self.check_client_version(client_type) @@ -740,6 +755,9 @@ class AzureRMModuleBase(object): if VSCODEEXT_USER_AGENT_KEY in os.environ: client.config.add_user_agent(os.environ[VSCODEEXT_USER_AGENT_KEY]) + if self._cert_validation_mode == 'ignore': + client.config.session_configuration_callback = self._validation_ignore_callback + return client @property diff --git a/lib/ansible/utils/module_docs_fragments/azure.py b/lib/ansible/utils/module_docs_fragments/azure.py index dcf25bba31..eb2c1100bf 100644 --- a/lib/ansible/utils/module_docs_fragments/azure.py +++ b/lib/ansible/utils/module_docs_fragments/azure.py @@ -67,6 +67,15 @@ options: C(AzureUSGovernment)), or a metadata discovery endpoint URL (required for Azure Stack). Can also be set via credential file profile or the C(AZURE_CLOUD_ENVIRONMENT) environment variable. default: AzureCloud + version_added: 2.4 + cert_validation_mode: + description: + - Controls the certificate validation behavior for Azure endpoints. By default, all modules will validate the server certificate, but + when an HTTPS proxy is in use, or against Azure Stack, it may be necessary to disable this behavior by passing C(ignore). Can also be + set via credential file profile or the C(AZURE_CERT_VALIDATION) environment variable. + choices: [validate, ignore] + default: null + version_added: 2.5 requirements: - "python >= 2.7" - "azure >= 2.0.0"