mirror of
https://github.com/thib8956/nginx-proxy
synced 2024-12-24 03:26:31 +00:00
TESTS: rewrite tests using pytest and docker-compose
Experimentation to see if it is worth the effort
This commit is contained in:
parent
985c46d8b5
commit
197d793a25
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
**/__pycache__/
|
||||
**/.cache/
|
14
.travis.yml
14
.travis.yml
@ -6,6 +6,7 @@ services:
|
||||
env:
|
||||
global:
|
||||
- DOCKER_VERSION=1.12.3-0~trusty
|
||||
- DOCKER_COMPOSE_VERSION=1.9.0
|
||||
|
||||
before_install:
|
||||
# list docker-engine versions
|
||||
@ -14,15 +15,28 @@ before_install:
|
||||
- sudo apt-get -o Dpkg::Options::="--force-confnew" install -y --force-yes docker-engine=${DOCKER_VERSION}
|
||||
- docker version
|
||||
- docker info
|
||||
# install docker-compose
|
||||
- sudo rm /usr/local/bin/docker-compose ||true
|
||||
- curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
|
||||
- chmod +x docker-compose
|
||||
- sudo mv docker-compose /usr/local/bin/docker-compose
|
||||
- docker-compose --version
|
||||
# install bats
|
||||
- sudo add-apt-repository ppa:duggan/bats --yes
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq bats
|
||||
# prepare docker images
|
||||
- make update-dependencies
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- env: TEST_ID=test-debian
|
||||
- env: TEST_ID=test-alpine
|
||||
- env: TEST_ID=test2-debian
|
||||
- env: TEST_ID=test2-alpine
|
||||
allow_failures:
|
||||
- env: TEST_ID=test2-debian
|
||||
- env: TEST_ID=test2-alpine
|
||||
|
||||
script:
|
||||
- make $TEST_ID
|
||||
|
8
Makefile
8
Makefile
@ -1,5 +1,5 @@
|
||||
.SILENT :
|
||||
.PHONY : test
|
||||
.PHONY : test test2
|
||||
|
||||
update-dependencies:
|
||||
docker pull jwilder/docker-gen:0.7.3
|
||||
@ -19,3 +19,9 @@ test-alpine:
|
||||
bats test
|
||||
|
||||
test: test-debian test-alpine
|
||||
|
||||
test2-debian:
|
||||
$(MAKE) -C test2 test-debian
|
||||
|
||||
test2-alpine:
|
||||
$(MAKE) -C test2 test-alpine
|
||||
|
17
test2/Makefile
Normal file
17
test2/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
.SILENT :
|
||||
.PHONY : test-debian test-alpine test
|
||||
|
||||
|
||||
update-dependencies:
|
||||
requirements/build.sh
|
||||
pip install -U -r requirements.txt
|
||||
|
||||
test-debian: update-dependencies
|
||||
docker build -t jwilder/nginx-proxy:test ..
|
||||
pytest
|
||||
|
||||
test-alpine: update-dependencies
|
||||
docker build -f ../Dockerfile.alpine -t jwilder/nginx-proxy:test ..
|
||||
pytest
|
||||
|
||||
test: test-debian test-alpine
|
84
test2/README.md
Normal file
84
test2/README.md
Normal file
@ -0,0 +1,84 @@
|
||||
Nginx proxy test suite
|
||||
======================
|
||||
|
||||
Install requirements
|
||||
--------------------
|
||||
|
||||
You need [python 2.7](https://www.python.org/) and [pip](https://pip.pypa.io/en/stable/installing/) installed. Then run the commands:
|
||||
|
||||
requirements/build.sh
|
||||
pip install -r requirements.txt
|
||||
|
||||
|
||||
Prepare the nginx-proxy test image
|
||||
----------------------------------
|
||||
|
||||
docker build -t jwilder/nginx-proxy:test ..
|
||||
|
||||
make sure to tag that test image exactly `jwilder/nginx-proxy:test` or the test suite won't work.
|
||||
|
||||
|
||||
Run the test suite
|
||||
------------------
|
||||
|
||||
pytest
|
||||
|
||||
need more verbosity ?
|
||||
|
||||
pytest -s
|
||||
|
||||
|
||||
Run one single test module
|
||||
--------------------------
|
||||
|
||||
pytest test_nominal.py
|
||||
|
||||
|
||||
Write a test module
|
||||
-------------------
|
||||
|
||||
This test suite uses [pytest](http://doc.pytest.org/en/latest/). The [conftest.py](conftest.py) file will be automatically loaded by pytest and will provide you with two useful pytest [fixtures](http://doc.pytest.org/en/latest/fixture.html#fixture):
|
||||
|
||||
- docker_compose
|
||||
- nginxproxy
|
||||
|
||||
Also _conftest.py_ alters the way the python interpreter resolves domain names to IP addresses in such a way that any domain name containing the substring `nginx-proxy` will resolve to the IP address of the container that was created from the `jwilder/nginx-proxy:test` image.
|
||||
|
||||
So all the following domain names will resolve to the nginx-proxy container in tests:
|
||||
- `nginx-proxy`
|
||||
- `nginx-proxy.com`
|
||||
- `www.nginx-proxy.com`
|
||||
- `www.nginx-proxy.test`
|
||||
- `www.nginx-proxy`
|
||||
- `whatever.nginx-proxyooooooo`
|
||||
- ...
|
||||
|
||||
|
||||
### docker_compose fixture
|
||||
|
||||
When using the `docker_compose` fixture in a test, pytest will try to find a yml file named after your test module filename. For instance, if your test module is `test_example.py`, then the `docker_compose` fixture will try to load a `test_example.yml` [docker compose file](https://docs.docker.com/compose/compose-file/).
|
||||
|
||||
The only requirement within that compose file is to have a container declared from the docker image `jwilder/nginx-proxy:test`.
|
||||
|
||||
Once the docker compose file found, the fixture will remove all containers, run `docker-compose up`, and finally your test will be executed.
|
||||
|
||||
The fixture will run the _docker-compose_ command with the `-f` option to load the given compose file. So you can test your docker compose file syntax by running it yourself with:
|
||||
|
||||
docker-compose -f test_example.yml up -d
|
||||
|
||||
|
||||
### nginxproxy fixture
|
||||
|
||||
The `nginxproxy` fixture will provide you with a replacement for the python [requests](https://pypi.python.org/pypi/requests/) module. This replacement will just repeat up to 30 times a requests if it receives the HTTP error 404 or 502. This error occurs when you try to send queries to nginx-proxy too early after the container creation.
|
||||
|
||||
Also this requests replacement is preconfigured to use the Certificate Authority root certificate [certs/ca-root.crt](certs/) to validate https connections.
|
||||
|
||||
|
||||
### The web docker image
|
||||
|
||||
When you ran the `requirements/build.sh` script earlier, you built a [`web`](requirements/README.md) docker image which is convenient for running a small web server in a container. This image can produce containers that listens on multiple ports at the same time.
|
||||
|
||||
|
||||
### Testing TLS
|
||||
|
||||
If you need to create server certificates, use the [`certs/create_server_certificate.sh`](certs/) script. Pytest will be able to validate any certificate issued from this script.
|
70
test2/certs/*.nginx-proxy.tld.crt
Normal file
70
test2/certs/*.nginx-proxy.tld.crt
Normal file
@ -0,0 +1,70 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 4096 (0x1000)
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld
|
||||
Validity
|
||||
Not Before: Jan 10 00:08:52 2017 GMT
|
||||
Not After : May 28 00:08:52 2044 GMT
|
||||
Subject: CN=*.nginx-proxy.tld
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:cb:45:f4:14:9b:fe:64:85:79:4a:36:8d:3d:d1:
|
||||
27:d0:7c:36:28:30:e6:73:80:6f:7c:49:23:d0:6c:
|
||||
17:e4:44:c0:77:4d:9a:c2:bc:24:84:e3:a5:4d:ba:
|
||||
d2:da:51:7b:a1:2a:12:d4:c0:19:55:69:2c:22:27:
|
||||
2d:1a:f6:fc:4b:7f:e9:cb:a8:3c:e8:69:b8:d2:4f:
|
||||
de:4e:50:e2:d0:74:30:7c:42:5a:ae:aa:85:a5:b1:
|
||||
71:4d:c9:7e:86:8b:62:8c:3e:0d:e3:3b:c3:f5:81:
|
||||
0b:8c:68:79:fe:bf:10:fb:ae:ec:11:49:6d:64:5e:
|
||||
1a:7d:b3:92:93:4e:96:19:3a:98:04:a7:66:b2:74:
|
||||
61:2d:41:13:0c:a4:54:0d:2c:78:fd:b4:a3:e8:37:
|
||||
78:9a:de:fa:bc:2e:a8:0f:67:14:58:ce:c3:87:d5:
|
||||
14:0e:8b:29:7d:48:19:b2:a9:f5:b4:e8:af:32:21:
|
||||
67:15:7e:43:52:8b:20:cf:9f:38:43:bf:fd:c8:24:
|
||||
7f:52:a3:88:f2:f1:4a:14:91:2a:6e:91:6f:fb:7d:
|
||||
6a:78:c6:6d:2e:dd:1e:4c:2b:63:bb:3a:43:9c:91:
|
||||
f9:df:d3:08:13:63:86:7d:ce:e8:46:cf:f1:6c:1f:
|
||||
ca:f7:4c:de:d8:4b:e0:da:bc:06:d9:87:0f:ff:96:
|
||||
45:85
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:*.nginx-proxy.tld
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
6e:a5:0e:e4:d3:cc:d5:b7:fc:34:75:89:4e:98:8c:e7:08:06:
|
||||
a8:5b:ec:13:7d:83:99:a2:61:b8:d5:12:6e:c5:b4:53:4e:9a:
|
||||
22:cd:ad:14:30:6a:7d:58:d7:23:d9:a4:2a:96:a0:40:9e:50:
|
||||
9f:ce:f2:fe:8c:dd:9a:ac:99:39:5b:89:2d:ca:e5:3e:c3:bc:
|
||||
03:04:1c:12:d9:6e:b8:9f:f0:3a:be:12:44:7e:a4:21:86:73:
|
||||
af:d5:00:51:3f:2c:56:70:34:8f:26:b0:7f:b0:cf:cf:7f:f9:
|
||||
40:6f:00:29:c4:cf:c3:b7:c2:49:3d:3f:b0:26:78:87:b9:c7:
|
||||
6c:1b:aa:6a:1a:dd:c5:eb:f2:69:ba:6d:46:0b:92:49:b5:11:
|
||||
3c:eb:48:c7:2f:fb:33:a6:6a:82:a2:ab:f8:1e:5f:7d:e3:b7:
|
||||
f2:fd:f5:88:a5:09:4d:a0:bc:f4:3b:cd:d2:8b:d7:57:1f:86:
|
||||
3b:d2:3e:a4:92:21:b0:02:0b:e9:e0:c4:1c:f1:78:e2:58:a7:
|
||||
26:5f:4c:29:c8:23:f0:6e:12:3f:bd:ad:44:7b:0b:bd:db:ba:
|
||||
63:8d:07:c6:9d:dc:46:cc:63:40:ba:5e:45:82:dd:9a:e5:50:
|
||||
e8:e7:d7:27:88:fc:6f:1d:8a:e7:5c:49:28:aa:10:29:75:28:
|
||||
c7:52:de:f9
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC9zCCAd+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
|
||||
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
|
||||
ZDAeFw0xNzAxMTAwMDA4NTJaFw00NDA1MjgwMDA4NTJaMBwxGjAYBgNVBAMMESou
|
||||
bmdpbngtcHJveHkudGxkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
|
||||
y0X0FJv+ZIV5SjaNPdEn0Hw2KDDmc4BvfEkj0GwX5ETAd02awrwkhOOlTbrS2lF7
|
||||
oSoS1MAZVWksIictGvb8S3/py6g86Gm40k/eTlDi0HQwfEJarqqFpbFxTcl+hoti
|
||||
jD4N4zvD9YELjGh5/r8Q+67sEUltZF4afbOSk06WGTqYBKdmsnRhLUETDKRUDSx4
|
||||
/bSj6Dd4mt76vC6oD2cUWM7Dh9UUDospfUgZsqn1tOivMiFnFX5DUosgz584Q7/9
|
||||
yCR/UqOI8vFKFJEqbpFv+31qeMZtLt0eTCtjuzpDnJH539MIE2OGfc7oRs/xbB/K
|
||||
90ze2Evg2rwG2YcP/5ZFhQIDAQABoyAwHjAcBgNVHREEFTATghEqLm5naW54LXBy
|
||||
b3h5LnRsZDANBgkqhkiG9w0BAQsFAAOCAQEAbqUO5NPM1bf8NHWJTpiM5wgGqFvs
|
||||
E32DmaJhuNUSbsW0U06aIs2tFDBqfVjXI9mkKpagQJ5Qn87y/ozdmqyZOVuJLcrl
|
||||
PsO8AwQcEtluuJ/wOr4SRH6kIYZzr9UAUT8sVnA0jyawf7DPz3/5QG8AKcTPw7fC
|
||||
ST0/sCZ4h7nHbBuqahrdxevyabptRguSSbURPOtIxy/7M6ZqgqKr+B5ffeO38v31
|
||||
iKUJTaC89DvN0ovXVx+GO9I+pJIhsAIL6eDEHPF44linJl9MKcgj8G4SP72tRHsL
|
||||
vdu6Y40Hxp3cRsxjQLpeRYLdmuVQ6OfXJ4j8bx2K51xJKKoQKXUox1Le+Q==
|
||||
-----END CERTIFICATE-----
|
27
test2/certs/*.nginx-proxy.tld.key
Normal file
27
test2/certs/*.nginx-proxy.tld.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAy0X0FJv+ZIV5SjaNPdEn0Hw2KDDmc4BvfEkj0GwX5ETAd02a
|
||||
wrwkhOOlTbrS2lF7oSoS1MAZVWksIictGvb8S3/py6g86Gm40k/eTlDi0HQwfEJa
|
||||
rqqFpbFxTcl+hotijD4N4zvD9YELjGh5/r8Q+67sEUltZF4afbOSk06WGTqYBKdm
|
||||
snRhLUETDKRUDSx4/bSj6Dd4mt76vC6oD2cUWM7Dh9UUDospfUgZsqn1tOivMiFn
|
||||
FX5DUosgz584Q7/9yCR/UqOI8vFKFJEqbpFv+31qeMZtLt0eTCtjuzpDnJH539MI
|
||||
E2OGfc7oRs/xbB/K90ze2Evg2rwG2YcP/5ZFhQIDAQABAoIBAQCjAro2PNLJMfCO
|
||||
fyjNRgmzu6iCmpR0U68T8GN0JPsT576g7e8J828l0pkhuIyW33lRSThIvLSUNf9a
|
||||
dChL032H3lBTLduKVh4NKleQXnVFzaeEPoISSFVdButiAhAhPW4OIUVp0OfY3V+x
|
||||
fac3j2nDLAfL5SKAtqZv363Py9m66EBYm5BmGTQqT/frQWeCEBvlErQef5RIaU8p
|
||||
e2zMWgSNNojVai8U3nKNRvYHWeWXM6Ck7lCvkHhMF+RpbmCZuqhbEARVnehU/Jdn
|
||||
QHJ3nxeA2OWpoWKXvAHtSnno49yxq1UIstiQvY+ng5C5i56UlB60UiU2NJ6doZkB
|
||||
uQ7/1MaBAoGBAORdcFtgdgRALjXngFWhpCp0CseyUehn1KhxDCG+D1pJ142/ymcf
|
||||
oJOzKJPMRNDdDUBMnR1GBfy7rmwvYevI/SMNy2Qs7ofcXPbdtwwvTCToZ1V9/54k
|
||||
VfuPBFT+3QzWRvG1tjTV3E4L2VV3nrl2qNPhE5DlfIaU3nQq5Fl0HprJAoGBAOPf
|
||||
MWOTGev61CdODO5KN3pLAoamiPs5lEUlz3kM3L1Q52YLITxNDjRj9hWBUATJZOS2
|
||||
pLOoYRwmhD7vrnimMc41+NuuFX+4T7hWPc8uSuOxX0VijYtULyNRK57mncG1Fq9M
|
||||
RMLbOJ7FD+8jdXNsSMqpQ+pxLJRX/A10O2fOQnbdAoGAL5hV4YWSM0KZHvz332EI
|
||||
ER0MXiCJN7HkPZMKH0I4eu3m8hEmAyYxVndBnsQ1F37q0xrkqAQ/HTSUntGlS/og
|
||||
4Bxw5pkCwegoq/77tpto+ExDtSrEitYx4XMmSPyxX4qNULU5m3tzJgUML+b1etwD
|
||||
Rd2kMU/TC02dq4KBAy/TbRkCgYAl1xN5iJz+XenLGR/2liZ+TWR+/bqzlU006mF4
|
||||
pZUmbv/uJxz+yYD5XDwqOA4UrWjuvhG9r9FoflDprp2XdWnB556KxG7XhcDfSJr9
|
||||
A5/2DadXe1Ur9O/a+oi2228JEsxQkea9QPA3FVxfBtFjOHEiDlez39VaUP4PMeUH
|
||||
iO3qlQKBgFQhdTb7HeYnApYIDHLmd1PvjRvp8XKR1CpEN0nkw8HpHcT1q1MUjQCr
|
||||
iT6FQupULEvGmO3frQsgVeRIQDbEdZK3C5xCtn6qOw70sYATVf361BbTtidmU9yV
|
||||
THFxwDSVLiVZgFryoY/NtAc27sVdJnGsPRjjaeVgALAsLbmZ1K/H
|
||||
-----END RSA PRIVATE KEY-----
|
81
test2/certs/README.md
Normal file
81
test2/certs/README.md
Normal file
@ -0,0 +1,81 @@
|
||||
create_server_certificate.sh
|
||||
============================
|
||||
|
||||
`create_server_certificate.sh` is a script helping with issuing server certificates that can be used to provide TLS on web servers.
|
||||
|
||||
It also creates a Certificate Authority (CA) root key and certificate. This CA root certificate can be used to validate the server certificates it generates.
|
||||
|
||||
For instance, with _curl_:
|
||||
|
||||
curl --cacert /somewhere/ca-root.crt https://www.example.com/
|
||||
|
||||
or with _wget_:
|
||||
|
||||
wget --certificate=/somewhere/ca-root.crt https://www.example.com/
|
||||
|
||||
or with the python _requests_ module:
|
||||
|
||||
import requests
|
||||
r = requests.get("https://www.example.com", verify="/somewhere/ca-root.crt")
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
### Simple domain
|
||||
|
||||
Create a server certificate for domain `www.example.com`:
|
||||
|
||||
./create_server_certificate.sh www.example.com
|
||||
|
||||
Will produce:
|
||||
- `www.example.com.key`
|
||||
- `www.example.com.crt`
|
||||
|
||||
|
||||
### Multiple domains
|
||||
|
||||
Create a server certificate for main domain `www.example.com` and alternative domains `example.com`, `foo.com` and `bar.com`:
|
||||
|
||||
./create_server_certificate.sh www.example.com foo.com bar.com
|
||||
|
||||
Will produce:
|
||||
- `www.example.com.key`
|
||||
- `www.example.com.crt`
|
||||
|
||||
### Wildcard domain
|
||||
|
||||
Create a server certificate for wildcard domain `*.example.com`:
|
||||
|
||||
./create_server_certificate.sh "*.example.com"
|
||||
|
||||
Note that you need to use quotes around the domain string or the shell would expand `*`.
|
||||
|
||||
Will produce:
|
||||
- `*.example.com.key`
|
||||
- `*.example.com.crt`
|
||||
|
||||
Again, to prevent your shell from expanding `*`, use quotes. i.e.: `cat "*.example.com.crt"`.
|
||||
|
||||
Such a server certificate would be valid for domains:
|
||||
- `foo.example.com`
|
||||
- `bar.example.com`
|
||||
|
||||
but not for domains:
|
||||
- `example.com`
|
||||
- `foo.bar.example.com`
|
||||
|
||||
|
||||
### Wildcard domain on multiple levels
|
||||
|
||||
While you can technically create a server certificate for wildcard domain `*.example.com` and alternative name `*.*.example.com`, client implementations generally do not support multiple wildcards in a domain name.
|
||||
|
||||
For instance, a python script using urllib3 would fail to validate domain `foo.bar.example.com` presenting a certificate with name `*.*.example.com`. It is advised to stay away from producing such certificates.
|
||||
|
||||
If you want to give it a try:
|
||||
|
||||
./create_server_certificate.sh "*.example.com" "*.*.example.com"
|
||||
|
||||
Such a server certificate would be valid for domains:
|
||||
- `foo.example.com`
|
||||
- `bar.example.com`
|
||||
- `foo.bar.example.com`
|
21
test2/certs/ca-root.crt
Normal file
21
test2/certs/ca-root.crt
Normal file
@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDZDCCAkygAwIBAgIJAJmW6Ju6iJNNMA0GCSqGSIb3DQEBCwUAMD8xHzAdBgNV
|
||||
BAoMFm5naW54LXByb3h5IHRlc3Qgc3VpdGUxHDAaBgNVBAMME3d3dy5uZ2lueC1w
|
||||
cm94eS50bGQwHhcNMTcwMTEwMDAwODUxWhcNMjcwMTA4MDAwODUxWjA/MR8wHQYD
|
||||
VQQKDBZuZ2lueC1wcm94eSB0ZXN0IHN1aXRlMRwwGgYDVQQDDBN3d3cubmdpbngt
|
||||
cHJveHkudGxkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAndjE3OPr
|
||||
48hIOQigk/HejrowsQDLNfkkc6vej0J983rJitGTgBfxqq27fOPfqhE5bi1M5JDk
|
||||
KkrOrSitxCJLgpq+4Ls9/RXg8skZFHRAQbNwuKBehaDkPdamJ0i3dv6e4kZy41oI
|
||||
RqxQ/MKdminC4LShFZvPoKeh9ae7w1MgB2/4E68LO66bYiHlLNL7ENViSHhLyCmt
|
||||
qIE7kdV9jgn2NuVJ37m6/6SNQ3GBiIjEW+ooRQ3HEVKBCismcwq80+BD5VS/yW18
|
||||
KqX8m4sBM+IgZbcOqrV+APMbGvd8iNJgQSSQC/r0Wscgt7UeggVYKDazjDSPvLUE
|
||||
FUN5wEmydkP2AQIDAQABo2MwYTAdBgNVHQ4EFgQUJL59pHomt+8dUNxv8HgrYjKf
|
||||
OA8wHwYDVR0jBBgwFoAUJL59pHomt+8dUNxv8HgrYjKfOA8wDwYDVR0TAQH/BAUw
|
||||
AwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggEBABALxY96YqsZ
|
||||
CL2crzY0FIGhfjLE7P3mtUGklUpFu7xyI6mGUyL1nJYSnHB5IEV6QLhVVUE/CojI
|
||||
crXorQWBDkx26AgCt/eIOdvPYC0JDeXiIhH6sld3yH7JGwGqJkfXaUUfUkuwMae7
|
||||
mMIEG9e6vfSh/YNTRxs0KBjBcXHHl5K+Dz4h9r14OqnQFqVFZaR6T6td44tDDNhn
|
||||
beW8iIfCWRqDsnvIcJzLa2QR4onmJSw5DaSeFFaKefhdHEzEBZntLfyFbjRYHT/O
|
||||
+BRdewhg6rSDkGLcL8n/ZnRLOa+xmegjQ/Op94OmWO3TfXOITJAtkaO2YVZoyek8
|
||||
T6ckVovq4zU=
|
||||
-----END CERTIFICATE-----
|
27
test2/certs/ca-root.key
Normal file
27
test2/certs/ca-root.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAndjE3OPr48hIOQigk/HejrowsQDLNfkkc6vej0J983rJitGT
|
||||
gBfxqq27fOPfqhE5bi1M5JDkKkrOrSitxCJLgpq+4Ls9/RXg8skZFHRAQbNwuKBe
|
||||
haDkPdamJ0i3dv6e4kZy41oIRqxQ/MKdminC4LShFZvPoKeh9ae7w1MgB2/4E68L
|
||||
O66bYiHlLNL7ENViSHhLyCmtqIE7kdV9jgn2NuVJ37m6/6SNQ3GBiIjEW+ooRQ3H
|
||||
EVKBCismcwq80+BD5VS/yW18KqX8m4sBM+IgZbcOqrV+APMbGvd8iNJgQSSQC/r0
|
||||
Wscgt7UeggVYKDazjDSPvLUEFUN5wEmydkP2AQIDAQABAoIBAQCDM4zetix6lx1B
|
||||
GuSuVFrTc/vJBInkgQRFiVRi67fZS/R+CJl73WsonWO7+YUNzWdZJxpE2hJs/OUx
|
||||
lSBqaL8u/gUuszRhS3BBHdpU4BQRCF/ndpVaqVNN+z78ZDrrE9Vo63nPdCRw6gYf
|
||||
MnzhiVjMghdq6Kn6NZwvno45WrzCsIbrrQ4zU+S2PhG8MTA53jzqqQ8mUSJX0lAl
|
||||
6b9+1aWA0d0Jnk3M3doaFU/Dlnz3n6kkx0AdqNe8bdsFrPfwsrF+dwGx04SGgLmK
|
||||
V2OjIDFYYGtiHp3PJ9IYIA32ij+UloSDDZ2BxXkma8Zilw04ytY5l8tlk2ZDWTD9
|
||||
U2MXxjmBAoGBAMmmI19I/asTPjljlqzrOsrdRkklJvnCHgy/yw9u3nMfkJ0lLGAp
|
||||
mZoCqJIEsAqlLGM5bOjKy3KQ3n2SBX3mz7/RajnpJRTnNLeJIPAAXHN9TDyKcWRo
|
||||
Los6xHN7YMSLYKs4HMihXp9Yu4Ms88/8nO/01nufjN0rTgFnWdL0WfxJAoGBAMhk
|
||||
Qm92ukMmbrXSrV0WF+eFooHwgPmUWZ1oZY5ZHmO3FCuSBHiICGrWKmdbcG6H5zmZ
|
||||
oFZ0unsvk2Yjl+/+tntxr/dwp6Q+chsqkLms8GE76NWEO8qn4hQNywkFgpKlPci3
|
||||
n5IqpuQ2DpJ1PAQkwgZD/5rSscNidNMezXO5Uvv5AoGBALR291kjXcJpKlr6AbMn
|
||||
oipD9c8obMVBMNuAGh7pvjORoD7DMf+tu0XV8z8a6uHcCOmUTx/XvlP9yuDeegO/
|
||||
OVYV+NdzDDi04r0PAGdKK3NAQ6Y60Fhn1J/OLFqdpHDBu/X/9eKoaKJ7KvWumVUe
|
||||
YuVtXTauB8c4JkujTwQ4ov/hAoGAHxvhbGhkFhSbT0K7gx3w7BJE3iM2AojTOKqC
|
||||
SYzwOM6tJO5wHz4PAHbq8kyxsZcLgFenGoTYhlMmcM7JwYorThKiHKmyfL7s++ap
|
||||
vQlp785bIPp8RcO2RyK1CFuAn79jTgujjA9vBTKXJIlqncIPFOXtgl1/FzPrqvK3
|
||||
NmXoyhECgYEAje9hM9RYO0jbfmTZoQh+onMRz34SM9XWLH+NQGgfvsGtjeRnrUKK
|
||||
GuWQz/GQGJLy/Uc1KHIdrfPDjvQhZXmPL1v7pNfCrqyj+EnKCNDPPnYq5Zq4WLsB
|
||||
x1hKPH0LmfEBkXOiFGrD3h3KAuBK5nb0/EFBDR4JuMaySC5CpbOds9o=
|
||||
-----END RSA PRIVATE KEY-----
|
183
test2/certs/create_server_certificate.sh
Executable file
183
test2/certs/create_server_certificate.sh
Executable file
@ -0,0 +1,183 @@
|
||||
#!/bin/bash
|
||||
set -u
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
cat <<-EOF
|
||||
|
||||
To generate a server certificate, provide the domain name as a parameter:
|
||||
$(basename $0) www.my-domain.tdl
|
||||
$(basename $0) www.my-domain.tdl alternate.domain.tld
|
||||
|
||||
You can also create certificates for wildcard domains:
|
||||
$(basename $0) '*.my-domain.tdl'
|
||||
|
||||
EOF
|
||||
exit 0
|
||||
else
|
||||
DOMAIN="$1"
|
||||
ALTERNATE_DOMAINS="DNS:$( echo "$@" | sed 's/ /,DNS:/g')"
|
||||
fi
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Create a nginx container (which conveniently provides the `openssl` command)
|
||||
###############################################################################
|
||||
|
||||
CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.11.8)
|
||||
# Configure openssl
|
||||
docker exec $CONTAINER bash -c '
|
||||
mkdir -p /ca/{certs,crl,private,newcerts} 2>/dev/null
|
||||
echo 1000 > /ca/serial
|
||||
touch /ca/index.txt
|
||||
cat > /ca/openssl.cnf <<-"OESCRIPT"
|
||||
[ ca ]
|
||||
# `man ca`
|
||||
default_ca = CA_default
|
||||
|
||||
[ CA_default ]
|
||||
# Directory and file locations.
|
||||
dir = /ca
|
||||
certs = $dir/certs
|
||||
crl_dir = $dir/crl
|
||||
new_certs_dir = $dir/newcerts
|
||||
database = $dir/index.txt
|
||||
serial = $dir/serial
|
||||
RANDFILE = $dir/private/.rand
|
||||
|
||||
# The root key and root certificate.
|
||||
private_key = /work/ca-root.key
|
||||
certificate = /work/ca-root.crt
|
||||
|
||||
# SHA-1 is deprecated, so use SHA-2 instead.
|
||||
default_md = sha256
|
||||
|
||||
name_opt = ca_default
|
||||
cert_opt = ca_default
|
||||
default_days = 10000
|
||||
preserve = no
|
||||
policy = policy_loose
|
||||
|
||||
[ policy_loose ]
|
||||
countryName = optional
|
||||
stateOrProvinceName = optional
|
||||
localityName = optional
|
||||
organizationName = optional
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
[ req ]
|
||||
# Options for the `req` tool (`man req`).
|
||||
default_bits = 2048
|
||||
distinguished_name = req_distinguished_name
|
||||
string_mask = utf8only
|
||||
|
||||
# SHA-1 is deprecated, so use SHA-2 instead.
|
||||
default_md = sha256
|
||||
|
||||
# Extension to add when the -x509 option is used.
|
||||
x509_extensions = v3_ca
|
||||
|
||||
[ req_distinguished_name ]
|
||||
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
|
||||
countryName = Country Name (2 letter code)
|
||||
stateOrProvinceName = State or Province Name
|
||||
localityName = Locality Name
|
||||
0.organizationName = Organization Name
|
||||
organizationalUnitName = Organizational Unit Name
|
||||
commonName = Common Name
|
||||
emailAddress = Email Address
|
||||
|
||||
[ v3_ca ]
|
||||
# Extensions for a typical CA (`man x509v3_config`).
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer
|
||||
basicConstraints = critical, CA:true
|
||||
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
||||
|
||||
[ server_cert ]
|
||||
# Extensions for server certificates (`man x509v3_config`).
|
||||
basicConstraints = CA:FALSE
|
||||
nsCertType = server
|
||||
nsComment = server certificate generated for test purpose (nginx-proxy test suite)
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid,issuer:always
|
||||
keyUsage = critical, digitalSignature, keyEncipherment
|
||||
extendedKeyUsage = serverAuth
|
||||
|
||||
[ san_env ]
|
||||
subjectAltName=${ENV::SAN}
|
||||
OESCRIPT
|
||||
'
|
||||
|
||||
# shortcut for calling `openssl` inside the container
|
||||
function openssl {
|
||||
docker exec $CONTAINER openssl "$@"
|
||||
}
|
||||
|
||||
function exitfail {
|
||||
echo
|
||||
echo ERROR: "$@"
|
||||
docker rm -f $CONTAINER
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Setup Certificate authority
|
||||
###############################################################################
|
||||
|
||||
if ! [[ -f "$DIR/ca-root.key" ]]; then
|
||||
echo
|
||||
echo "> Create a Certificate Authority root key: $DIR/ca-root.key"
|
||||
openssl genrsa -out ca-root.key 2048
|
||||
[[ $? -eq 0 ]] || exitfail failed to generate CA root key
|
||||
fi
|
||||
|
||||
# Create a CA root certificate
|
||||
if ! [[ -f "$DIR/ca-root.crt" ]]; then
|
||||
echo
|
||||
echo "> Create a CA root certificate: $DIR/ca-root.crt"
|
||||
openssl req -config /ca/openssl.cnf \
|
||||
-key ca-root.key \
|
||||
-new -x509 -days 3650 -subj "/O=nginx-proxy test suite/CN=www.nginx-proxy.tld" -extensions v3_ca \
|
||||
-out ca-root.crt
|
||||
[[ $? -eq 0 ]] || exitfail failed to generate CA root certificate
|
||||
|
||||
# Verify certificate
|
||||
openssl x509 -noout -text -in ca-root.crt
|
||||
fi
|
||||
|
||||
|
||||
###############################################################################
|
||||
# create server key and certificate signed by the certificate authority
|
||||
###############################################################################
|
||||
|
||||
echo
|
||||
echo "> Create a host key: $DIR/$DOMAIN.key"
|
||||
openssl genrsa -out "$DOMAIN.key" 2048
|
||||
|
||||
echo
|
||||
echo "> Create a host certificate signing request"
|
||||
|
||||
SAN="$ALTERNATE_DOMAINS" openssl req -config /ca/openssl.cnf \
|
||||
-key "$DOMAIN.key" \
|
||||
-new -out "/ca/$DOMAIN.csr" -days 1000 -extensions san_env -subj "/CN=$DOMAIN"
|
||||
[[ $? -eq 0 ]] || exitfail failed to generate server certificate signing request
|
||||
|
||||
echo
|
||||
echo "> Create server certificate: $DIR/$DOMAIN.crt"
|
||||
SAN="$ALTERNATE_DOMAINS" openssl ca -config /ca/openssl.cnf -batch \
|
||||
-extensions server_cert \
|
||||
-extensions san_env \
|
||||
-in "/ca/$DOMAIN.csr" \
|
||||
-out "$DOMAIN.crt"
|
||||
[[ $? -eq 0 ]] || exitfail failed to generate server certificate
|
||||
|
||||
|
||||
# Verify host certificate
|
||||
#openssl x509 -noout -text -in "$DOMAIN.crt"
|
||||
|
||||
|
||||
docker rm -f $CONTAINER >/dev/null
|
70
test2/certs/web.nginx-proxy.tld.crt
Normal file
70
test2/certs/web.nginx-proxy.tld.crt
Normal file
@ -0,0 +1,70 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 4096 (0x1000)
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld
|
||||
Validity
|
||||
Not Before: Jan 13 03:06:39 2017 GMT
|
||||
Not After : May 31 03:06:39 2044 GMT
|
||||
Subject: CN=web.nginx-proxy.tld
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:95:56:c7:0d:48:a5:2b:3c:65:49:3f:26:e1:38:
|
||||
2b:61:30:56:e4:92:d7:63:e0:eb:ad:ac:f9:33:9b:
|
||||
b2:31:f1:39:13:0b:e5:43:7b:c5:bd:8a:85:c8:d9:
|
||||
3d:d8:ac:71:ba:16:e7:81:96:b2:ab:ae:c6:c0:bd:
|
||||
be:a7:d1:96:8f:b2:9b:df:ba:f9:4d:a1:3b:7e:21:
|
||||
4a:cd:b6:45:f9:6d:79:50:bf:24:8f:c1:6b:c1:09:
|
||||
19:5b:62:cb:96:e8:04:14:20:e8:d4:16:62:6a:f2:
|
||||
37:c1:96:e2:9d:53:05:0b:52:1d:e7:68:92:db:8b:
|
||||
36:68:cd:8d:5b:02:ff:12:f0:ac:5d:0c:c4:e0:7a:
|
||||
55:a2:49:60:9f:ff:47:1f:52:73:55:4d:d4:f2:d1:
|
||||
62:a2:f4:50:9d:c9:f6:f1:43:b3:dc:57:e1:31:76:
|
||||
b4:e0:a4:69:7e:f2:6d:34:ae:b9:8d:74:26:7b:d9:
|
||||
f6:07:00:ef:4b:36:61:b3:ef:7a:a1:36:3a:b6:d0:
|
||||
9e:f8:b8:a9:0d:4c:30:a2:ed:eb:ab:6b:eb:2e:e2:
|
||||
0b:28:be:f7:04:b1:e9:e0:84:d6:5d:31:77:7c:dc:
|
||||
d2:1f:d4:1d:71:6f:6f:6c:6d:1b:bf:31:e2:5b:c3:
|
||||
52:d0:14:fc:8b:fb:45:ea:41:ec:ca:c7:3b:67:12:
|
||||
c4:df
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:web.nginx-proxy.tld
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
4e:48:7d:81:66:ba:2f:50:3d:24:42:61:3f:1f:de:cf:ec:1b:
|
||||
1b:bd:0a:67:b6:62:c8:79:9d:31:a0:fd:a9:61:ce:ff:69:bf:
|
||||
0e:f4:f7:e6:15:2b:b0:f0:e4:f2:f4:d2:8f:74:02:b1:1e:4a:
|
||||
a8:6f:26:0a:77:32:29:cf:dc:b5:61:82:3e:58:47:61:92:f0:
|
||||
0c:20:25:f8:41:4d:34:09:44:bc:39:9e:aa:82:06:83:13:8b:
|
||||
1e:2c:3d:cf:cd:1a:f7:77:39:38:e0:a3:a7:f3:09:da:02:8d:
|
||||
73:75:38:b4:dd:24:a7:f9:03:db:98:c6:88:54:87:dc:e0:65:
|
||||
4c:95:c5:39:9c:00:30:dc:f0:d3:2c:19:ca:f1:f4:6c:c6:d9:
|
||||
b5:c4:4a:c7:bc:a1:2e:88:7b:b5:33:d0:ff:fb:48:5e:3e:29:
|
||||
fa:58:e5:03:de:d8:17:de:ed:96:fc:7e:1f:fe:98:f6:be:99:
|
||||
38:87:51:c0:d3:b7:9a:0f:26:92:e5:53:1b:d6:25:4c:ac:48:
|
||||
f3:29:fc:74:64:9d:07:6a:25:57:24:aa:a7:70:fa:8f:6c:a7:
|
||||
2b:b7:9d:81:46:10:32:93:b9:45:6d:0f:16:18:b2:21:1f:f3:
|
||||
30:24:62:3f:e1:6c:07:1d:71:28:cb:4c:bb:f5:39:05:f9:b2:
|
||||
5b:a0:05:1b
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC+zCCAeOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
|
||||
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
|
||||
ZDAeFw0xNzAxMTMwMzA2MzlaFw00NDA1MzEwMzA2MzlaMB4xHDAaBgNVBAMME3dl
|
||||
Yi5uZ2lueC1wcm94eS50bGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
||||
AQCVVscNSKUrPGVJPybhOCthMFbkktdj4OutrPkzm7Ix8TkTC+VDe8W9ioXI2T3Y
|
||||
rHG6FueBlrKrrsbAvb6n0ZaPspvfuvlNoTt+IUrNtkX5bXlQvySPwWvBCRlbYsuW
|
||||
6AQUIOjUFmJq8jfBluKdUwULUh3naJLbizZozY1bAv8S8KxdDMTgelWiSWCf/0cf
|
||||
UnNVTdTy0WKi9FCdyfbxQ7PcV+ExdrTgpGl+8m00rrmNdCZ72fYHAO9LNmGz73qh
|
||||
Njq20J74uKkNTDCi7eura+su4gsovvcEsenghNZdMXd83NIf1B1xb29sbRu/MeJb
|
||||
w1LQFPyL+0XqQezKxztnEsTfAgMBAAGjIjAgMB4GA1UdEQQXMBWCE3dlYi5uZ2lu
|
||||
eC1wcm94eS50bGQwDQYJKoZIhvcNAQELBQADggEBAE5IfYFmui9QPSRCYT8f3s/s
|
||||
Gxu9Cme2Ysh5nTGg/alhzv9pvw709+YVK7Dw5PL00o90ArEeSqhvJgp3MinP3LVh
|
||||
gj5YR2GS8AwgJfhBTTQJRLw5nqqCBoMTix4sPc/NGvd3OTjgo6fzCdoCjXN1OLTd
|
||||
JKf5A9uYxohUh9zgZUyVxTmcADDc8NMsGcrx9GzG2bXESse8oS6Ie7Uz0P/7SF4+
|
||||
KfpY5QPe2Bfe7Zb8fh/+mPa+mTiHUcDTt5oPJpLlUxvWJUysSPMp/HRknQdqJVck
|
||||
qqdw+o9spyu3nYFGEDKTuUVtDxYYsiEf8zAkYj/hbAcdcSjLTLv1OQX5slugBRs=
|
||||
-----END CERTIFICATE-----
|
27
test2/certs/web.nginx-proxy.tld.key
Normal file
27
test2/certs/web.nginx-proxy.tld.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAlVbHDUilKzxlST8m4TgrYTBW5JLXY+Drraz5M5uyMfE5Ewvl
|
||||
Q3vFvYqFyNk92KxxuhbngZayq67GwL2+p9GWj7Kb37r5TaE7fiFKzbZF+W15UL8k
|
||||
j8FrwQkZW2LLlugEFCDo1BZiavI3wZbinVMFC1Id52iS24s2aM2NWwL/EvCsXQzE
|
||||
4HpVoklgn/9HH1JzVU3U8tFiovRQncn28UOz3FfhMXa04KRpfvJtNK65jXQme9n2
|
||||
BwDvSzZhs+96oTY6ttCe+LipDUwwou3rq2vrLuILKL73BLHp4ITWXTF3fNzSH9Qd
|
||||
cW9vbG0bvzHiW8NS0BT8i/tF6kHsysc7ZxLE3wIDAQABAoIBAEmK7IecKMq7+V0y
|
||||
3mC3GpXICmKR9cRX9XgX4LkLiZuSoXrBtuuevmhzGSMp6I0VjwQHV4a3wdFORs6Q
|
||||
Ip3eVvj5Ck4Jc9BJAFVC6+WWR6tnwACFwOmSZRAw/O3GH2B3bdrDwiT/yQPFuLN7
|
||||
LKoxQiCrFdLp6rh3PBosb9pMBXU7k/HUazIdgmSKg6/JIoo/4Gwyid04TF/4MI2l
|
||||
RscxtP5/ANtS8VgwBEqhgdafRJ4KnLEpgvswgIQvUKmduVhZQlzd0LMY8FbhKVqz
|
||||
Utg8gsXaTyH6df/nmgUIInxLMz/MKPnMkv99fS6Sp/hvYlGpLZFWBJ6unMq3lKEr
|
||||
LMbHfIECgYEAxB+5QWdVqG2r9loJlf8eeuNeMPml4P8Jmi5RKyJC7Cww6DMlMxOS
|
||||
78ZJfl4b3ZrWuyvhjOfX/aTq7kQaF1BI9o3KJBH8k6EtO4gI8KeNmDONyQk9zsrn
|
||||
ru8Zwr7hVbAo8fCXxCnmPzhDLsYg6f3BVOsQWoX2SFYKZ1GvkPfIReECgYEAwu6G
|
||||
qtgFb57Vim10ecfWGM6vrPxvyfqP+zlH/p4nR+aQ+2sFbt27D0B1byWBRZe4KQyw
|
||||
Vq6XiQ09Fk6MJr8E8iAr9GXPPHcqlYI6bbNc6YOP3jVSKut0tQdTUOHll4kYIY+h
|
||||
RS3VA3+BA//ADpWpywu+7RZRbaIECA+U2a224r8CgYB5PCMIixgoRaNHZeEHF+1/
|
||||
iY1wOOKRcxY8eOU0BLnZxHd3EiasrCzoi2pi80nGczDKAxYqRCcAZDHVl8OJJdf0
|
||||
kTGjmnrHx5pucmkUWn7s1vGOlGfgrQ0K1kLWX6hrj7m/1Tn7yOrLqbvd7hvqiTI5
|
||||
jBVP3/+eN5G2zIf61TC4AQKBgCX2Q92jojNhsF58AHHy+/vqzIWYx8CC/mVDe4TX
|
||||
kfjLqzJ7XhyAK/zFZdlWaX1/FYtRAEpxR+uV226rr1mgW7s3jrfS1/ADmRRyvyQ8
|
||||
CP0k9PCmW7EmF51lptEanRbMyRlIGnUZfuFmhF6eAO4WMXHsgKs1bHg4VCapuihG
|
||||
T1aLAoGACRGn1UxFuBGqtsh2zhhsBZE7GvXKJSk/eP7QJeEXUNpNjCpgm8kIZM5K
|
||||
GorpL7PSB8mwVlDl18TpMm3P7nz6YkJYte+HdjO7pg59H39Uvtg3tZnIrFxNxVNb
|
||||
YF62/yHfk2AyTgjQZQUSmDS84jq1zUK4oS90lxr+u8qwELTniMs=
|
||||
-----END RSA PRIVATE KEY-----
|
71
test2/certs/web2.nginx-proxy.tld.crt
Normal file
71
test2/certs/web2.nginx-proxy.tld.crt
Normal file
@ -0,0 +1,71 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 4096 (0x1000)
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld
|
||||
Validity
|
||||
Not Before: Jan 10 00:37:02 2017 GMT
|
||||
Not After : May 28 00:37:02 2044 GMT
|
||||
Subject: CN=web2.nginx-proxy.tld
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:da:ee:46:2d:44:7c:f1:e6:91:11:bf:34:d6:02:
|
||||
4e:fe:43:23:fb:6d:20:f7:8d:1b:c6:9c:cd:1c:1a:
|
||||
07:95:c2:ed:b9:23:73:c1:02:2b:50:51:3f:33:cf:
|
||||
8e:aa:f1:13:58:4c:ff:7f:7d:4a:87:fc:f0:0f:54:
|
||||
af:8c:eb:ba:b4:0f:71:5e:12:1f:64:b1:3d:83:88:
|
||||
dd:9c:09:50:2d:37:1d:03:3b:18:30:36:f4:82:94:
|
||||
87:7f:31:27:28:84:0c:99:6d:77:b5:b8:4f:ca:83:
|
||||
58:d5:d8:4e:36:73:1c:1a:5c:ed:05:ef:95:60:03:
|
||||
28:0c:9f:d8:6f:98:a8:cd:08:be:af:b1:95:5a:60:
|
||||
96:fe:2a:d0:98:74:9b:4a:c0:48:66:73:67:54:33:
|
||||
11:22:20:ea:11:05:ba:a6:ed:74:12:05:d8:de:4f:
|
||||
01:46:39:74:d8:34:1a:f2:2c:c2:df:6d:94:57:52:
|
||||
c1:e4:2e:1b:8e:12:0e:43:e7:6f:1f:da:51:80:35:
|
||||
c2:8a:9b:b6:2a:30:39:6b:a0:77:fa:37:11:b7:ec:
|
||||
de:6e:8c:6f:93:81:5e:2d:90:69:1b:4b:a4:80:ca:
|
||||
f4:e5:5b:c0:13:45:b9:76:70:ed:d3:4e:dd:66:98:
|
||||
99:9f:9d:f0:1e:fd:dd:04:4f:9a:55:bc:38:ad:42:
|
||||
b9:dd
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:web2.nginx-proxy.tld
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
38:d6:8c:be:3c:5e:5d:61:02:77:eb:5b:6e:a7:1d:4f:69:0d:
|
||||
54:bd:dd:3a:1a:8e:9d:a0:c2:f3:a5:31:91:3e:ec:7a:69:48:
|
||||
40:27:45:a5:c6:b9:af:6d:d9:76:24:97:ec:c5:cf:4d:cc:49:
|
||||
93:ab:bc:4f:01:7e:7a:57:73:4d:27:62:a6:68:bf:4c:00:2c:
|
||||
c0:f3:7b:b3:32:81:6b:96:20:0a:73:a0:85:b5:f8:07:10:88:
|
||||
e8:62:85:41:63:df:43:c5:f9:4b:90:89:6a:16:d9:a6:85:4a:
|
||||
04:1b:5e:75:d8:84:ae:69:c7:62:8f:f1:53:c8:c6:31:71:6d:
|
||||
0c:05:2d:bf:6e:b8:b8:7a:8c:73:6f:17:bb:5c:5a:67:51:12:
|
||||
af:e2:17:9c:40:0e:35:f6:59:93:69:45:14:74:33:c6:aa:04:
|
||||
76:8e:3c:a6:ac:f4:60:cb:53:eb:d6:63:1a:47:7b:be:11:8d:
|
||||
74:de:e8:e5:bc:de:1b:09:db:1b:87:89:b7:6a:20:0a:5e:fb:
|
||||
35:04:ab:b2:f7:4d:a1:86:65:1d:c7:c3:aa:30:15:3a:6e:66:
|
||||
f8:43:33:63:ac:fc:c1:58:48:5b:ec:a0:00:bf:d4:f1:06:03:
|
||||
79:ca:d5:b6:f2:39:0b:62:b4:fd:27:27:e9:37:52:21:ce:a4:
|
||||
32:8a:bb:c7
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC/TCCAeWgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
|
||||
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
|
||||
ZDAeFw0xNzAxMTAwMDM3MDJaFw00NDA1MjgwMDM3MDJaMB8xHTAbBgNVBAMMFHdl
|
||||
YjIubmdpbngtcHJveHkudGxkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
|
||||
AQEA2u5GLUR88eaREb801gJO/kMj+20g940bxpzNHBoHlcLtuSNzwQIrUFE/M8+O
|
||||
qvETWEz/f31Kh/zwD1SvjOu6tA9xXhIfZLE9g4jdnAlQLTcdAzsYMDb0gpSHfzEn
|
||||
KIQMmW13tbhPyoNY1dhONnMcGlztBe+VYAMoDJ/Yb5iozQi+r7GVWmCW/irQmHSb
|
||||
SsBIZnNnVDMRIiDqEQW6pu10EgXY3k8BRjl02DQa8izC322UV1LB5C4bjhIOQ+dv
|
||||
H9pRgDXCipu2KjA5a6B3+jcRt+zeboxvk4FeLZBpG0ukgMr05VvAE0W5dnDt007d
|
||||
ZpiZn53wHv3dBE+aVbw4rUK53QIDAQABoyMwITAfBgNVHREEGDAWghR3ZWIyLm5n
|
||||
aW54LXByb3h5LnRsZDANBgkqhkiG9w0BAQsFAAOCAQEAONaMvjxeXWECd+tbbqcd
|
||||
T2kNVL3dOhqOnaDC86UxkT7semlIQCdFpca5r23ZdiSX7MXPTcxJk6u8TwF+eldz
|
||||
TSdipmi/TAAswPN7szKBa5YgCnOghbX4BxCI6GKFQWPfQ8X5S5CJahbZpoVKBBte
|
||||
ddiErmnHYo/xU8jGMXFtDAUtv264uHqMc28Xu1xaZ1ESr+IXnEAONfZZk2lFFHQz
|
||||
xqoEdo48pqz0YMtT69ZjGkd7vhGNdN7o5bzeGwnbG4eJt2ogCl77NQSrsvdNoYZl
|
||||
HcfDqjAVOm5m+EMzY6z8wVhIW+ygAL/U8QYDecrVtvI5C2K0/Scn6TdSIc6kMoq7
|
||||
xw==
|
||||
-----END CERTIFICATE-----
|
27
test2/certs/web2.nginx-proxy.tld.key
Normal file
27
test2/certs/web2.nginx-proxy.tld.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEA2u5GLUR88eaREb801gJO/kMj+20g940bxpzNHBoHlcLtuSNz
|
||||
wQIrUFE/M8+OqvETWEz/f31Kh/zwD1SvjOu6tA9xXhIfZLE9g4jdnAlQLTcdAzsY
|
||||
MDb0gpSHfzEnKIQMmW13tbhPyoNY1dhONnMcGlztBe+VYAMoDJ/Yb5iozQi+r7GV
|
||||
WmCW/irQmHSbSsBIZnNnVDMRIiDqEQW6pu10EgXY3k8BRjl02DQa8izC322UV1LB
|
||||
5C4bjhIOQ+dvH9pRgDXCipu2KjA5a6B3+jcRt+zeboxvk4FeLZBpG0ukgMr05VvA
|
||||
E0W5dnDt007dZpiZn53wHv3dBE+aVbw4rUK53QIDAQABAoIBABeTCsl7E30017Ay
|
||||
h6z3yKvGbQx43tDpR/FmFwwMnX555AFImQFSi3l1ljmtAu7TUML0X5rJ0gm8qdjs
|
||||
xI6HH66d7xYzG2BLWZVdWoef1RtZUO11IpCmikO5XLHMiCvrtDOdPwO5WhYzeJBm
|
||||
X12rnX4VPYyjFNGm5Vwepj62EI8rS9G3NG00pDYPmN/vUQJiV/iTRIlvXgFm4Hl2
|
||||
zJhVi+NhyiptFEycdg65JwVfLKtmUXRmwGFiSxQi1FX8YS5EdIV2S8yDwXlWSxmq
|
||||
4R1eSID7pKxtzyRtBqZJggzfqtY8cMpoOC12FbLAvzagOavs4ntMgAVy5k2T15G2
|
||||
syQyLSECgYEA+1NIRF3CxNUaPvpcR8Y4PWhwDEzqn5ZscnXaFrUp1W72f3bpwSCa
|
||||
/t9lXe9O53R5/yt4nCbwvVM0UWYPHGZGQr+5AS7WWDVWVcwkXX1NIjALi0TXQ0Ty
|
||||
zeuViXDofUS31yhwFFmgGa52pd+edXaGRvxzGyPVdtwpSLZP/gBLQykCgYEA3wC9
|
||||
sHNPKMxi6vI2VBvmBXHoCSDAkuRLmQEGDmjjt0Ve4fmwGRbBJxniOlNtufNQRfRg
|
||||
67qaeM4BTrP03cilZ71yXvLN5G2opY5c/I0dYTXRhV3IV6XwlCC+0xmn+ro7kB8x
|
||||
J4wAj/h/tJ8T0+0TpnbyjmPH4KTJ9GjRTKwe65UCgYBszIHlbr2JXkONbe6S98GS
|
||||
++o9uPJ9Aa6S4mf2Gpkwl2fIiF7rR0Ux/t2wC5AZ7Ld/en8tAkKHg0SL1GXIQpI6
|
||||
BSt+0prh9r0YSVaYzkyc9zWYJcYWjfuan1jN9f3/dMctMolKlf4UAA3HAwZjDVtV
|
||||
0aW24w1e9jI9EweQCuqJ+QKBgBwZec18GiNn7abxMktS4J8bBUPxLpLT1XrIGD1E
|
||||
lj0HrrcGwVvH9Dq7FjiHPrJJqHnIG1ZYwxIp0xxZrKctmzoBMyInsi3wa2nBEJJ6
|
||||
LZOMNoR5lr8El9XyclkjSHldchfs9kKnb4K0q1LVIKh5nRpCrrmmdQ8ndJMpigYB
|
||||
QjwpAoGAWIhFrN0Acdq7Xc9pScqnAohPMWCTBUbeKrOm0ZwN4Q9D+lLeeggbWlWy
|
||||
AqR4WHQMHc6B+p4Ncg3XBCFw0V62PkYhSCdaLNH3CPyFT0qoeY8VuMjmqS7yoKvp
|
||||
uMMHfzMmyGg0dyplVGgANafb/it6Dp8T0pnCmzxhe57jf9xsVBo=
|
||||
-----END RSA PRIVATE KEY-----
|
71
test2/certs/web3.nginx-proxy.tld.crt
Normal file
71
test2/certs/web3.nginx-proxy.tld.crt
Normal file
@ -0,0 +1,71 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 4096 (0x1000)
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld
|
||||
Validity
|
||||
Not Before: Jan 10 00:58:11 2017 GMT
|
||||
Not After : May 28 00:58:11 2044 GMT
|
||||
Subject: CN=web3.nginx-proxy.tld
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:ac:9b:90:dc:2c:0d:c3:ae:f4:a0:cc:40:15:d2:
|
||||
c4:c2:2c:8c:15:b6:70:28:cf:32:c4:03:ce:b3:87:
|
||||
30:5d:a6:12:96:69:7a:fe:67:29:1c:8c:24:bb:6a:
|
||||
c8:86:13:19:91:00:3e:ef:00:67:50:b0:ea:c9:93:
|
||||
c6:8a:73:82:d8:37:9f:8e:6e:12:13:ec:fa:08:0f:
|
||||
ac:73:6e:42:96:67:9f:20:c5:1c:a3:b1:4a:83:36:
|
||||
0e:0a:31:93:76:b1:b6:37:4f:e0:88:3c:46:dc:c1:
|
||||
53:60:df:28:ae:3e:20:d8:d9:53:a2:be:09:38:f0:
|
||||
ff:4a:91:45:cb:cb:b5:b3:3d:7d:09:98:47:dc:0d:
|
||||
5e:83:73:b6:c9:f3:fb:9a:f2:bb:b0:62:ca:aa:af:
|
||||
6b:42:e5:08:b2:14:87:f4:fc:f1:14:f8:cc:76:b3:
|
||||
c0:49:df:66:c6:21:a0:bc:5e:0c:bb:de:e9:9c:e7:
|
||||
fb:31:a1:cf:c4:e9:bb:bd:c3:5a:0d:23:52:c6:b3:
|
||||
84:77:f1:0c:3d:ca:c3:60:48:f9:7e:a6:dc:4f:f7:
|
||||
d2:5b:7c:02:4d:38:09:64:33:7e:bb:b1:65:bb:e2:
|
||||
2b:1d:9a:49:d4:34:21:42:7a:49:3e:11:6c:10:66:
|
||||
b4:91:db:bd:3a:c2:8d:f4:e4:03:b1:b4:6e:5c:98:
|
||||
bf:7d
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:web3.nginx-proxy.tld
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
9a:f6:b9:c2:08:a4:b4:d7:e4:b2:d3:22:e9:fe:69:4a:e8:76:
|
||||
18:60:11:1b:3b:7c:4b:c3:72:66:95:b7:7c:de:c7:34:32:58:
|
||||
aa:5d:e0:12:f0:df:27:b6:3f:dd:f1:8c:ed:ce:bd:73:50:fc:
|
||||
9b:e1:8c:c2:7f:ac:6b:54:9d:23:0a:d9:a6:25:cc:99:94:73:
|
||||
2b:69:e8:f7:07:40:37:d3:d4:0b:14:86:6a:a1:01:53:4b:ae:
|
||||
85:2d:12:13:bd:23:1e:09:cf:20:50:24:76:a6:5f:b4:d6:d6:
|
||||
e1:34:40:93:4d:42:f7:d0:95:98:77:53:16:e7:ce:cc:4c:35:
|
||||
b8:30:3b:62:95:e2:40:0c:a1:73:84:92:93:63:df:c6:21:d5:
|
||||
eb:1d:a1:d0:f2:ec:a5:cf:d6:10:c9:8f:ac:11:16:39:cd:b0:
|
||||
38:04:29:cf:e1:1c:dd:21:df:1f:95:35:a5:a4:61:2b:3d:8b:
|
||||
8a:76:02:6d:31:a1:e8:6b:c5:3b:eb:90:40:34:16:5a:07:93:
|
||||
96:56:cd:8b:52:ca:65:51:78:d3:f2:af:40:44:43:ec:fe:a2:
|
||||
c8:d4:6d:21:c7:1f:d2:45:28:0d:d2:51:0f:d1:a5:db:00:2a:
|
||||
3a:10:88:9e:5a:76:a2:f7:e2:f0:fe:14:a3:e8:ec:ef:00:f0:
|
||||
35:87:eb:7c
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC/TCCAeWgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp
|
||||
bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs
|
||||
ZDAeFw0xNzAxMTAwMDU4MTFaFw00NDA1MjgwMDU4MTFaMB8xHTAbBgNVBAMMFHdl
|
||||
YjMubmdpbngtcHJveHkudGxkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
|
||||
AQEArJuQ3CwNw670oMxAFdLEwiyMFbZwKM8yxAPOs4cwXaYSlml6/mcpHIwku2rI
|
||||
hhMZkQA+7wBnULDqyZPGinOC2Defjm4SE+z6CA+sc25ClmefIMUco7FKgzYOCjGT
|
||||
drG2N0/giDxG3MFTYN8orj4g2NlTor4JOPD/SpFFy8u1sz19CZhH3A1eg3O2yfP7
|
||||
mvK7sGLKqq9rQuUIshSH9PzxFPjMdrPASd9mxiGgvF4Mu97pnOf7MaHPxOm7vcNa
|
||||
DSNSxrOEd/EMPcrDYEj5fqbcT/fSW3wCTTgJZDN+u7Flu+IrHZpJ1DQhQnpJPhFs
|
||||
EGa0kdu9OsKN9OQDsbRuXJi/fQIDAQABoyMwITAfBgNVHREEGDAWghR3ZWIzLm5n
|
||||
aW54LXByb3h5LnRsZDANBgkqhkiG9w0BAQsFAAOCAQEAmva5wgiktNfkstMi6f5p
|
||||
Suh2GGARGzt8S8NyZpW3fN7HNDJYql3gEvDfJ7Y/3fGM7c69c1D8m+GMwn+sa1Sd
|
||||
IwrZpiXMmZRzK2no9wdAN9PUCxSGaqEBU0uuhS0SE70jHgnPIFAkdqZftNbW4TRA
|
||||
k01C99CVmHdTFufOzEw1uDA7YpXiQAyhc4SSk2PfxiHV6x2h0PLspc/WEMmPrBEW
|
||||
Oc2wOAQpz+Ec3SHfH5U1paRhKz2LinYCbTGh6GvFO+uQQDQWWgeTllbNi1LKZVF4
|
||||
0/KvQERD7P6iyNRtIccf0kUoDdJRD9Gl2wAqOhCInlp2ovfi8P4Uo+js7wDwNYfr
|
||||
fA==
|
||||
-----END CERTIFICATE-----
|
27
test2/certs/web3.nginx-proxy.tld.key
Normal file
27
test2/certs/web3.nginx-proxy.tld.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEArJuQ3CwNw670oMxAFdLEwiyMFbZwKM8yxAPOs4cwXaYSlml6
|
||||
/mcpHIwku2rIhhMZkQA+7wBnULDqyZPGinOC2Defjm4SE+z6CA+sc25ClmefIMUc
|
||||
o7FKgzYOCjGTdrG2N0/giDxG3MFTYN8orj4g2NlTor4JOPD/SpFFy8u1sz19CZhH
|
||||
3A1eg3O2yfP7mvK7sGLKqq9rQuUIshSH9PzxFPjMdrPASd9mxiGgvF4Mu97pnOf7
|
||||
MaHPxOm7vcNaDSNSxrOEd/EMPcrDYEj5fqbcT/fSW3wCTTgJZDN+u7Flu+IrHZpJ
|
||||
1DQhQnpJPhFsEGa0kdu9OsKN9OQDsbRuXJi/fQIDAQABAoIBAA14DjPAFEriyiAK
|
||||
EC4jxkrIox3GoLXuhS2ahnSn5fRI00Z9cKWNcz3RCcS+LmuX7fTMqhyIUYeQZqHY
|
||||
MDP5k4o/vOmmWS7I3THn1zMitXt7FoW+G+ACI6hdfXb6K2GluGxUhVbcLUNoqpLy
|
||||
lwARxQpm2wnl/l49IA63i1S9zq3vy5HSvxBv3jq8xp2PX3Sho33LhsvW+miCJe+R
|
||||
etKSV4mAjvR62XVgUGJ40FciVMK3pzwwIKPLI7k9sa7WHZr6fNHeDxIWA6AsVBTH
|
||||
O+2l8Ufd79KesOD6VqdHlxg2a79s3NoCOflQQAbOSSR9ioCE7Ykgvw0wVl57xNoB
|
||||
WZVAY0ECgYEA2I6+a56NMzkEMxr0w9ZRqgocXCgbqxZx1v7newDyO5J3X4jYhmMJ
|
||||
abNZtnVs1Pz0IAgCMCf+N4D+RAi9/ahYxq7jmhIkT/IUHseh93XLgd/x9Q9ZJOGm
|
||||
9+NI3aIBgWOsy4orKxfwzRAVEakOCChYUCy/GUDDD1MPcjxC8ma5abUCgYEAzAua
|
||||
15Nayr9Sg0QsHqNvgTVkVlA6u+TwN+vfI8cH5nmXIMm5ShwCc9+Pm8mpcFwUo4uE
|
||||
vOzQ+NwG9CBbVu6/i1/aR+ZlbctdhpsW51v18B9eFVXSZUvEv1ONGdoJZhq0tW7W
|
||||
V4Zjf+UwdTcrSZKVpd5woUbRkByROPdir/3Ie6kCgYBhf5LX3SBxSWBMqfw9F4bY
|
||||
6YhvLVeXpZlHVKhfRsPIcl7wUio6Bui8ABWKAkAnfGNk8HYbvEXGM3tGojD3vQ2L
|
||||
Fj4+paBXpgPM/9A6G3yuUmcbD/fwlO+Zd2jc8A2BdaDcWq6ozjSJ/o2dz+ETZyar
|
||||
ohm/gtrPUXQI2HzDqeAcaQKBgEBMd+LvAHFbkPjkhrKw9fZViOTaK2gCYOB+Z7ay
|
||||
hX7PWhxu9QCxiuRQ0sRY7BgILEjNMmsGhWOmklpjx+TBH4MgFX0K0XOj3jkIrlMB
|
||||
26JrgA5hGQfqtHlGLvSyjLusNr3ly42RP9GRu490byOkGZxHWF66Hle3aNv2uRaU
|
||||
dpThAoGBAMIPpf4E6xGzurhgYdXMit3jGAYD85BbNUIm9jOym2lxS63ipoF08QhH
|
||||
NoMVRf/AUoS4VDGXsuABjMffTZbE8L+DaL1cWSuPJAoF9AXUXtz6A8LRc9Mn2WjS
|
||||
L8BIs9xZCzrJ5XzY4PSnjjyAU81z6E80azWglkmh8rRDzi/o9O79
|
||||
-----END RSA PRIVATE KEY-----
|
235
test2/conftest.py
Normal file
235
test2/conftest.py
Normal file
@ -0,0 +1,235 @@
|
||||
from __future__ import print_function
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import shlex
|
||||
import socket
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
import backoff
|
||||
import docker
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
logging.getLogger('backoff').setLevel(logging.INFO)
|
||||
logging.getLogger('patched DNS').setLevel(logging.INFO)
|
||||
|
||||
|
||||
CA_ROOT_CERTIFICATE = os.path.join(os.path.dirname(__file__), 'certs/ca-root.crt')
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# utilities
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
class requests_retry_on_error_502(object):
|
||||
"""
|
||||
Proxy for calling methods of the requests module.
|
||||
When a HTTP response failed due to HTTP Error 404 or 502, retry up to 30 times.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.session = requests.Session()
|
||||
if os.path.isfile(CA_ROOT_CERTIFICATE):
|
||||
self.session.verify = CA_ROOT_CERTIFICATE
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
@backoff.on_predicate(backoff.constant, lambda r: r.status_code in (404, 502), interval=1, max_tries=30)
|
||||
def _get(*args, **kwargs):
|
||||
return self.session.get(*args, **kwargs)
|
||||
return _get(*args, **kwargs)
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
@backoff.on_predicate(backoff.constant, lambda r: r.status_code in (404, 502), interval=1, max_tries=30)
|
||||
def _post(*args, **kwargs):
|
||||
return self.session.post(*args, **kwargs)
|
||||
return _post(*args, **kwargs)
|
||||
|
||||
def put(self, *args, **kwargs):
|
||||
@backoff.on_predicate(backoff.constant, lambda r: r.status_code in (404, 502), interval=1, max_tries=30)
|
||||
def _put(*args, **kwargs):
|
||||
return self.session.put(*args, **kwargs)
|
||||
return _put(*args, **kwargs)
|
||||
|
||||
def head(self, *args, **kwargs):
|
||||
@backoff.on_predicate(backoff.constant, lambda r: r.status_code in (404, 502), interval=1, max_tries=30)
|
||||
def _head(*args, **kwargs):
|
||||
return self.session.head(*args, **kwargs)
|
||||
return _head(*args, **kwargs)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
@backoff.on_predicate(backoff.constant, lambda r: r.status_code in (404, 502), interval=1, max_tries=30)
|
||||
def _delete(*args, **kwargs):
|
||||
return self.session.delete(*args, **kwargs)
|
||||
return _delete(*args, **kwargs)
|
||||
|
||||
def options(self, *args, **kwargs):
|
||||
@backoff.on_predicate(backoff.constant, lambda r: r.status_code in (404, 502), interval=1, max_tries=30)
|
||||
def _options(*args, **kwargs):
|
||||
return self.session.options(*args, **kwargs)
|
||||
return _options(*args, **kwargs)
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(requests, name)
|
||||
|
||||
|
||||
def monkey_patch_urllib_dns_resolver():
|
||||
"""
|
||||
Alter the behavior of the urllib DNS resolver so that any domain name
|
||||
containing substring 'nginx-proxy' will resolve to the IP address
|
||||
of the container created from image 'jwilder/nginx-proxy:test'.
|
||||
"""
|
||||
log = logging.getLogger("patched DNS")
|
||||
prv_getaddrinfo = socket.getaddrinfo
|
||||
dns_cache = {}
|
||||
def new_getaddrinfo(*args):
|
||||
log.debug("resolving domain name %s" % repr(args))
|
||||
if 'nginx-proxy' in args[0]:
|
||||
docker_client = docker.from_env()
|
||||
ip = docker_client.containers(filters={"status": "running", "ancestor": "jwilder/nginx-proxy:test"})[0]["NetworkSettings"]["Networks"]["bridge"]["IPAddress"]
|
||||
log.info("resolving domain name %r as IP address is %s" % (args[0], ip))
|
||||
return [
|
||||
(socket.AF_INET, socket.SOCK_STREAM, 6, '', (ip, args[1])),
|
||||
(socket.AF_INET, socket.SOCK_DGRAM, 17, '', (ip, args[1])),
|
||||
(socket.AF_INET, socket.SOCK_RAW, 0, '', (ip, args[1]))
|
||||
]
|
||||
|
||||
try:
|
||||
return dns_cache[args]
|
||||
except KeyError:
|
||||
res = prv_getaddrinfo(*args)
|
||||
dns_cache[args] = res
|
||||
return res
|
||||
socket.getaddrinfo = new_getaddrinfo
|
||||
return prv_getaddrinfo
|
||||
|
||||
def restore_urllib_dns_resolver(getaddrinfo_func):
|
||||
socket.getaddrinfo = getaddrinfo_func
|
||||
|
||||
|
||||
def remove_all_containers():
|
||||
docker_client = docker.from_env()
|
||||
for info in docker_client.containers(all=True):
|
||||
docker_client.remove_container(info["Id"], v=True, force=True)
|
||||
|
||||
|
||||
def get_nginx_conf_from_container(container_id):
|
||||
"""
|
||||
return the nginx /etc/nginx/conf.d/default.conf file content from a container
|
||||
"""
|
||||
import tarfile
|
||||
from cStringIO import StringIO
|
||||
docker_client = docker.from_env()
|
||||
strm, stat = docker_client.get_archive(container_id, '/etc/nginx/conf.d/default.conf')
|
||||
with tarfile.open(fileobj=StringIO(strm.read())) as tf:
|
||||
conffile = tf.extractfile('default.conf')
|
||||
return conffile.read()
|
||||
|
||||
|
||||
def docker_compose_up(compose_file='docker-compose.yml'):
|
||||
subprocess.check_output(shlex.split('docker-compose -f %s up -d' % compose_file))
|
||||
|
||||
|
||||
def wait_for_nginxproxy_to_be_ready():
|
||||
"""
|
||||
If a one (and only one) container started from image jwilder/nginx-proxy:test is found,
|
||||
wait for its log to contain substring "Watching docker events"
|
||||
"""
|
||||
docker_client = docker.from_env()
|
||||
containers = docker_client.containers(filters={"ancestor": "jwilder/nginx-proxy:test"})
|
||||
if len(containers) != 1:
|
||||
return
|
||||
container = containers[0]
|
||||
for line in docker_client.logs(container['Id'], stream=True):
|
||||
if "Watching docker events" in line:
|
||||
logging.debug("nginx-proxy ready")
|
||||
break
|
||||
|
||||
|
||||
def find_docker_compose_file(request):
|
||||
"""
|
||||
helper for fixture functions to figure out the name of the docker-compose file to consider.
|
||||
|
||||
- if the test module provides a `docker_compose_file` variable, take that
|
||||
- else, if a yaml file exists with the same name as the test module (but for the `.yml` extension), use that
|
||||
- otherwise use `docker-compose.yml`.
|
||||
"""
|
||||
test_module_dir = os.path.dirname(request.module.__file__)
|
||||
yml_file = os.path.join(test_module_dir, request.module.__name__ + '.yml')
|
||||
yaml_file = os.path.join(test_module_dir, request.module.__name__ + '.yaml')
|
||||
default_file = os.path.join(test_module_dir, 'docker-compose.yml')
|
||||
|
||||
docker_compose_file_module_variable = getattr(request.module, "docker_compose_file", None)
|
||||
if docker_compose_file_module_variable is not None:
|
||||
docker_compose_file = os.path.join( test_module_dir, docker_compose_file_module_variable)
|
||||
if not os.path.isfile(docker_compose_file):
|
||||
raise ValueError("docker compose file %r could not be found. Check your test module `docker_compose_file` variable value." % docker_compose_file)
|
||||
else:
|
||||
if os.path.isfile(yml_file):
|
||||
docker_compose_file = yml_file
|
||||
elif os.path.isfile(yaml_file):
|
||||
docker_compose_file = yaml_file
|
||||
else:
|
||||
docker_compose_file = default_file
|
||||
|
||||
if not os.path.isfile(docker_compose_file):
|
||||
logging.error("Could not find any docker-compose file named either '{0}.yml', '{0}.yaml' or 'docker-compose.yml'".format(request.module.__name__))
|
||||
|
||||
logging.info("using docker compose file %s" % docker_compose_file)
|
||||
return docker_compose_file
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Py.test fixtures
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
@pytest.yield_fixture(scope="module")
|
||||
def docker_compose(request):
|
||||
"""
|
||||
pytest fixture providing containers described in a docker compose file. After the tests, remove the created containers
|
||||
|
||||
A custom docker compose file name can be defined in a variable named `docker_compose_file`.
|
||||
"""
|
||||
docker_compose_file = find_docker_compose_file(request)
|
||||
original_dns_resolver = monkey_patch_urllib_dns_resolver()
|
||||
remove_all_containers()
|
||||
docker_compose_up(docker_compose_file)
|
||||
wait_for_nginxproxy_to_be_ready()
|
||||
time.sleep(3)
|
||||
yield
|
||||
restore_urllib_dns_resolver(original_dns_resolver)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def nginxproxy():
|
||||
"""
|
||||
Provides the `nginxproxy` object that can be used in the same way the requests module is:
|
||||
|
||||
r = nginxproxy.get("http://foo.com")
|
||||
|
||||
The difference is that in case an HTTP requests has status code 404 or 502 (which mostly
|
||||
indicates that nginx has just reloaded), we retry up to 30 times the query
|
||||
"""
|
||||
return requests_retry_on_error_502()
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Py.test hooks
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
# pytest hook to display additionnal stuff in test report
|
||||
def pytest_runtest_logreport(report):
|
||||
if report.failed:
|
||||
docker_client = docker.from_env()
|
||||
test_containers = docker_client.containers(all=True, filters={"ancestor": "jwilder/nginx-proxy:test"})
|
||||
for container in test_containers:
|
||||
report.longrepr.addsection('nginx-proxy logs', docker_client.logs(container['Id']))
|
||||
report.longrepr.addsection('nginx-proxy conf', get_nginx_conf_from_container(container['Id']))
|
||||
|
5
test2/requirements.txt
Normal file
5
test2/requirements.txt
Normal file
@ -0,0 +1,5 @@
|
||||
backoff==1.3.2
|
||||
docker-compose==1.9.0
|
||||
docker-py==1.10.6
|
||||
pytest==3.0.5
|
||||
requests==2.11.1
|
35
test2/requirements/README.md
Normal file
35
test2/requirements/README.md
Normal file
@ -0,0 +1,35 @@
|
||||
This directory contains ressources to build Docker images tests depend on
|
||||
|
||||
# Build images
|
||||
|
||||
./build.sh
|
||||
|
||||
|
||||
# Images
|
||||
|
||||
## web
|
||||
|
||||
This container will run one or many webservers, each of them listening on a single port.
|
||||
|
||||
Ports are specified using the `WEB_PORTS` environment variable:
|
||||
|
||||
docker run -d -e WEB_PORTS=80 web # will create a container running one webserver listening on port 80
|
||||
docker run -d -e WEB_PORTS="80 81" web # will create a container running two webservers, one listening on port 80 and a second one listening on port 81
|
||||
|
||||
The webserver answer for two paths:
|
||||
|
||||
- `/headers`
|
||||
- `/port`
|
||||
|
||||
```
|
||||
$ docker run -d -e WEB_PORTS=80 -p 80:80 web
|
||||
$ curl http://127.0.0.1:80/headers
|
||||
Host: 127.0.0.1
|
||||
User-Agent: curl/7.47.0
|
||||
Accept: */*
|
||||
|
||||
$ curl http://127.0.0.1:80/port
|
||||
answer from port 80
|
||||
|
||||
```
|
||||
|
6
test2/requirements/build.sh
Executable file
6
test2/requirements/build.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
docker build -t web $DIR/web
|
8
test2/requirements/web/Dockerfile
Normal file
8
test2/requirements/web/Dockerfile
Normal file
@ -0,0 +1,8 @@
|
||||
# Docker Image running one (or multiple) webservers listening on all given ports from WEB_PORTS environment variable
|
||||
|
||||
FROM python:3
|
||||
COPY ./webserver.py /
|
||||
COPY ./entrypoint.sh /
|
||||
WORKDIR /opt
|
||||
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
|
||||
|
15
test2/requirements/web/entrypoint.sh
Normal file
15
test2/requirements/web/entrypoint.sh
Normal file
@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
set -u
|
||||
|
||||
trap '[ ${#PIDS[@]} -gt 0 ] && kill -TERM ${PIDS[@]}' TERM
|
||||
declare -a PIDS
|
||||
|
||||
for port in $WEB_PORTS; do
|
||||
echo starting a web server listening on port $port;
|
||||
/webserver.py $port &
|
||||
PIDS+=($!)
|
||||
done
|
||||
|
||||
wait ${PIDS[@]}
|
||||
trap - TERM
|
||||
wait ${PIDS[@]}
|
27
test2/requirements/web/webserver.py
Executable file
27
test2/requirements/web/webserver.py
Executable file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os, sys
|
||||
import http.server
|
||||
import socketserver
|
||||
|
||||
class BatsHandler(http.server.SimpleHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
root = os.getcwd()
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "text/plain")
|
||||
self.end_headers()
|
||||
|
||||
if self.path == "/headers":
|
||||
self.wfile.write(self.headers.as_string().encode())
|
||||
elif self.path == "/port":
|
||||
response = "answer from port %s\n" % PORT
|
||||
self.wfile.write(response.encode())
|
||||
else:
|
||||
self.wfile.write("No route for this path!\n".encode())
|
||||
|
||||
if __name__ == '__main__':
|
||||
PORT = int(sys.argv[1])
|
||||
socketserver.TCPServer.allow_reuse_address = True
|
||||
httpd = socketserver.TCPServer(('0.0.0.0', PORT), BatsHandler)
|
||||
httpd.serve_forever()
|
15
test2/test_DOCKER_HOST_unix_socket.py
Normal file
15
test2/test_DOCKER_HOST_unix_socket.py
Normal file
@ -0,0 +1,15 @@
|
||||
import pytest
|
||||
|
||||
def test_unknown_virtual_host(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://nginx-proxy/port")
|
||||
assert r.status_code == 503
|
||||
|
||||
def test_forwards_to_web1(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web1.nginx-proxy.tld/port")
|
||||
assert r.status_code == 200
|
||||
assert r.text == "answer from port 81\n"
|
||||
|
||||
def test_forwards_to_web2(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web2.nginx-proxy.tld/port")
|
||||
assert r.status_code == 200
|
||||
assert r.text == "answer from port 82\n"
|
24
test2/test_DOCKER_HOST_unix_socket.yml
Normal file
24
test2/test_DOCKER_HOST_unix_socket.yml
Normal file
@ -0,0 +1,24 @@
|
||||
web1:
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: 81
|
||||
VIRTUAL_HOST: web1.nginx-proxy.tld
|
||||
|
||||
web2:
|
||||
image: web
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
WEB_PORTS: 82
|
||||
VIRTUAL_HOST: web2.nginx-proxy.tld
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/f00.sock:ro
|
||||
environment:
|
||||
DOCKER_HOST: unix:///f00.sock
|
||||
|
7
test2/test_default-host.py
Normal file
7
test2/test_default-host.py
Normal file
@ -0,0 +1,7 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_fallback_on_default(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://unknown.nginx-proxy.tld/port")
|
||||
assert r.status_code == 200
|
||||
assert r.text == "answer from port 81\n"
|
17
test2/test_default-host.yml
Normal file
17
test2/test_default-host.yml
Normal file
@ -0,0 +1,17 @@
|
||||
# GIVEN a webserver with VIRTUAL_HOST set to web1.tld
|
||||
web1:
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: 81
|
||||
VIRTUAL_HOST: web1.tld
|
||||
|
||||
|
||||
# WHEN nginx-proxy runs with DEFAULT_HOST set to web1.tld
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
environment:
|
||||
DEFAULT_HOST: web1.tld
|
81
test2/test_headers_http.py
Normal file
81
test2/test_headers_http.py
Normal file
@ -0,0 +1,81 @@
|
||||
import pytest
|
||||
|
||||
def test_arbitrary_headers_are_passed_on(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'Foo': 'Bar'})
|
||||
assert r.status_code == 200
|
||||
assert "Foo: Bar\n" in r.text
|
||||
|
||||
|
||||
##### Testing the handling of X-Forwarded-For #####
|
||||
|
||||
def test_X_Forwarded_For_is_generated(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/headers")
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-For:" in r.text
|
||||
|
||||
def test_X_Forwarded_For_is_passed_on(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-For': '1.2.3.4'})
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-For: 1.2.3.4, " in r.text
|
||||
|
||||
|
||||
##### Testing the handling of X-Forwarded-Proto #####
|
||||
|
||||
def test_X_Forwarded_Proto_is_generated(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/headers")
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-Proto: http" in r.text
|
||||
|
||||
def test_X_Forwarded_Proto_is_passed_on(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Proto': 'f00'})
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-Proto: f00\n" in r.text
|
||||
|
||||
|
||||
##### Testing the handling of X-Forwarded-Port #####
|
||||
|
||||
def test_X_Forwarded_Port_is_generated(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/headers")
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-Port: 80\n" in r.text
|
||||
|
||||
def test_X_Forwarded_Port_is_passed_on(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Port': '1234'})
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-Port: 1234\n" in r.text
|
||||
|
||||
|
||||
##### Testing the handling of X-Forwarded-Ssl #####
|
||||
|
||||
def test_X_Forwarded_Ssl_is_generated(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/headers")
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-Ssl: off\n" in r.text
|
||||
|
||||
def test_X_Forwarded_Ssl_is_overwritten(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Ssl': 'f00'})
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-Ssl: off\n" in r.text
|
||||
|
||||
|
||||
##### Other headers
|
||||
|
||||
def test_X_Real_IP_is_generated(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/headers")
|
||||
assert r.status_code == 200
|
||||
assert "X-Real-IP: " in r.text
|
||||
|
||||
def test_Host_is_passed_on(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/headers")
|
||||
assert r.status_code == 200
|
||||
assert "Host: web.nginx-proxy.tld" in r.text
|
||||
|
||||
def test_httpoxy_safe(docker_compose, nginxproxy):
|
||||
"""
|
||||
See https://httpoxy.org/
|
||||
nginx-proxy should suppress the `Proxy` header
|
||||
"""
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'Proxy': 'tcp://some.hacker.com'})
|
||||
assert r.status_code == 200
|
||||
assert "Proxy:" not in r.text
|
||||
|
13
test2/test_headers_http.yml
Normal file
13
test2/test_headers_http.yml
Normal file
@ -0,0 +1,13 @@
|
||||
web:
|
||||
image: web
|
||||
expose:
|
||||
- "80"
|
||||
environment:
|
||||
WEB_PORTS: 80
|
||||
VIRTUAL_HOST: web.nginx-proxy.tld
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
82
test2/test_headers_https.py
Normal file
82
test2/test_headers_https.py
Normal file
@ -0,0 +1,82 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_arbitrary_headers_are_passed_on(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'Foo': 'Bar'})
|
||||
assert r.status_code == 200
|
||||
assert "Foo: Bar\n" in r.text
|
||||
|
||||
|
||||
##### Testing the handling of X-Forwarded-For #####
|
||||
|
||||
def test_X_Forwarded_For_is_generated(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web.nginx-proxy.tld/headers")
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-For:" in r.text
|
||||
|
||||
def test_X_Forwarded_For_is_passed_on(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-For': '1.2.3.4'})
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-For: 1.2.3.4, " in r.text
|
||||
|
||||
|
||||
##### Testing the handling of X-Forwarded-Proto #####
|
||||
|
||||
def test_X_Forwarded_Proto_is_generated(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web.nginx-proxy.tld/headers")
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-Proto: https" in r.text
|
||||
|
||||
def test_X_Forwarded_Proto_is_passed_on(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Proto': 'f00'})
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-Proto: f00\n" in r.text
|
||||
|
||||
|
||||
##### Testing the handling of X-Forwarded-Port #####
|
||||
|
||||
def test_X_Forwarded_Port_is_generated(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web.nginx-proxy.tld/headers")
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-Port: 443\n" in r.text
|
||||
|
||||
def test_X_Forwarded_Port_is_passed_on(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Port': '1234'})
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-Port: 1234\n" in r.text
|
||||
|
||||
|
||||
##### Testing the handling of X-Forwarded-Ssl #####
|
||||
|
||||
def test_X_Forwarded_Ssl_is_generated(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web.nginx-proxy.tld/headers")
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-Ssl: on\n" in r.text
|
||||
|
||||
def test_X_Forwarded_Ssl_is_overwritten(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Ssl': 'f00'})
|
||||
assert r.status_code == 200
|
||||
assert "X-Forwarded-Ssl: on\n" in r.text
|
||||
|
||||
|
||||
##### Other headers
|
||||
|
||||
def test_X_Real_IP_is_generated(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web.nginx-proxy.tld/headers")
|
||||
assert r.status_code == 200
|
||||
assert "X-Real-IP: " in r.text
|
||||
|
||||
def test_Host_is_passed_on(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web.nginx-proxy.tld/headers")
|
||||
assert r.status_code == 200
|
||||
assert "Host: web.nginx-proxy.tld" in r.text
|
||||
|
||||
def test_httpoxy_safe(docker_compose, nginxproxy):
|
||||
"""
|
||||
See https://httpoxy.org/
|
||||
nginx-proxy should suppress the `Proxy` header
|
||||
"""
|
||||
r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'Proxy': 'tcp://some.hacker.com'})
|
||||
assert r.status_code == 200
|
||||
assert "Proxy:" not in r.text
|
||||
|
15
test2/test_headers_https.yml
Normal file
15
test2/test_headers_https.yml
Normal file
@ -0,0 +1,15 @@
|
||||
web:
|
||||
image: web
|
||||
expose:
|
||||
- "80"
|
||||
environment:
|
||||
WEB_PORTS: 80
|
||||
VIRTUAL_HOST: web.nginx-proxy.tld
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro
|
||||
- ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro
|
16
test2/test_multiple-hosts.py
Normal file
16
test2/test_multiple-hosts.py
Normal file
@ -0,0 +1,16 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_unknown_virtual_host_is_503(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://unknown.nginx-proxy.tld/port")
|
||||
assert r.status_code == 503
|
||||
|
||||
def test_webA_is_forwarded(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://webA.nginx-proxy.tld/port")
|
||||
assert r.status_code == 200
|
||||
assert r.text == "answer from port 81\n"
|
||||
|
||||
def test_webB_is_forwarded(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://webB.nginx-proxy.tld/port")
|
||||
assert r.status_code == 200
|
||||
assert r.text == "answer from port 81\n"
|
13
test2/test_multiple-hosts.yml
Normal file
13
test2/test_multiple-hosts.yml
Normal file
@ -0,0 +1,13 @@
|
||||
web:
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: 81
|
||||
VIRTUAL_HOST: webA.nginx-proxy.tld,webB.nginx-proxy.tld
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
7
test2/test_multiple-ports-VIRTUAL_PORT.py
Normal file
7
test2/test_multiple-ports-VIRTUAL_PORT.py
Normal file
@ -0,0 +1,7 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_answer_is_served_from_chosen_port(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/port")
|
||||
assert r.status_code == 200
|
||||
assert "answer from port 90\n" in r.text
|
14
test2/test_multiple-ports-VIRTUAL_PORT.yml
Normal file
14
test2/test_multiple-ports-VIRTUAL_PORT.yml
Normal file
@ -0,0 +1,14 @@
|
||||
web:
|
||||
image: web
|
||||
expose:
|
||||
- "80"
|
||||
- "90"
|
||||
environment:
|
||||
WEB_PORTS: "80 90"
|
||||
VIRTUAL_HOST: "web.nginx-proxy.tld"
|
||||
VIRTUAL_PORT: 90
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
7
test2/test_multiple-ports-default-80.py
Normal file
7
test2/test_multiple-ports-default-80.py
Normal file
@ -0,0 +1,7 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_answer_is_served_from_port_80_by_default(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/port")
|
||||
assert r.status_code == 200
|
||||
assert "answer from port 80\n" in r.text
|
13
test2/test_multiple-ports-default-80.yml
Normal file
13
test2/test_multiple-ports-default-80.yml
Normal file
@ -0,0 +1,13 @@
|
||||
web:
|
||||
image: web
|
||||
expose:
|
||||
- "80"
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: "80 81"
|
||||
VIRTUAL_HOST: "web.nginx-proxy.tld"
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
7
test2/test_multiple-ports-single-port-not-80.py
Normal file
7
test2/test_multiple-ports-single-port-not-80.py
Normal file
@ -0,0 +1,7 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_answer_is_served_from_exposed_port_even_if_not_80(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web.nginx-proxy.tld/port")
|
||||
assert r.status_code == 200
|
||||
assert "answer from port 81\n" in r.text
|
13
test2/test_multiple-ports-single-port-not-80.yml
Normal file
13
test2/test_multiple-ports-single-port-not-80.yml
Normal file
@ -0,0 +1,13 @@
|
||||
web:
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: "81"
|
||||
VIRTUAL_HOST: "web.nginx-proxy.tld"
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
15
test2/test_nominal.py
Normal file
15
test2/test_nominal.py
Normal file
@ -0,0 +1,15 @@
|
||||
import pytest
|
||||
|
||||
def test_unknown_virtual_host(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://nginx-proxy/port")
|
||||
assert r.status_code == 503
|
||||
|
||||
def test_forwards_to_web1(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web1.nginx-proxy.tld/port")
|
||||
assert r.status_code == 200
|
||||
assert r.text == "answer from port 81\n"
|
||||
|
||||
def test_forwards_to_web2(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web2.nginx-proxy.tld/port")
|
||||
assert r.status_code == 200
|
||||
assert r.text == "answer from port 82\n"
|
21
test2/test_nominal.yml
Normal file
21
test2/test_nominal.yml
Normal file
@ -0,0 +1,21 @@
|
||||
web1:
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: 81
|
||||
VIRTUAL_HOST: web1.nginx-proxy.tld
|
||||
|
||||
web2:
|
||||
image: web
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
WEB_PORTS: 82
|
||||
VIRTUAL_HOST: web2.nginx-proxy.tld
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
19
test2/test_ssl_nohttp.py
Normal file
19
test2/test_ssl_nohttp.py
Normal file
@ -0,0 +1,19 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_web2_http_is_not_forwarded(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web2.nginx-proxy.tld/", allow_redirects=False)
|
||||
assert r.status_code == 503
|
||||
|
||||
|
||||
def test_web2_https_is_forwarded(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web2.nginx-proxy.tld/port", allow_redirects=False)
|
||||
assert r.status_code == 200
|
||||
assert "answer from port 82\n" in r.text
|
||||
|
||||
|
||||
def test_web2_HSTS_policy_is_active(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web2.nginx-proxy.tld/port", allow_redirects=False)
|
||||
assert "answer from port 82\n" in r.text
|
||||
assert "Strict-Transport-Security" in r.headers
|
||||
|
16
test2/test_ssl_nohttp.yml
Normal file
16
test2/test_ssl_nohttp.yml
Normal file
@ -0,0 +1,16 @@
|
||||
web2:
|
||||
image: web
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
WEB_PORTS: "82"
|
||||
VIRTUAL_HOST: "web2.nginx-proxy.tld"
|
||||
HTTPS_METHOD: nohttp
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./certs/web2.nginx-proxy.tld.crt:/etc/nginx/certs/web2.nginx-proxy.tld.crt:ro
|
||||
- ./certs/web2.nginx-proxy.tld.key:/etc/nginx/certs/web2.nginx-proxy.tld.key:ro
|
19
test2/test_ssl_noredirect.py
Normal file
19
test2/test_ssl_noredirect.py
Normal file
@ -0,0 +1,19 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_web3_http_is_forwarded(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("http://web3.nginx-proxy.tld/port", allow_redirects=False)
|
||||
assert r.status_code == 200
|
||||
assert "answer from port 83\n" in r.text
|
||||
|
||||
|
||||
def test_web3_https_is_forwarded(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web3.nginx-proxy.tld/port", allow_redirects=False)
|
||||
assert r.status_code == 200
|
||||
assert "answer from port 83\n" in r.text
|
||||
|
||||
|
||||
def test_web2_HSTS_policy_is_inactive(docker_compose, nginxproxy):
|
||||
r = nginxproxy.get("https://web3.nginx-proxy.tld/port", allow_redirects=False)
|
||||
assert "answer from port 83\n" in r.text
|
||||
assert "Strict-Transport-Security" not in r.headers
|
16
test2/test_ssl_noredirect.yml
Normal file
16
test2/test_ssl_noredirect.yml
Normal file
@ -0,0 +1,16 @@
|
||||
web3:
|
||||
image: web
|
||||
expose:
|
||||
- "83"
|
||||
environment:
|
||||
WEB_PORTS: "83"
|
||||
VIRTUAL_HOST: "web3.nginx-proxy.tld"
|
||||
HTTPS_METHOD: noredirect
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./certs/web3.nginx-proxy.tld.crt:/etc/nginx/certs/web3.nginx-proxy.tld.crt:ro
|
||||
- ./certs/web3.nginx-proxy.tld.key:/etc/nginx/certs/web3.nginx-proxy.tld.key:ro
|
24
test2/test_ssl_wildcard.py
Normal file
24
test2/test_ssl_wildcard.py
Normal file
@ -0,0 +1,24 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize("subdomain", ["foo", "bar"])
|
||||
def test_web1_http_redirects_to_https(docker_compose, nginxproxy, subdomain):
|
||||
r = nginxproxy.get("http://%s.nginx-proxy.tld/" % subdomain, allow_redirects=False)
|
||||
assert r.status_code == 301
|
||||
assert "Location" in r.headers
|
||||
assert "https://%s.nginx-proxy.tld/" % subdomain == r.headers['Location']
|
||||
|
||||
|
||||
@pytest.mark.parametrize("subdomain", ["foo", "bar"])
|
||||
def test_web1_https_is_forwarded(docker_compose, nginxproxy, subdomain):
|
||||
r = nginxproxy.get("https://%s.nginx-proxy.tld/port" % subdomain, allow_redirects=False)
|
||||
assert r.status_code == 200
|
||||
assert "answer from port 81\n" in r.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("subdomain", ["foo", "bar"])
|
||||
def test_web1_HSTS_policy_is_active(docker_compose, nginxproxy, subdomain):
|
||||
r = nginxproxy.get("https://%s.nginx-proxy.tld/port" % subdomain, allow_redirects=False)
|
||||
assert "answer from port 81\n" in r.text
|
||||
assert "Strict-Transport-Security" in r.headers
|
||||
|
16
test2/test_ssl_wildcard.yml
Normal file
16
test2/test_ssl_wildcard.yml
Normal file
@ -0,0 +1,16 @@
|
||||
web1:
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: "81"
|
||||
VIRTUAL_HOST: "*.nginx-proxy.tld"
|
||||
CERT_NAME: "*.nginx-proxy.tld"
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
- ./certs/*.nginx-proxy.tld.crt:/etc/nginx/certs/*.nginx-proxy.tld.crt:ro
|
||||
- ./certs/*.nginx-proxy.tld.key:/etc/nginx/certs/*.nginx-proxy.tld.key:ro
|
32
test2/test_wildcard_host.py
Normal file
32
test2/test_wildcard_host.py
Normal file
@ -0,0 +1,32 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize("host,expected_port", [
|
||||
("f00.nginx-proxy.test", 81),
|
||||
("bar.nginx-proxy.test", 81),
|
||||
("test.nginx-proxy.f00", 82),
|
||||
("test.nginx-proxy.bar", 82),
|
||||
("web3.123.nginx-proxy.regexp", 83),
|
||||
("web3.ABC.nginx-proxy.regexp", 83),
|
||||
("web3.123.ABC.nginx-proxy.regexp", 83),
|
||||
("web3.123-ABC.nginx-proxy.regexp", 83),
|
||||
("web3.whatever.nginx-proxy.regexp-to-infinity-and-beyond", 83),
|
||||
("web4.123.nginx-proxy.regexp", 84),
|
||||
("web4.ABC.nginx-proxy.regexp", 84),
|
||||
("web4.123.ABC.nginx-proxy.regexp", 84),
|
||||
("web4.123-ABC.nginx-proxy.regexp", 84),
|
||||
("web4.whatever.nginx-proxy.regexp", 84),
|
||||
])
|
||||
def test_wildcard_prefix(docker_compose, nginxproxy, host, expected_port):
|
||||
r = nginxproxy.get("http://%s/port" % host)
|
||||
assert r.status_code == 200
|
||||
assert r.text == "answer from port %s\n" % expected_port
|
||||
|
||||
|
||||
@pytest.mark.parametrize("host", [
|
||||
"unexpected.nginx-proxy.tld",
|
||||
"web4.whatever.nginx-proxy.regexp-to-infinity-and-beyond"
|
||||
])
|
||||
def test_non_matching_host_is_503(docker_compose, nginxproxy, host):
|
||||
r = nginxproxy.get("http://%s/port" % host)
|
||||
assert r.status_code == 503, r.text
|
37
test2/test_wildcard_host.yml
Normal file
37
test2/test_wildcard_host.yml
Normal file
@ -0,0 +1,37 @@
|
||||
web1:
|
||||
image: web
|
||||
expose:
|
||||
- "81"
|
||||
environment:
|
||||
WEB_PORTS: "81"
|
||||
VIRTUAL_HOST: "*.nginx-proxy.test"
|
||||
|
||||
web2:
|
||||
image: web
|
||||
expose:
|
||||
- "82"
|
||||
environment:
|
||||
WEB_PORTS: "82"
|
||||
VIRTUAL_HOST: "test.nginx-proxy.*"
|
||||
|
||||
web3:
|
||||
image: web
|
||||
expose:
|
||||
- "83"
|
||||
environment:
|
||||
WEB_PORTS: "83"
|
||||
VIRTUAL_HOST: ~^web3\..*\.nginx-proxy\.regexp
|
||||
|
||||
web4:
|
||||
image: web
|
||||
expose:
|
||||
- "84"
|
||||
environment:
|
||||
WEB_PORTS: "84"
|
||||
VIRTUAL_HOST: ~^web4\..*\.nginx-proxy\.regexp$$ # we need to double the `$` because of docker-compose variable interpolation
|
||||
|
||||
|
||||
sut:
|
||||
image: jwilder/nginx-proxy:test
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
Loading…
Reference in New Issue
Block a user