Serviços remotos em uma VPC aceitam acesso apenas por nome de domínio. Requisições diretas por endereço IP falham. Este tópico descreve como acessar um serviço HTTPS pelo endereço IP ao adicionar o nome de domínio ao cabeçalho Host da requisição. Essa abordagem é útil para cenários de acesso remoto, como tarefas do Spark ou de Função Definida pelo Usuário (UDF).
Falha no acesso HTTPS por endereço IP
Mensagem de erro
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.
Descrição do problema
Quando uma tarefa do Spark ou UDF usa um endereço IP para acessar um serviço remoto, como KMS ou OSS, via HTTPS em uma VPC, a requisição falha e retorna o erro acima.
Solução
Para corrigir a falha na validação do certificado SSL ao acessar um serviço HTTPS por endereço IP, adicione o nome de domínio do serviço ao cabeçalho Host da requisição.
-
Obtenha o endereço IP do serviço remoto.
Use ping
Em um console Windows ou Linux, execute o comando abaixo para obter o endereço IP do serviço remoto.
ping service.cn-shanghai-vpc.maxcompute.aliyun-inc.com-
Resultado no 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 -
Resultado no 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.
Use dig
-
Instale o bind-utils no ambiente Windows ou Linux.
-
Windows
Baixe o arquivo BIND9.17.12.x64.zip, extraia-o em um diretório como
D:\install\BIND9.17.12.x64e adicione esse caminho à variável de ambiente Path no Windows. -
Linux (CentOS)
Execute
sudo yum install bind-utilspara instalar o pacote.
-
-
Execute o seguinte comando no 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
-
Configure o cliente HTTP.
Os exemplos de código a seguir mostram como criar um adaptador HTTP personalizado para diferentes versões do Python. Esse adaptador envia o endereço IP na URL da requisição, mas usa o nome de domínio original no cabeçalho Host para validação SSL. Antes de publicar a tarefa, teste o acesso remoto no ambiente de rede correto.
-
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")
Resultados do teste
Execute o teste no mesmo ambiente de rede da tarefa. Para acessar um serviço em uma VPC, configure o ambiente Python dentro dessa VPC e use a URL do serviço e o endereço IP resolvidos internamente.
-
Acesso ao serviço MaxCompute de uma máquina local pela rede pública.
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> -
Acesso ao serviço MaxCompute de uma instância ECS Linux pela rede pública.
[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>