当我尝试访问 GeoPy 时在 AWS EC2 实例上出现 SSL 错误 API
Getting SSL Error on AWS EC2 Instance When I Try to Reach GeoPy API
我正在尝试连接到 Nominatim GeoPy API 以从邮政编码解析 latitude/longitude 坐标。实现如下所示(最小可重现性):
# Create a function that returns lat/lon coordinates from zip code
def get_coord(zip_code):
geolocator = Nominatim(user_agent="GCD Data Client")
location = geolocator.geocode({"postalcode": zip_code, "country": "US"}, exactly_one = True)
in_lat = location.latitude
in_lon = location.longitude
return in_lat, in_lon
# Inputs for data
def get_params(self, zip_code):
# Do error checking to prevent strange, unexpected output from leaving function
out = False
while not out:
try:
in_lat, in_lon = get_coord(zip_code)
# Make sure the lat/lon pair is valid
if abs(in_lat) > 90 or abs(in_lon) > 180:
raise ValueError
out = True
except ValueError:
print("Make sure your lat/lon coordinates are valid (-90-90, -180-180)")
return in_lat, in_lon
if __name__ == '__main__':
# Get some input lats and lons
in_lats = []
in_lons = []
zip_codes = [14201, 80919, 84101] # Dummy data
for zip_code in zip_codes:
in_lat, in_lon = get_params(zip_code)
in_lats.append(in_lat)
in_lons.append(in_lon)
print(in_lats)
print(in_lons)
但是,代码不是问题所在。当我在本地机器 (windows) 上 运行 这段代码时,我得到了预期的 lat/lon 坐标。我很确定问题是与 GeoPy 服务器的通信被 AWS 阻止了,因为当我在那里 运行 时收到此错误:
geopy.exc.GeocoderUnavailable: HTTPSConnectionPool(host='nominatim.openstreetmap.org', port=443): Max retries exceeded with url: /search?postalcode=14201&country=US&format=json&limit=1 (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",),))
我尝试了一些不同的 ec2 安全配置。一个使用默认的 SSH 和 HTTPS(因为那是 443 路由到的地方)。我还尝试将它开放给所有入站流量(尽管这是糟糕的安全实践)进行测试,因为它只是一个开发服务器(并且已经再次将其锁定 :))。在这两种情况下,我仍然遇到同样的问题。这是我需要以某种方式启用的 SSL 设置吗?
我试过了,我可以确认这不是 ec2 相关的问题,因为我在 ec2 上试过,它有效。
总之,您可能需要使用最新的python版本或者更改您的系统证书文件。
这是我2021年的测试结果:在我的环境中,python 3.6.8 + geopy 2.2.0 + centos 7 有效; python 2.7.18 + geopy 1.23.0 + centos 8 也可以;但是 python 2.7.5 + geopy 1.23.0 + centos 7 不工作并报告证书错误。
终于,我找到了根本原因,这是由于 LetsEncrypt 使用的旧 'DST' 根证书于 9 月 30 日到期;参见 https://letsencrypt.org/docs/dst-root-ca-x3-expiration-september-2021 . Python is affected if it uses OpenSSL below 1.1.0; see https://openssl.org/blog/blog/2021/09/13/LetsEncryptRootCertExpire。
并且我使 python 2.7.5 + geopy 1.23.0 + centos 7 + openssl 1.0.2k-fips 与解决方法 1 一起工作,即从系统中删除 (DST Root CA X3) 根证书证书,详细步骤为:
- 检查 DST Root 在 /etc/pki/tls/certs/ca-bundle.crt 和 ISRG Root 中
X1 在 ISRG 根 X1 中。
- 将“# DST Root CA X3”部分复制到
/etc/pki/ca-trust/source/blacklist 目录为 pem 文件
- 运行 update-ca-trust
- 检查 DST Root 不再存在
/etc/pki/tls/certs/ca-bundle.crt, ISRG Root X1 在ISRG Root
X1.
参考:
- https://github.com/geopy/geopy/issues/124
- Mongodb SSL 连接
使用 Let's encrypt 突然颁发的 SSL 证书时失败
即使证书没有过期
我正在尝试连接到 Nominatim GeoPy API 以从邮政编码解析 latitude/longitude 坐标。实现如下所示(最小可重现性):
# Create a function that returns lat/lon coordinates from zip code
def get_coord(zip_code):
geolocator = Nominatim(user_agent="GCD Data Client")
location = geolocator.geocode({"postalcode": zip_code, "country": "US"}, exactly_one = True)
in_lat = location.latitude
in_lon = location.longitude
return in_lat, in_lon
# Inputs for data
def get_params(self, zip_code):
# Do error checking to prevent strange, unexpected output from leaving function
out = False
while not out:
try:
in_lat, in_lon = get_coord(zip_code)
# Make sure the lat/lon pair is valid
if abs(in_lat) > 90 or abs(in_lon) > 180:
raise ValueError
out = True
except ValueError:
print("Make sure your lat/lon coordinates are valid (-90-90, -180-180)")
return in_lat, in_lon
if __name__ == '__main__':
# Get some input lats and lons
in_lats = []
in_lons = []
zip_codes = [14201, 80919, 84101] # Dummy data
for zip_code in zip_codes:
in_lat, in_lon = get_params(zip_code)
in_lats.append(in_lat)
in_lons.append(in_lon)
print(in_lats)
print(in_lons)
但是,代码不是问题所在。当我在本地机器 (windows) 上 运行 这段代码时,我得到了预期的 lat/lon 坐标。我很确定问题是与 GeoPy 服务器的通信被 AWS 阻止了,因为当我在那里 运行 时收到此错误:
geopy.exc.GeocoderUnavailable: HTTPSConnectionPool(host='nominatim.openstreetmap.org', port=443): Max retries exceeded with url: /search?postalcode=14201&country=US&format=json&limit=1 (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",),))
我尝试了一些不同的 ec2 安全配置。一个使用默认的 SSH 和 HTTPS(因为那是 443 路由到的地方)。我还尝试将它开放给所有入站流量(尽管这是糟糕的安全实践)进行测试,因为它只是一个开发服务器(并且已经再次将其锁定 :))。在这两种情况下,我仍然遇到同样的问题。这是我需要以某种方式启用的 SSL 设置吗?
我试过了,我可以确认这不是 ec2 相关的问题,因为我在 ec2 上试过,它有效。
总之,您可能需要使用最新的python版本或者更改您的系统证书文件。
这是我2021年的测试结果:在我的环境中,python 3.6.8 + geopy 2.2.0 + centos 7 有效; python 2.7.18 + geopy 1.23.0 + centos 8 也可以;但是 python 2.7.5 + geopy 1.23.0 + centos 7 不工作并报告证书错误。
终于,我找到了根本原因,这是由于 LetsEncrypt 使用的旧 'DST' 根证书于 9 月 30 日到期;参见 https://letsencrypt.org/docs/dst-root-ca-x3-expiration-september-2021 . Python is affected if it uses OpenSSL below 1.1.0; see https://openssl.org/blog/blog/2021/09/13/LetsEncryptRootCertExpire。
并且我使 python 2.7.5 + geopy 1.23.0 + centos 7 + openssl 1.0.2k-fips 与解决方法 1 一起工作,即从系统中删除 (DST Root CA X3) 根证书证书,详细步骤为:
- 检查 DST Root 在 /etc/pki/tls/certs/ca-bundle.crt 和 ISRG Root 中 X1 在 ISRG 根 X1 中。
- 将“# DST Root CA X3”部分复制到 /etc/pki/ca-trust/source/blacklist 目录为 pem 文件
- 运行 update-ca-trust
- 检查 DST Root 不再存在 /etc/pki/tls/certs/ca-bundle.crt, ISRG Root X1 在ISRG Root X1.
参考:
- https://github.com/geopy/geopy/issues/124
- Mongodb SSL 连接 使用 Let's encrypt 突然颁发的 SSL 证书时失败 即使证书没有过期