Les services distants dans un VPC n'acceptent les connexions que via un nom de domaine. Toute requête adressée directement à une adresse IP échoue. Cette rubrique explique comment accéder à un service HTTPS via son adresse IP en ajoutant le nom de domaine à l'en-tête Host de la requête. Cette méthode s'avère utile pour les scénarios d'accès distant, tels que les tâches Spark ou les fonctions définies par l'utilisateur (UDF).
Échec de l'accès HTTPS par adresse IP
Message d'erreur
SSL: no alternative certificate subject name matches target host name '47.116.XX.XX'
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it.
To learn more about this situation and how to fix it, please visit the web page mentioned above.
Description du problème
Lorsqu'une tâche Spark ou UDF utilise une adresse IP pour accéder à un service distant tel que KMS ou OSS via HTTPS dans un VPC, la requête échoue avec l'erreur indiquée ci-dessus.
Solution
Pour résoudre l'échec de validation du certificat SSL lors de l'accès à un service HTTPS par adresse IP, ajoutez le nom de domaine du service à l'en-tête Host de la requête.
1. Récupérez l'adresse IP du service distant.
Utiliser ping
Depuis une console Windows ou Linux, exécutez la commande suivante pour obtenir l'adresse IP du service distant.
ping service.cn-shanghai-vpc.maxcompute.aliyun-inc.com
-
Résultat sous Windows :
PS C:\Users\xxx> ping service.cn-shanghai-vpc.maxcompute.aliyun-inc.com Ping service.cn-shanghai-vpc.maxcompute.aliyun-inc.com [100.103.104.45] xxx -
Résultat sous Linux :
[root@iZbxxx ~]# ping service.cn-shanghai-vpc.maxcompute.aliyun-inc.com PING service.cn-shanghai-vpc.maxcompute.aliyun-inc.com (100.103.104.45) 56(84) bytes of data.
Utiliser dig
-
Installez bind-utils dans votre environnement Windows ou Linux.
-
Windows
Téléchargez BIND9.17.12.x64.zip, extrayez-le dans un répertoire tel que
D:\install\BIND9.17.12.x64, puis ajoutez ce chemin à la variable d'environnement Path de Windows. -
Linux (CentOS)
Exécutez
sudo yum install bind-utilspour installer le paquet.
-
-
Exécutez la commande suivante dans votre console :
dig service.cn-shanghai-vpc.maxcompute.aliyun-inc.comWindows
PS C:\Users\xxx> dig service.cn-shanghai-vpc.maxcompute.aliyun-inc.com ; <<>> DiG 9.17.12 <<>> service.cn-shanghai-vpc.maxcompute.aliyun-inc.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49974 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4000 ;; QUESTION SECTION: ;service.cn-shanghai-vpc.maxcompute.aliyun-inc.com. IN A ;; ANSWER SECTION: service.cn-shanghai-vpc.maxcompute.aliyun-inc.com. 1 IN A 100.103.104.45 ;; Query time: 4 msec ;; SERVER: 10.61.150.xxx ;; WHEN: Wed Jan 08 14xxxLinux
[root@iZbxxx ~]# dig service.cn-shanghai-vpc.maxcompute.aliyun-inc.com ; <<>> DiG 9.11.4-P2-RedHat-9.11.4 <<>> service.cn-shanghai-vpc.maxcompute.aliyun-inc.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36725 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;service.cn-shanghai-vpc.maxcompute.aliyun-inc.com. IN A ;; ANSWER SECTION: service.cn-shanghai-vpc.maxcompute.aliyun-inc.com. 1 IN A 100.103.104.45 ;; Query time: 2 msec ;; SERVER: 100.100.2.xxx ;; WHEN: Wed Jan 08 14xxx
2. Configurez le client HTTP.
Les exemples de code suivants illustrent la création d'un adaptateur HTTP personnalisé pour différentes versions de Python. Cet adaptateur transmet l'adresse IP dans l'URL de la requête, tout en conservant le nom de domaine d'origine dans l'en-tête Host pour la validation SSL. Avant de publier votre tâche, testez l'accès distant depuis l'environnement réseau adéquat.
-
Python 2
# _*_ coding: utf-8 _*_ # only for python2 import requests from urlparse import urlparse class HostHeaderSSLAdapter(requests.adapters.HTTPAdapter): def __init__(self, resolved_ip): super(HostHeaderSSLAdapter,self).__init__() self.resolved_ip = resolved_ip def send(self, request, **kwargs): connection_pool_kwargs = self.poolmanager.connection_pool_kw result = urlparse(request.url) if result.scheme == 'https' and self.resolved_ip: request.url = request.url.replace( 'https://' + result.hostname, 'https://' + self.resolved_ip, ) connection_pool_kwargs['assert_hostname'] = result.hostname request.headers['Host'] = result.hostname else: connection_pool_kwargs.pop('assert_hostname', None) return super(HostHeaderSSLAdapter, self).send(request, **kwargs) def access_url(url, resolved_ip): session = requests.Session() # Get the hostname from the URL. parsed_url = urlparse(url) hostname = parsed_url.hostname session.mount('https://'+hostname, HostHeaderSSLAdapter(resolved_ip)) try: r = session.get(url) except Exception as e: print("Error: "+ str(e)) else: if r.status_code != 200: print("Request failed with non-200 status. Response: "+ r.text) else: print("Success. Response: "+ r.text) if __name__ == "__main__": # Obtain the IP address by using 'dig' for the domain name within the VPC environment. # Test a VPC address. #access_url("https://service.cn-shanghai-vpc.maxcompute.aliyun-inc.com", "100.103.104.45") # Test a public network address. access_url("https://service.cn-shanghai.maxcompute.aliyun.com", "47.116.XX.XX") -
Python 3
# _*_ coding: utf-8 _*_ import requests from urllib.parse import urlparse class HostHeaderSSLAdapter(requests.adapters.HTTPAdapter): def __init__(self, resolved_ip): super().__init__() self.resolved_ip = resolved_ip def send(self, request, **kwargs): connection_pool_kwargs = self.poolmanager.connection_pool_kw result = urlparse(request.url) if result.scheme == 'https' and self.resolved_ip: request.url = request.url.replace( 'https://' + result.hostname, 'https://' + self.resolved_ip, ) connection_pool_kwargs['server_hostname'] = result.hostname # Overwrite the Host header. request.headers['Host'] = result.hostname else: # Clear headers that might be left from a previous request. connection_pool_kwargs.pop('server_hostname', None) return super().send(request, **kwargs) def access_url(url, resolved_ip): session = requests.Session() # Get the hostname from the URL. parsed_url = urlparse(url) hostname = parsed_url.hostname session.mount('https://'+hostname, HostHeaderSSLAdapter(resolved_ip)) try: r = session.get(url) except Exception as e: print("Error: "+ str(e)) else: if r.status_code != 200: print("Request failed with non-200 status. Response: "+ r.text) else: print("Success. Response: "+ r.text) if __name__ == "__main__": # Obtain the IP address by using 'dig' for the domain name within the VPC environment. # Test a VPC address. #access_url("https://service.cn-shanghai-vpc.maxcompute.aliyun-inc.com", "100.103.104.45") # Test a public network address. access_url("https://service.cn-shanghai.maxcompute.aliyun.com", "47.116.XX.XX")
Résultats des tests
Exécutez le test depuis le même environnement réseau que celui de votre tâche. Pour accéder à un service dans un VPC, configurez l'environnement Python au sein de ce VPC et utilisez l'URL du service ainsi que l'adresse IP résolue depuis celui-ci.
-
Accédez au service MaxCompute depuis une machine locale via le réseau public.
if __name__ == "__main__": access_url( url="https://service.cn-shanghai.maxcompute.aliyun.com", resolved_ip="47.116.XX.XX") "D:\Program Files\Python311\python.exe" D:\ProgramData\PycharmProjects\pythontest1\text.py Success. Response: <!DOCTYPE html> <html> <head> <title>Welcome to tengine!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to tengine!</h1> <p>If you see this page, the tengine web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://tengine.taobao.org/">tengine.taobao.org</a>.</p> <p><em>Thank you for using tengine.</em></p> </body> </html> -
Accédez au service MaxCompute depuis une instance ECS Linux via le réseau public.
[root@iZbp1ehm6ky76ig8n1jd8dZ opt]# python3 text.py Success. Response: <!DOCTYPE html> <html> <head> <title>Welcome to tengine!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to tengine!</h1> <p>If you see this page, the tengine web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://tengine.taobao.org/">tengine.taobao.org</a>.</p> <p><em>Thank you for using tengine.</em></p> </body> </html>