I generated a self-signed certificate for my REST api. At first, I specified the common name of the certificate as my external IP (a.b.c.d
). When I called it with Python's requests
library, specifying the verify
flag as my own cert, the call succeeded, but I got the following warning:
SubjectAltNameWarning: Certificate for a.b.c.d has no `subjectAltName`, falling back to check for a `commonName` for now. This feature is being removed by major browsers and deprecated by RFC 2818. (See https://github.com/urllib3/urllib3/issues/497 for details.)
No problem, I added the subjectAltName
with the second solution here: Invalid self signed SSL cert - "Subject Alternative Name Missing"
However, now when I call it with requests, I get the following:
Max retries exceeded with url: /todo1 (Caused by SSLError(CertificateError("hostname 'a.b.c.d' doesn't match 'a.b.c.d'")))
hostname 'a.b.c.d' doesn't match 'a.b.c.d'
Yes, it says that the exact same string does not match itself. I even copy pasted the strings to make sure there were no funny characters being used and checked for ==
in Python, it returned True.
The behavior is the exact same whether I call it on the local machine or an external machine.
I searched everywhere but didn't find anything even close to this problem. At this point I'm prepared to give up, go back to using the common name only, and disable the subjectAltName warning. (I know that I can disable the hostname check, but that seems less secure than ignoring a warning, and it doesn't seem like the optimal solution.) Please help me figure out why it's erroring. Thank you very much.
The exact code running on server:
from flask import Flask, request
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
todos = {}
class TodoSimple(Resource):
def get(self, todo_id):
return {todo_id: todos[todo_id]}
def put(self, todo_id):
todos[todo_id] = request.form['data']
return {todo_id: todos[todo_id]}
class TodoDelete(Resource):
def get(self, todo_id):
del todos[todo_id]
api.add_resource(TodoSimple, '/<string:todo_id>')
api.add_resource(TodoDelete, '/delete/<string:todo_id>')
if __name__ == '__main__':
#app.run(debug=True, port=443)
app.run(debug=False, host='0.0.0.0', port=443, ssl_context=('/root/cert.pem', '/root/key.pem'))
The requests call:
put('https://a.b.c.d:443/todo1', data={'data': 'Remember the milk'}, verify='/root/cert.pem').json()