Skip to content

Commit c60b998

Browse files
ppxlcesmarvin
authored andcommitted
Merge branch 'release/v1.29.4-2'
2 parents 4ccc2a4 + e74382f commit c60b998

11 files changed

Lines changed: 234 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [v1.29.4-2] - 2026-01-19
11+
### Added
12+
- [#134] support mutual TLS with client certificates
13+
1014
## [v1.29.4-1] - 2025-12-16
1115
### Changed
1216
- [#132] Upgrade nginx to v1.29.4

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FROM node:lts-alpine as templating
22

33
ENV WORKDIR=/template \
44
# Used in template to invalidate caches - do not remove. The release script will auto update this line
5-
VERSION="1.29.4-1"
5+
VERSION="1.29.4-2"
66

77
RUN mkdir -p ${WORKDIR}
88
WORKDIR ${WORKDIR}
@@ -68,11 +68,11 @@ RUN wget --progress=bar:force:noscroll -O /tmp/warp.zip https://github.com/cloud
6868
FROM registry.cloudogu.com/official/base:3.22.0-5
6969
LABEL maintainer="hello@cloudogu.com" \
7070
NAME="official/nginx" \
71-
VERSION="1.29.4-1"
71+
VERSION="1.29.4-2"
7272

7373
ENV CES_MAINTENANCE_MODE=false \
7474
# Used in template to invalidate caches - do not remove. The release script will auto update this line
75-
VERSION="1.29.4-1"
75+
VERSION="1.29.4-2"
7676

7777
RUN set -x -o errexit \
7878
&& set -o nounset \

docs/dev/client-certificates_de.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Mutual TLS mit Client Zertifikaten
2+
3+
Das Nginx-Dogu unterstützt die Authentifizierung von Clients mittels Zertifikaten (Mutual TLS). Wenn diese Funktion aktiviert
4+
ist, fordert Nginx beim TLS-Handshake ein Zertifikat vom Client an und validiert dieses gegen eine hinterlegte
5+
Certificate Authority (CA).
6+
7+
## Konfiguration
8+
9+
Die Konfiguration erfolgt über die Dogu-Konfiguration `mutual_tls/enabled`.
10+
11+
> [!IMPORTANT]
12+
> Damit die Authentifizierung mit Client-Zertifikaten funktioniert, muss Split-DNS konfiguriert sein.
13+
> Siehe [Split-DNS](#split-dns)
14+
15+
### 1. CA Zertifikat hinterlegen
16+
17+
Damit Nginx die Client-Zertifikate validieren kann, muss das öffentliche Zertifikat der CA global im CES bekannt sein.
18+
Das CA-Zertifikat muss im PEM-Format in der globalen Konfiguration gespeichert werden:
19+
20+
```bash
21+
cat client-ca.crt | etcdctl set /config/_global/certificate/client-ca.crt
22+
```
23+
24+
> Hinweis: Ein CA-Zertifikat kann z.B. so erzeugt werden:
25+
> 1. Key erzeugen: `openssl genrsa -out client-ca.key 4096`
26+
> 2. Zerifikat erstellen: ` openssl req -x509 -new -nodes -key client-ca.key -sha256 -days 3650 -out client-ca.crt -subj "/C=DE/O=MyOrg/CN=MyOrg Client Root CA`
27+
28+
### 2. Authentifizierung aktivieren
29+
30+
Die Client-Authentifizierung ist standardmäßig deaktiviert. Sie über die Dogu-Config des nginx aktiviert werden:
31+
32+
```bash
33+
etcdctl set /config/nginx/mutual_tls/enabled true
34+
```
35+
36+
Nach der Änderung muss das Nginx-Dogu neu gestartet werden, damit das CA-Zertifikat aus der Registry geladen und die
37+
Konfiguration neu generiert wird.
38+
39+
## Funktionsweise
40+
41+
Sobald `mutual_tls/enabled` auf `true` gesetzt ist:
42+
43+
1. Extrahiert das `startup.sh` Skript das CA-Zertifikat aus der globalen Registry nach `/etc/ssl/client-ca.crt`.
44+
2. Aktiviert die `ssl.conf` die Nginx-Direktiven `ssl_client_certificate` und `ssl_verify_client on`.
45+
46+
### Ausnahme für interne Dogu-Requests
47+
Damit Dogus auch ohne Client-Zertifikat Requests an andere Dogus stellen können (z.B. zur Validierung der CAS-Session),
48+
wird in der `nginx.conf` eine Ausnahme für alle Requests erstellt, die aus dem internen Docker-Netzwerk (`172.18.0.1/32`) stammen.
49+
50+
#### Split-DNS
51+
Damit das funktioniert, muss Split-DNS entsprechend konfiguriert sein.
52+
Bei der Installation des CES kann dies in der setup.json unter `useInternalIp` bzw. `internalIp` konfiguriert werden. Siehe: https://docs.cloudogu.com/de/docs/system-components/ces-setup/operations/setup-json/#useinternalip
53+
54+
Dabei wird dann ein entsprechender Eintrag in der `/etc/hosts` der CES-Instanz erzeugt.
55+
Um eine CES-Instanz nach der Installation für Split-DNS zu konfigurieren, muss für die interne IP ein entsprechender Eintrag in der `/etc/hosts` hinterlegt werden.
56+
Zum Beispiel:
57+
```
58+
<interne IP> <DNS-Name>
59+
172.18.0.1 ces.example.com
60+
```
61+
62+
Danach müssen alle Dogus einmal neugestartet werden.
63+
64+
## Ein Client-Zertifikat erzeugen
65+
Folgende Schritte sind nötig um ein Client-Zertifikat zu erzeugen:
66+
67+
1. User-Key generieren: `openssl genrsa -out client1.key 4096`
68+
2. Certificate Signing Request (CSR) generieren: `openssl req -new -key client1.key -out client1.csr -subj "/C=DE/O=MyOrg/OU=Clients/CN=client1"`
69+
3. Client extension file generieren:
70+
```bash
71+
cat > client.ext <<'EOF'
72+
basicConstraints = CA:FALSE
73+
keyUsage = digitalSignature, keyEncipherment
74+
extendedKeyUsage = clientAuth
75+
subjectKeyIdentifier = hash
76+
EOF
77+
```
78+
4. CSR signieren: `openssl x509 -req -in client1.csr -CA client-ca.crt -CAkey client-ca.key -CAcreateserial -out client1.crt -days 365 -sha256 -extfile client.ext`
79+
5. Client-Zertifikat exportieren: `openssl pkcs12 -export -inkey client1.key -in client1.crt -certfile client-ca.crt -name "client1" -out client1.p12`
80+
> Hinweis: Beim Exportieren muss ein Passwort angegeben werden.
81+
82+
Das exportierte Zertifikat kann nun im Browser importiert werden.

docs/dev/client-certificates_en.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Mutual TLS with client certificates
2+
3+
Nginx Dogu supports client authentication using certificates (Mutual TLS). When this feature is enabled,
4+
Nginx requests a certificate from the client during the TLS handshake and validates it against a stored
5+
Certificate Authority (CA).
6+
7+
## Configuration
8+
9+
The configuration is done via the Dogu configuration `mutual_tls/enabled`.
10+
11+
> [!IMPORTANT]
12+
> Split DNS must be configured for authentication with client certificates to work.
13+
> See [Split DNS](#split-dns)
14+
15+
### 1. Store CA certificate
16+
17+
In order for Nginx to validate the client certificates, the public certificate of the CA must be known globally in the CES.
18+
The CA certificate must be stored in PEM format in the global configuration:
19+
20+
```bash
21+
cat client-ca.crt | etcdctl set /config/_global/certificate/client-ca.crt
22+
```
23+
24+
> Note: A CA certificate can be generated as follows, for example:
25+
> 1. Generate key: `openssl genrsa -out client-ca.key 4096`
26+
> 2. Create certificate: ` openssl req -x509 -new -nodes -key client-ca.key -sha256 -days 3650 -out client-ca.crt -subj "/C=DE/O=MyOrg/CN=MyOrg Client Root CA`
27+
28+
29+
### 2. Enable authentication
30+
31+
Client authentication is disabled by default. It can be enabled via the Dogu config of nginx:
32+
33+
```bash
34+
etcdctl set /config/nginx/mutual_tls/enabled true
35+
```
36+
37+
After making this change, the Nginx Dogu must be restarted so that the CA certificate is loaded from the registry and the
38+
configuration is regenerated.
39+
40+
## How it works
41+
42+
Once `mutual_tls/enabled` is set to `true`:
43+
44+
1. The `startup.sh` script extracts the CA certificate from the global registry to `/etc/ssl/client-ca.crt`.
45+
2. The `ssl.conf` activates the Nginx directives `ssl_client_certificate` and `ssl_verify_client on`.
46+
47+
### Exception for internal Dogu requests
48+
To enable Dogus to send requests to other Dogus without a client certificate (e.g., to validate the CAS session),
49+
an exception is created in `nginx.conf` for all requests originating from the internal Docker network (`172.18.0.1/32`).
50+
51+
#### Split DNS
52+
For this to work, split DNS must be configured accordingly.
53+
When installing the CES, this can be configured in setup.json under `useInternalIp` or `internalIp`. See: https://docs.cloudogu.com/de/docs/system-components/ces-setup/operations/setup-json/#useinternalip
54+
55+
This creates a corresponding entry in the `/etc/hosts` of the CES instance.
56+
To configure a CES instance for split DNS after installation, a corresponding entry must be stored in `/etc/hosts` for the internal IP.
57+
For example:
58+
```
59+
<internal IP> <DNS name>
60+
172.18.0.1 ces.example.com
61+
```
62+
63+
After that, all Dogus must be restarted once.
64+
65+
## Generate a client certificate
66+
The following steps are necessary to generate a client certificate:
67+
68+
1. Generate user key: `openssl genrsa -out client1.key 4096`
69+
2. Generate a certificate signing request (CSR): `openssl req -new -key client1.key -out client1.csr -subj “/C=DE/O=MyOrg/OU=Clients/CN=client1”`
70+
3. Generate client extension file:
71+
```bash
72+
cat > client.ext <<‘EOF’
73+
basicConstraints = CA:FALSE
74+
keyUsage = digitalSignature, keyEncipherment
75+
extendedKeyUsage = clientAuth
76+
subjectKeyIdentifier = hash
77+
EOF
78+
```
79+
4. Sign CSR: `openssl x509 -req -in client1.csr -CA client-ca.crt -CAkey client-ca.key -CAcreateserial -out client1.crt -days 365 -sha256 -extfile client.ext`
80+
5. Export client certificate: `openssl pkcs12 -export -inkey client1.key -in client1.crt -certfile client-ca.crt -name “client1” -out client1.p12`
81+
> Note: A password must be entered when exporting.
82+
83+
The exported certificate can now be imported into the browser.

docs/gui/release_notes_de.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Technische Details zu einem Release finden Sie im zugehörigen [Changelog](https
66

77
## [Unreleased]
88

9+
## [v1.29.4-2] - 2026-01-19
10+
- Fügt Mutual-TLS-Zertifikatsunterstützung hinzu
11+
912
## [v1.29.4-1] - 2025-12-16
1013
- Wir haben nur technische Änderungen vorgenommen. Näheres finden Sie in den Changelogs.
1114

docs/gui/release_notes_en.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Technical details on a release can be found in the corresponding [Changelog](htt
66

77
## [Unreleased]
88

9+
## [v1.29.4-2] - 2026-01-19
10+
- Adds support for Mutual TLS certificates
11+
912
## [v1.29.4-1] - 2025-12-16
1013
- We have only made technical changes. You can find more details in the changelogs.
1114

dogu.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"Name": "official/nginx",
3-
"Version": "1.29.4-1",
3+
"Version": "1.29.4-2",
44
"DisplayName": "Nginx",
55
"Description": "Nginx WebServer.",
66
"Logo": "https://cloudogu.com/images/dogus/nginx.png",
@@ -120,6 +120,19 @@
120120
"Name": "buffer/proxy_busy_buffers_size",
121121
"Description": "When buffering of responses from the proxied server is enabled, limits the total size of buffers that can be busy sending a response to the client while the response is not yet fully read. In the meantime, the rest of the buffers can be used for reading the response and, if needed, buffering part of the response to a temporary file. By default, size is limited by the size of two buffers set by the proxy_buffer_size and proxy_buffers directives. The default value is 8k/16k (depending on the platform). Format: '{buffer size}k' ",
122122
"Optional": true
123+
},
124+
{
125+
"Name": "mutual_tls/enabled",
126+
"Description": "Enables mutual TLS. If enabled, the certificate of the client must be provided in the request to the server. Format: 'true' or 'false'. Ensure the CA certificate used to sign client certificates is stored in the global configuration at 'certificate/client-ca.crt'",
127+
"Default": "false",
128+
"Validation": {
129+
"Type": "ONE_OF",
130+
"Values": [
131+
"true",
132+
"false"
133+
]
134+
},
135+
"Optional": true
123136
}
124137
],
125138
"Volumes": [

resources/etc/ces-confd/templates/app.conf.tpl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ server {
2828
proxy_set_header X-Real-IP $remote_addr;
2929
proxy_set_header X-Scheme $scheme;
3030
31+
proxy_set_header X-Client-S-DN $ssl_client_s_dn;
32+
proxy_set_header X-Client-Verify $ssl_client_verify;
33+
3134
# proxy keep alive settings
3235
# https://github.com/cloudogu/ecosystem/issues/298
3336
# https://stackoverflow.com/questions/28347184/upstream-timed-out-110-connection-timed-out-for-static-content

resources/etc/nginx/include.d/ssl.conf.tpl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,13 @@ ssl_protocols TLSv1.2 TLSv1.3;
1212
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256";
1313
ssl_conf_command Ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384;
1414
ssl_prefer_server_ciphers on;
15+
16+
{{- if eq (.Config.GetOrDefault "mutual_tls/enabled" "false") "true" -}}
17+
ssl_client_certificate /etc/ssl/client-ca.crt;
18+
ssl_verify_client optional;
19+
20+
# check if access is allowed
21+
if ($access_allowed = 0) {
22+
return 403;
23+
}
24+
{{- end -}}

resources/etc/nginx/nginx.conf.tpl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,28 @@ http {
6666
# include app configuration
6767
include /etc/nginx/conf.d/*.conf;
6868
include {{ .Env.Get "APPCONF_VOL_DIR" }}/*.conf;
69+
70+
{{- if eq (.Config.GetOrDefault "mutual_tls/enabled" "false") "true" -}}
71+
# mark internal requests coming from the docker network
72+
geo $is_internal {
73+
default 0;
74+
172.18.0.1/32 1;
75+
127.0.0.1/32 1;
76+
}
77+
78+
# allow only all internal requests or external requests if mTLS was successful
79+
map "$is_internal:$ssl_client_verify" $access_allowed {
80+
default 0;
81+
82+
# internal always allowed
83+
"1:NONE" 1;
84+
"1:FAILED" 1;
85+
"1:SUCCESS" 1;
86+
87+
# external only allowed, if mTLS was successful
88+
"0:SUCCESS" 1;
89+
}
90+
91+
{{- end -}}
92+
6993
}

0 commit comments

Comments
 (0)