Glocke
Anmeldungsdatum: 1. März 2009
Beiträge: 880
Wohnort: Thüringen
|
Hi, für ein Intranet möchte ich einen HTTPS-Webserver aufsetzen. Dazu habe ich mithilfe von CA (Abschnitt „Eigene-CA-betreiben“) eine eigene CA erzeugt, ein Zertifikat erzeugt und signiert. Das signierte Zertifikat befindet sich in ./newkey-wpwd.pem (als Ergebnis von openssl rsa ... ), die erstellte CA befindet sich in ./demoCA . Für den Webserver habe ich mir Python3 mit bottle überlegt und will - um das HTTPS zu realisieren - cherrypy mit verwenden. Nach einigem Googeln (die API hatte sich nochmal geändert), bin ich bei folgendem Minimalbeispiel:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | #!/usr/bin/python3
from bottle import ServerAdapter, route, run, server_names
@route('/', method='GET')
def index():
print('Läuft')
class SSLWebServer(ServerAdapter):
def run(self, handler):
from cheroot.wsgi import Server as WSGIServer
from cheroot.ssl.builtin import BuiltinSSLAdapter
server = WSGIServer((self.host, self.port), handler)
server.ssl_adapter = BuiltinSSLAdapter(
certificate="newkey-wpwd.pem",
private_key="demoCA/private/cakey.pem",
certificate_chain=None
)
try:
server.start()
except:
server.stop()
server_names['sslwebserver'] = SSLWebServer
run(host='0.0.0.0', port=443, server='sslwebserver')
|
Allerdings bricht der Server mit einem SSLError ab und mir fehlt auf dem HTTPS- und SSL-Gebiet noch die Erfahrung. Worin liegt mein Fehler? | Traceback (most recent call last):
File "./webtool.py", line 30, in <module>
run(host='0.0.0.0', port=443, server='sslwebserver')
File "/usr/local/lib/python3.4/dist-packages/bottle.py", line 3127, in run
server.run(app)
File "./webtool.py", line 19, in run
certificate_chain=None
File "/usr/local/lib/python3.4/dist-packages/cheroot/ssl/builtin.py", line 71, in __init__
self.context.load_cert_chain(certificate, private_key)
ssl.SSLError: [SSL] PEM lib (_ssl.c:2515)
|
LG Glocke PS:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 | $ /usr/lib/ssl/misc/CA.pl -newca
CA certificate filename (or enter to create)
Making CA certificate ...
Generating a 2048 bit RSA private key
......................................+++
....................................+++
writing new private key to './demoCA/private/cakey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:
State or Province Name (full name) []:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Demo
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:Administrator
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 12864710336022254648 (0xb288a1e3f4e71438)
Validity
Not Before: May 15 10:02:19 2018 GMT
Not After : May 14 10:02:19 2021 GMT
Subject:
organizationName = Demo
commonName = Administrator
X509v3 extensions:
X509v3 Subject Key Identifier:
91:DF:50:CE:8C:25:0D:27:3E:59:8A:4C:54:01:A0:74:AF:E2:82:D6
X509v3 Authority Key Identifier:
keyid:91:DF:50:CE:8C:25:0D:27:3E:59:8A:4C:54:01:A0:74:AF:E2:82:D6
X509v3 Basic Constraints:
CA:TRUE
Certificate is to be certified until May 14 10:02:19 2021 GMT (1095 days)
Write out database with 1 new entries
Data Base Updated
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | $ /usr/lib/ssl/misc/CA.pl -newreq
Generating a 2048 bit RSA private key
.................................+++
.................................................................................................+++
writing new private key to 'newkey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
Verify failure
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:
State or Province Name (full name) []:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Demo
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:localhost
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Request is in newreq.pem, private key is in newkey.pem
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 | $ /usr/lib/ssl/misc/CA.pl -sign
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 12864710336022254649 (0xb288a1e3f4e71439)
Validity
Not Before: May 15 10:02:53 2018 GMT
Not After : May 15 10:02:53 2019 GMT
Subject:
organizationName = Demo
commonName = localhost
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Cert Type:
SSL Server
X509v3 Key Usage: critical
Key Encipherment
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
FA:F6:E3:56:F1:25:EA:96:BA:B0:5E:AD:1D:3C:A5:14:B0:66:95:D7
X509v3 Authority Key Identifier:
keyid:91:DF:50:CE:8C:25:0D:27:3E:59:8A:4C:54:01:A0:74:AF:E2:82:D6
X509v3 Extended Key Usage:
TLS Web Server Authentication
Certificate is to be certified until May 15 10:02:53 2019 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Signed certificate is in newcert.pem
|
| $ openssl rsa -in newkey.pem -out newkey-wpwd.pem
Enter pass phrase for newkey.pem:
writing RSA key
|
|
noisefloor
Ehemaliger
Anmeldungsdatum: 6. Juni 2006
Beiträge: 29067
Wohnort: WW
|
Hallo, ich nutzte zwar auch Bottle, die ganzer Serveradapter finde ich aber suboptimal. Da weiß man nie so richtig, was im Hintergrund passiert. Der IMHO bessere weil besser kontrollierbare / konfigurierbare Weg wäre: Applikation mit Bottle erstellen über einen HTTPS-fähigen WSGI-Applikationsserver, der außerhalb von Bottle läuft, ausliefern.
Ob CherryPy letzters kann weiß ich gerade nicht, mit gunicorn geht es. Gruß, noisefloor
|
Glocke
(Themenstarter)
Anmeldungsdatum: 1. März 2009
Beiträge: 880
Wohnort: Thüringen
|
noisefloor schrieb: Applikation mit Bottle erstellen über einen HTTPS-fähigen WSGI-Applikationsserver, der außerhalb von Bottle läuft, ausliefern.
Probier ich, danke! Welchen HTTPS-fähigen WSPI-Applikationsserver verwendest du selbst?
|
misterunknown
Ehemalige
Anmeldungsdatum: 28. Oktober 2009
Beiträge: 4403
Wohnort: Sachsen
|
Ich würde für SSL-Offload einfach einen nginx als ReverseProxy nutzen. Der ist schlank und spricht vernünftiges SSL. Bottle kannst du dann lokal an einem anderen Port lauschen lassen.
|
noisefloor
Ehemaliger
Anmeldungsdatum: 6. Juni 2006
Beiträge: 29067
Wohnort: WW
|
Hallo,
Probier ich, danke! Welchen HTTPS-fähigen WSPI-Applikationsserver verwendest du selbst?
Gar keinen. Meine Server laufen alle nur bei mir zu Hause und da nutzte ich nur HTTP. Ich nutzte nginx als Reverse-Proxy, gunicorn als Applikationsserver und Django oder Bottle als Webframework. Du kannst natürlich SSL bei nginx nutzen und dann den Applikationsserver ohne SSL. Kommt halt drauf an, ob du einen Reverse-Proxy davor setzen willst oder nicht. Gruß, noisefloor
|
Glocke
(Themenstarter)
Anmeldungsdatum: 1. März 2009
Beiträge: 880
Wohnort: Thüringen
|
noisefloor schrieb: Du kannst natürlich SSL bei nginx nutzen und dann den Applikationsserver ohne SSL. Kommt halt drauf an, ob du einen Reverse-Proxy davor setzen willst oder nicht.
Also würde die HTTPS-Anfrage an nginx gehen, der die WSGI-Anfrage an gunicorn senden und dieser verwendet meine bottle -App? Benötige ich einen Reverse-Proxy? Ich bin auf de rHTTPS-Schiene noch nicht wirklich lange unterwegs 😀 misterunknown schrieb: Ich würde für SSL-Offload einfach einen nginx als ReverseProxy nutzen. Der ist schlank und spricht vernünftiges SSL. Bottle kannst du dann lokal an einem anderen Port lauschen lassen.
Also ohne gunicorn ? Abgesehen von der einfacheren Konfiguration ... wo siehst du da den Vorteil auf gunicorn als WSGI-Applikationsserver zu verzichten? Im Endeffekt geht es mir um ein Lehrer-Webtool im Schulintranet, das ich mittels HTTPS schützen möchte/müsste. LG Glocke
|
noisefloor
Ehemaliger
Anmeldungsdatum: 6. Juni 2006
Beiträge: 29067
Wohnort: WW
|
Hallo,
... wo siehst du da den Vorteil auf gunicorn als WSGI-Applikationsserver zu verzichten?
Es gib eigentlich keinen. Grund: zumindest nach meiner Erfahrung läuft der eingebaute Server von Bottle _nicht_ stabil, d.h. früher oder später stürzt der ab. Der eingebaute Server ist nicht für den Produktiveinsatz geeignet. Ein WSGI-Applikationsserver dagegen sollte stabil laufen. Zumindest habe ich mit gunicorn kein Problem, andere Server wie der von CherryPy, uwsgi etc. laufen aber auch stabil.
Also ohne gunicorn? Abgesehen von der einfacheren Konfiguration
gunicorn ist einfach zu konfigurieren. Im einfachsten Falls gibst du gunicorn nur den Einstiegspunkt der WSGI-kompatiblen Applikation mit, bei Bottle als in der Regel eine Instanz von bottle.Bottle() .
Benötige ich einen Reverse-Proxy? Ich bin auf de rHTTPS-Schiene noch nicht wirklich lange unterwegs.
Kommt drauf an. nginx ist als "buffering reverse proxy" kann halt mit hoher Last (= hunderten oder tausenden Request pro Sekunde) umgehen. gunicorn kann das zwar prinzipiell beim Einsatz von asyncronen Workern auch, aber nginx ist mit Sicherheit bei so was besser getestet als gunicorn. Außerdem brauchst du so wie so einen "richtigen" Server, wenn du noch statischen Content ausliefern willst. Oder mehrere unabhängige WSGI-Applikationen über eine Adresse und einen Port verfügbar machen willst. Ich würde dir dazu raten. 1. ist es nicht schwierig (im nginx-Artikel ist eine Beispielkonfiguration), 2. bist du dann voll flexible.
das ich mittels HTTPS schützen möchte/müsste.
HTTPS schützt nur die Verbindung. HTTPS schützt dich _nicht_ vor Programmierfehlern oder sonstigen Attacken gegen deine Applikation. Gruß, noisefloor Bearbeitet von sebix: Linksyntaxfix
|
Glocke
(Themenstarter)
Anmeldungsdatum: 1. März 2009
Beiträge: 880
Wohnort: Thüringen
|
noisefloor schrieb: Ich würde dir dazu raten. 1. ist es nicht schwierig (im -Artikel ist eine Beispielkonfiguration), 2. bist du dann voll flexible.
Ok danke, ich orientiere mich daran ☺ noisefloor schrieb: HTTPS schützt nur die Verbindung. HTTPS schützt dich _nicht_ vor Programmierfehlern oder sonstigen Attacken gegen deine Applikation.
Richtig. Zu dem Thema würde sich nen separater Foren-Thread eignen 😀 LG Glocke
|
Glocke
(Themenstarter)
Anmeldungsdatum: 1. März 2009
Beiträge: 880
Wohnort: Thüringen
|
Läuft inzwischen. Minimal-Beispiel für die Nachwelt:
| # apt-get install nginx python3-pip
# pip3 install bottle gunicorn
|
Und damit sollte die Vorbereitung stehen... Erstmal schön rm /etc/nginx/sites-enabled/default um die Default-Seite zu deaktivieren und dann kann's losgehen:
/etc/nginx/sites-available/demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name demo.com;
ssl_certificate /pfad/zu/demo.crt;
ssl_certificate_key /pfad/zu/demo.key;
location / {
include proxy_params;
proxy_pass http://unix:/pfad/zu/demo.sock;
}
}
|
Damit steht die Konfiguration, sodass http automatisch zu https umgeleitet wird und https auf die erstellten Zertifikate zurückgreift, wobei
Dann die Konfiguration aktivieren und den Server neustarten:
| # ln -s /etc/nginx/sites-available/demo /etc/nginx/sites-enabled
# service nginx restart
|
Damit steht der Reverse-Proxy für's HTTPs, alle Anfragen werden an den obigen Unix-Socket geleitet. Die Python-Anwendung sieht jetzt so aus:
demo.py
1
2
3
4
5
6
7
8
9
10
11
12 | from bottle import default_app, route, request
@route('/')
def index():
return 'Hallo'
# für mich zum testen
if __name__ == '__main__':
default_app.run(host='localhost', port=8000, debug=True, reloader=True)
# für gunicorn zum starten
app = default_app()
|
und Gunicorn starte ich (meine .sock und .py sind im gleichen Verzeichnis, dort befinde ich mich atm auch) mit:
| gunicorn --workers 3 --bind unix:demo.sock demo:app &
|
Danach startet gunicorn mit 3 Worker-Threads, die PIDs (zum Runterfahren) können aus der Ausgabe abgelesen werden. Jetzt muss ich es nur noch hinbekommen, dass der Browser das Zertifikat kennt 😀 LG Glocke
|
noisefloor
Ehemaliger
Anmeldungsdatum: 6. Juni 2006
Beiträge: 29067
Wohnort: WW
|
Hallo, statt gunicorn --workers 3 --bind unix:demo.sock demo:app & möchtest du gunicorn --workers 3 --bind unix:demo.sock demo:app -D verwendet. Bewirkt das gleiche, nur mit Bordmitteln von Gunicorn. Bzw. noch besser schreibst du dir eine systemd Service Unit zum Starten von Gunicorn. Dann bekommst du das Logging via journald "gratis" dazu und du brauchst keine PID zum Starten / stoppen. Gruß, noisefloor
|