La VPN està activa, el tauler intern s’obre al navegador i l’script de Python continua llançant un error de proxy. En aquesta imatge no hi ha res malament amb el túnel: l’intèrpret llegeix una adreça de proxy del seu propi entorn i hi envia la petició. Aquest manual llegeix l’entorn que el procés veu realment, aplica l’exclusió més estreta i només després considera una política de sessió explícita. Cada pas acaba amb una ordre la sortida de la qual decideix si continueu.

Llegiu l’entorn que el procés veu realment

La configuració de proxy de l’escriptori, les exportacions de l’intèrpret d’ordres i les línies Environment= d’una unitat de systemd són tres fonts diferents, i Requests només llegeix l’última que hereta. Executeu el diagnòstic de sota al mateix intèrpret d’ordres, contenidor o unitat que executa l’script fallit, no al vostre terminal interactiu. Una variable exportada al vostre intèrpret d’ordres d’inici de sessió és invisible per a un procés de contenidor, i aquesta bretxa explica molts informes de proxies que apareixen del no-res. Les dues ordres imprimeixen les mateixes dades amb nivells de detall diferents.

env | grep -i -E 'proxy|requests_ca_bundle|curl_ca_bundle'
python3 -c "import os;[print(k,'=',v) for k,v in sorted(os.environ.items()) if 'proxy' in k.lower()]"

Es llegeixen les dues grafies de cada variable, i les entrades duplicades s’apliquen en l’ordre en què el procés les va rebre, de manera que un HTTP_PROXY obsolet pot prevaler sobre el valor que acabeu d’exportar. Les variables del paquet de CA també importen aquí, perquè canvien a què resol verify sense aparèixer enlloc del codi. Si la sortida és buida, l’entorn no és el vostre problema i podeu deixar de llegir aquesta secció. Si hi apareix un proxy que no reconeixeu, trobeu el fitxer o la unitat que el defineix abans de canviar res.

Pregunteu a Requests què faria amb una URL concreta. Aquesta crida mostra els valors combinats de proxy, verify i cert per a aquella petició sense enviar cap paquet.

python3 -c "import requests;s=requests.Session();print(s.merge_environment_settings('https://api.corp.example/status',{},None,None,None))"

Una entrada proxies no buida per a l’amfitrió privat és la vostra resposta, i el valor verify imprès us diu de quin paquet de CA es refiaria la petició. Si tots dos semblen correctes, la fallada és més endavant a la pila i hauríeu de saltar a la secció de verificació. No endivineu a partir del codi: la combinació es fa per petició, i per això una sessió pot comportar-se de manera diferent per a dos amfitrions.

Excloeu l’amfitrió privat abans de desactivar res

Quan el proxy és realment necessari per a altres destinacions, la solució estreta és una exclusió per a aquest amfitrió. Afegiu a la llista existent en lloc de substituir-la, perquè esborrar NO_PROXY trenca totes les altres destinacions internes que hi confiaven. Les ordres de sota afegeixen l’entrada i després pregunten a Requests si s’aplica l’exclusió.

export NO_PROXY="${NO_PROXY:+$NO_PROXY,}api.corp.example,.corp.example"
python3 -c "import requests;print(requests.utils.should_bypass_proxies('https://api.corp.example/status',None))"

La concordança és pel sufix de l’amfitrió, així que .corp.example cobreix tot el domini mentre que api.corp.example cobreix un sol nom. Un asterisc sol desactiva el proxy per a tots els amfitrions i gairebé mai és el que vol una tasca de producció. Que s’accepti una entrada CIDR depèn de les versions de Requests i urllib3 de la imatge, així que proveu l’entrada exacta en lloc de suposar que funciona. Comproveu el resultat de should_bypass_proxies per a l’URL real, no per a un nom d’amfitrió que hàgiu escrit de memòria.

Manteniu les dues capes separades al cap. Evitar el proxy HTTP no evita la VPN, perquè la decisió del proxy passa a la biblioteca i la decisió del túnel passa a la taula d’encaminament del nucli.

Desactiveu trust_env només com a política de sessió deliberada

Si tota la tasca ha d’ignorar la configuració ambiental, construïu la sessió explícitament i registreu la decisió al codi. Això és una política, no una solució alternativa, i pertany a un diff que un revisor pugui veure. L’exemple de sota manté un temps d’espera, un camí de CA explícit i una comprovació d’estat.

import requests

with requests.Session() as session:
    session.trust_env = False
    response = session.get(
        "https://api.corp.example/status",
        timeout=(5, 20),
        verify="/etc/ssl/certs/corp-ca.pem",
    )
    response.raise_for_status()

Desactivar trust_env canvia tres comportaments alhora, i només un d’ells tracta de proxies. Requests deixa de llegir credencials de .netrc, i les variables REQUESTS_CA_BUNDLE i CURL_CA_BUNDLE deixen d’afectar verify, que llavors recorre al magatzem de certificats inclòs. Si la vostra organització acaba TLS amb la seva pròpia CA, aquest recurs produeix un error de verificació que sembla no relacionat amb el canvi que acabeu de fer. Passar verify explícitament és el que manté els dos efectes separats.

El que no hauríeu de fer és establir verify=False per silenciar l’error resultant. Això canvia una configuració de proxy incorrecta per una connexió no verificada, i amaga el problema de certificat que l’exclusió havia de revelar.

Verifiqueu la capa que falla i manteniu una reversió

Tres fallades semblen iguals en un registre i no tenen res en comú: un proxy que no pot arribar a la destinació llança ProxyError o retorna 502, un problema de confiança llança SSLError, i un rebuig de l’aplicació retorna 401 o 403. Reproduïu la petició fora de Requests per veure quina teniu. Les ordres de sota treuen el proxy, proven la cadena de certificats i després repeteixen la crida a través de la biblioteca.

curl -sv --noproxy '*' https://api.corp.example/status -o /dev/null
openssl s_client -connect api.corp.example:443 -servername api.corp.example </dev/null
python3 -c "import requests;r=requests.get('https://api.corp.example/status',timeout=10);print(r.status_code)"

Si la crida amb curl té èxit i la crida de Python falla, l’entorn continua sent la diferència. Si totes dues fallen a l’etapa TLS, el proxy mai no era el problema i ho és la cadena de certificats. Si totes dues retornen 401, la petició ha arribat a l’aplicació i la feina que queda és l’autenticació. Enregistrar quina de les tres heu observat estalvia una hora a la persona següent.

La reversió és una línia en qualsevol direcció: traieu l’exclusió o torneu trust_env enrere. Deseu el valor anterior de NO_PROXY abans d’afegir-hi, i preferiu un script embolcall o una entrada Environment= a nivell d’unitat a una exportació que només visqui a l’historial del vostre terminal. Els dos canvis són visibles a l’entorn del procés, així que un reinici normalment us torna al comportament antic.

Acabeu confirmant quatre coses: la configuració combinada per a l’URL privat no mostra cap proxy, el certificat es valida contra la CA prevista, la petició retorna l’estat que espereu i el canvi està confirmat en un lloc reproduïble. Un script verd amb un entorn inexplicat és una correcció que es torna a trencar a la màquina següent. Les ordres d’aquest manual són les que cal enganxar al tiquet.

Articles relacionats