Skip to content

Commit 88e8ecc

Browse files
evgeniadamruzicka
andcommitted
Fixes #37761 - use ProxyPass and upgrade=websocket where possible
RewriteRules need special handling of some characters (esp "?"), which differs based on Apache version. Instead of going down that way, we can switch to using ProxyPass as proxying is the only thing we really need here, at least for HTTP. For WebSockets, we need to allow protocol upgrades, which modern (2.4.47+) Apache can do itself via "ProxyPass … upgrade=websocket". For older Apache (esp on EL8 and Ubuntu 20.04), we keep the RewriteRules in place. To be removed when we drop support for those targets. Co-Authored-By: Adam Ruzicka <aruzicka@redhat.com>
1 parent d5d4921 commit 88e8ecc

File tree

6 files changed

+96
-42
lines changed

6 files changed

+96
-42
lines changed

manifests/config/apache.pp

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,9 @@
167167
if $suburi {
168168
$custom_fragment = undef
169169
} else {
170-
# mod_env and mod_expires are required by configuration in _assets.conf.erb
170+
# mod_env, mod_expires and mod_rewrite are required by configuration in _assets.conf.erb
171171
include apache::mod::env
172+
include apache::mod::rewrite
172173
# apache::mod::expires pulls in a config file we don't want, like apache::default_mods
173174
# It uses ensure_resource to be compatible with both $apache::default_mods set to true and false
174175
include apache
@@ -182,8 +183,23 @@
182183
order => '03',
183184
}
184185

185-
include apache::mod::proxy_wstunnel
186-
$websockets_backend = regsubst($_proxy_backend, 'http://', 'ws://')
186+
# mod_proxy supports "ProxyPass ... upgrade=websocket" since 2.4.47
187+
# EL8: 2.4.37 / EL9: 2.4.62 / Debian11: 2.4.62 / Ubuntu20.04: 2.4.41 / Ubuntu22.04: 2.4.52
188+
$proxy_upgrade_websocket = !($facts['os']['family'] == 'RedHat' and $facts['os']['release']['major'] == '8') and !($facts['os']['name'] == 'Ubuntu' and $facts['os']['release']['major'] == '20.04')
189+
if $proxy_upgrade_websocket {
190+
$vhost_rewrites = []
191+
$_proxy_params = $proxy_params + { 'upgrade' => 'websocket' }
192+
} else {
193+
include apache::mod::proxy_wstunnel
194+
$websockets_backend = regsubst($_proxy_backend, 'http://', 'ws://')
195+
$websockets_rewrite = {
196+
'comment' => 'Upgrade Websocket connections',
197+
'rewrite_cond' => '%{HTTP:Upgrade} =websocket [NC]',
198+
'rewrite_rule' => "/(.*) ${websockets_backend}\$1 [P,L]",
199+
}
200+
$vhost_rewrites = [$websockets_rewrite]
201+
$_proxy_params = $proxy_params
202+
}
187203

188204
$vhost_http_request_headers = [
189205
'set X_FORWARDED_PROTO "http"',
@@ -209,15 +225,9 @@
209225
'no_proxy_uris' => $_proxy_no_proxy_uris,
210226
'path' => pick($suburi, '/'),
211227
'url' => $_proxy_backend,
212-
'params' => $proxy_params,
228+
'params' => $_proxy_params,
213229
},
214-
'rewrites' => [
215-
{
216-
'comment' => 'Upgrade Websocket connections',
217-
'rewrite_cond' => '%{HTTP:Upgrade} =websocket [NC]',
218-
'rewrite_rule' => "/(.*) ${websockets_backend}\$1 [P,L]",
219-
},
220-
],
230+
'rewrites' => $vhost_rewrites,
221231
}
222232

223233
$vhost_https_request_headers = [

manifests/plugin/remote_execution/cockpit.pp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,16 @@
7272
require => Class['foreman::database'],
7373
}
7474
} else {
75-
include apache::mod::rewrite
76-
include apache::mod::proxy_wstunnel
7775
include apache::mod::proxy_http
76+
if $foreman::config::apache::proxy_upgrade_websocket {
77+
$_apache_template = 'cockpit-apache-ssl.conf.erb'
78+
} else {
79+
include apache::mod::rewrite
80+
include apache::mod::proxy_wstunnel
81+
$_apache_template = 'cockpit-apache-ssl-rewrite.conf.erb'
82+
}
7883
foreman::config::apache::fragment { 'cockpit':
79-
ssl_content => template('foreman/cockpit-apache-ssl.conf.erb'),
84+
ssl_content => template("foreman/${_apache_template}"),
8085
}
8186

8287
foreman_config_entry { 'remote_execution_cockpit_url':

spec/classes/foreman_config_apache_spec.rb

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,28 @@
1515
end
1616
end
1717

18+
let(:proxy_pass_params) do
19+
if (facts[:os]['family'] == 'RedHat' && facts[:os]['release']['major'] == '8') ||
20+
(facts[:os]['name'] == 'Ubuntu' && facts[:os]['release']['major'] == '20.04')
21+
{ 'retry' => '0' }
22+
else
23+
{ 'retry' => '0', 'upgrade' => 'websocket' }
24+
end
25+
end
26+
27+
1828
it { should compile.with_all_deps }
1929

2030
it 'should include apache with modules' do
2131
should contain_class('apache::mod::env')
2232
should contain_apache__mod('expires')
2333
should contain_class('apache::mod::proxy')
2434
should contain_class('apache::mod::proxy_http')
25-
should contain_class('apache::mod::proxy_wstunnel')
2635
should contain_class('apache::mod::rewrite')
36+
if (facts[:os]['family'] == 'RedHat' && facts[:os]['release']['major'] == '8') ||
37+
(facts[:os]['name'] == 'Ubuntu' && facts[:os]['release']['major'] == '20.04')
38+
should contain_class('apache::mod::proxy_wstunnel')
39+
end
2740
end
2841

2942
it 'does not manage the docroot' do
@@ -79,15 +92,19 @@
7992
"no_proxy_uris" => ['/pulp', '/pub', '/icons', '/images', '/server-status', '/webpack', '/assets'],
8093
"path" => '/',
8194
"url" => 'unix:///run/foreman.sock|http://foreman/',
82-
"params" => { "retry" => '0' },
95+
"params" => proxy_pass_params,
8396
)
84-
.with_rewrites([
85-
{
86-
'comment' => 'Upgrade Websocket connections',
87-
'rewrite_cond' => '%{HTTP:Upgrade} =websocket [NC]',
88-
'rewrite_rule' => '/(.*) unix:///run/foreman.sock|ws://foreman/$1 [P,L]',
89-
},
90-
])
97+
if (facts[:os]['family'] == 'RedHat' && facts[:os]['release']['major'] == '8') ||
98+
(facts[:os]['name'] == 'Ubuntu' && facts[:os]['release']['major'] == '20.04')
99+
should contain_apache__vhost('foreman')
100+
.with_rewrites([
101+
{
102+
'comment' => 'Upgrade Websocket connections',
103+
'rewrite_cond' => '%{HTTP:Upgrade} =websocket [NC]',
104+
'rewrite_rule' => '/(.*) unix:///run/foreman.sock|ws://foreman/$1 [P,L]',
105+
},
106+
])
107+
end
91108
end
92109

93110
it 'does not configure the HTTPS vhost' do
@@ -109,8 +126,11 @@ class { 'apache':
109126
should contain_apache__mod('expires')
110127
should contain_class('apache::mod::proxy')
111128
should contain_class('apache::mod::proxy_http')
112-
should contain_class('apache::mod::proxy_wstunnel')
113129
should contain_class('apache::mod::rewrite')
130+
if (facts[:os]['family'] == 'RedHat' && facts[:os]['release']['major'] == '8') ||
131+
(facts[:os]['name'] == 'Ubuntu' && facts[:os]['release']['major'] == '20.04')
132+
should contain_class('apache::mod::proxy_wstunnel')
133+
end
114134
end
115135
end
116136

@@ -152,7 +172,7 @@ class { 'apache':
152172
"no_proxy_uris" => ['/pulp', '/pub', '/icons', '/images', '/server-status'],
153173
"path" => '/',
154174
"url" => 'unix:///run/foreman.sock|http://foreman/',
155-
"params" => { "retry" => '0' },
175+
"params" => proxy_pass_params,
156176
)
157177
}
158178
end
@@ -229,15 +249,19 @@ class { 'apache':
229249
"no_proxy_uris" => ['/pulp', '/pub', '/icons', '/images', '/server-status', '/webpack', '/assets'],
230250
"path" => '/',
231251
"url" => 'unix:///run/foreman.sock|http://foreman/',
232-
"params" => { "retry" => '0' },
252+
"params" => proxy_pass_params,
233253
)
234-
.with_rewrites([
235-
{
236-
'comment' => 'Upgrade Websocket connections',
237-
'rewrite_cond' => '%{HTTP:Upgrade} =websocket [NC]',
238-
'rewrite_rule' => '/(.*) unix:///run/foreman.sock|ws://foreman/$1 [P,L]',
239-
},
240-
])
254+
if (facts[:os]['family'] == 'RedHat' && facts[:os]['release']['major'] == '8') ||
255+
(facts[:os]['name'] == 'Ubuntu' && facts[:os]['release']['major'] == '20.04')
256+
should contain_apache__vhost('foreman-ssl')
257+
.with_rewrites([
258+
{
259+
'comment' => 'Upgrade Websocket connections',
260+
'rewrite_cond' => '%{HTTP:Upgrade} =websocket [NC]',
261+
'rewrite_rule' => '/(.*) unix:///run/foreman.sock|ws://foreman/$1 [P,L]',
262+
},
263+
])
264+
end
241265
end
242266

243267
describe 'with vhost and ssl, no CRL explicitly' do

spec/classes/plugin/remote_execution_cockpit_spec.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,22 @@ class {'foreman':
6565
end
6666

6767
it 'configures apache' do
68-
is_expected.to contain_class('apache::mod::proxy_wstunnel')
6968
is_expected.to contain_class('apache::mod::proxy_http')
7069
is_expected.to contain_foreman__config__apache__fragment('cockpit')
7170
.without_content
7271
.with_ssl_content(%r{^<Location /webcon>$})
73-
.with_ssl_content(%r{^ RewriteRule /webcon/\(\.\*\) ws://127\.0\.0\.1:19090/webcon/\$1 \[P\]$})
74-
.with_ssl_content(%r{^ RewriteRule /webcon/\(\.\*\) http://127\.0\.0\.1:19090/webcon/\$1 \[P\]$})
72+
if (facts[:os]['family'] == 'RedHat' && facts[:os]['release']['major'] == '8') ||
73+
(facts[:os]['name'] == 'Ubuntu' && facts[:os]['release']['major'] == '20.04')
74+
is_expected.to contain_class('apache::mod::rewrite')
75+
is_expected.to contain_class('apache::mod::proxy_wstunnel')
76+
is_expected.to contain_foreman__config__apache__fragment('cockpit')
77+
.with_ssl_content(%r{^ RewriteRule /webcon/\(\.\*\) ws://127\.0\.0\.1:19090/webcon/\$1 \[P\]$})
78+
.with_ssl_content(%r{^ ProxyPass http://127\.0\.0\.1:19090/webcon$})
79+
else
80+
is_expected.to contain_foreman__config__apache__fragment('cockpit')
81+
.without_ssl_content(%r{RewriteRule})
82+
.with_ssl_content(%r{^ ProxyPass http://127\.0\.0\.1:19090/webcon upgrade=websocket$})
83+
end
7584
end
7685
end
7786

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
### File managed with puppet ###
2+
3+
<Location <%= @cockpit_path %>>
4+
ProxyPreserveHost On
5+
6+
RewriteEngine On
7+
RewriteCond %{HTTP:Upgrade} =websocket [NC]
8+
RewriteRule <%= @cockpit_path %>/(.*) ws://<%= @cockpit_host %>:<%= @cockpit_port %><%= @cockpit_path %>/$1 [P]
9+
10+
ProxyPass http://<%= @cockpit_host %>:<%= @cockpit_port %><%= @cockpit_path %>
11+
</Location>

templates/cockpit-apache-ssl.conf.erb

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,5 @@
22

33
<Location <%= @cockpit_path %>>
44
ProxyPreserveHost On
5-
6-
RewriteEngine On
7-
RewriteCond %{HTTP:Upgrade} =websocket [NC]
8-
RewriteRule <%= @cockpit_path %>/(.*) ws://<%= @cockpit_host %>:<%= @cockpit_port %><%= @cockpit_path %>/$1 [P]
9-
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
10-
RewriteRule <%= @cockpit_path %>/(.*) http://<%= @cockpit_host %>:<%= @cockpit_port %><%= @cockpit_path %>/$1 [P]
5+
ProxyPass http://<%= @cockpit_host %>:<%= @cockpit_port %><%= @cockpit_path %> upgrade=websocket
116
</Location>

0 commit comments

Comments
 (0)