Project

General

Profile

SSL with multiple domains.

Added by wonderboy over 3 years ago

Hello,
I have the following configuration:


$SERVER["socket"] == ":443" {
    ssl.engine = "enable" 
    ssl.pemfile = "/etc/lighttpd/ssl/lighttpd-selfsigned.pem" 
#    ssl.pemfile = "/etc/lighttpd/ssl/api.somesite.co/somesite_certbot.pem" 
}

$HTTP["host"] =~ "^(api|payment|admin|back\-office|casino\-api)\.([0-9]+)\.somesite\.co$" {
    evhost.path-pattern = "/var/www/html/%3/%4/public" 
    url.rewrite-if-not-file = (
        "\.(?:js|ico|gif|jpg|jpeg|png|css|ttf)$" => "",
        "^/([^\?]+)(\?(.*))?$" => "/index.php?_url=/$1&$3",
    )
}

I have couple issues:
1) If I put ssl.pemfile in the $SERVER directive it works, but if I put it in the $HOST directive it doesn't. I read [[https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_SSL]] but there is for static domains, not with evhosts. Can it work this way? If needed I can put api, payment, admin, back-office and casino-api in different $HOST directives, but I should keep the \.([0-9]+)\. part, because this is the ID of the employee, I don't want to create $HOST for every project for every employee.

2) I can generate certificate for all projects when I add new employee, but can I used them with pattern? Something like:

$HTTP["host"] =~ "^(api|payment|admin|back\-office|casino\-api)\.([0-9]+)\.somesite\.co$" {
    evhost.path-pattern = "/var/www/html/%3/%4/public" 
    ssl.pemfile = "/etc/lighttpd/ssl/api.%3.somesite.co/somesite_certbot.pem" 

Replies (10)

RE: SSL with multiple domains. - Added by wonderboy over 3 years ago

I forgot to add:
lighttpd/1.4.55 (ssl) - a light and fast webserver
VERSION="20.04.1 LTS (Focal Fossa)"

RE: SSL with multiple domains. - Added by gstrauss over 3 years ago

No, sorry, as you (did not) see in the Docs_SSL documentation, ssl.pemfile does not operate on a pattern in lighttpd. lighttpd currently loads and processes the config at startup. While dynamic choices are made for each request at runtime for what to select from the configuration tree, the configuration tree itself does not dynamically change after startup.

From your description, it sounds to me that you may be confusing server certs with client certs. Server certs identify a server. You could have a single wildcard cert for *.somesite.co. Client certs can be used to identify clients, and can be used with mod_auth.

RE: SSL with multiple domains. - Added by wonderboy over 3 years ago

Thank you for the reply. I must have missed the part that ssl.pemfile cannot operate on pattern.

I need server certificates, not client ones. I want each employee to has his own set of (sub)domains, so everyone will be able to work alone on his tasks. Let's say employee 100 has to work with 3rd party Company1, he can give them api.100.somesite.co as address, while employee 200, who works with Company2 can give them address api.200.somesite.co. Each of them will be able to work completely independantly.

I can't use single wildcard certificate, because they work only on one level of subdomain, while I'm using [service].[employee].somesite.co, which are two levels. I can easily swap [service] and [employee] and create $HOST directive for each service, but again because of the pattern matching for the employee I won't be able to apply the certificate.

I'll find some solution, thank you again :)

RE: SSL with multiple domains. - Added by gstrauss over 3 years ago

Aside: my comment about not seeing pattern matching in ssl.pemfile documentation is that such pattern matching is not supported in ssl.pemfile; pattern substitution in ssl.pemfile is not documented because it is not supported. Put another way, you did not see "support for pattern matching" there because pattern matching is not supported in ssl.pemfile, and the documentation is for things that ssl.pemfile does, not for things which ssl.pemfile does not do. If ssl.pemfile supported pattern matching, that feature would be documented.

I am still interested in trying to understand your use case.

Are you perhaps giving the server certificate private keys to employees to run on their own servers? If you manage the server and manage all the server certificate private keys, then why is a wildcard certificate not a possible solution? The hostname in web links and the URL bar will still be api.200.somesite.co even if the TLS server certificate is for *.somesite.co.

If each employee writes PHP or other code that runs on the server side and you need to isolate per employee, then you might use a lighttpd primary server (or HAProxy or other) which has all server certificates (or the single wildcard) for the front-end web server which terminates the TLS, and you could reverse proxy back to a second tier of web servers, one for each employee, where each web server in the second tier would run under a separate user id per employee.

I do not yet see why the TLS server certificate must be the bottleneck for scaling your configuration. TLS certificate management has its own challenges, and where possible, it is usually best to minimize the complexity and work involved for proper certificate management.

[Edit]
A wildcard cert for each of

*.api.somesite.co
*.payment.somesite.co
*.admin.somesite.co
*.back-office.somesite.co
*.casino-api.somesite.co

would be 5 TLS certificates, which is a fairly small number to manage.

RE: SSL with multiple domains. - Added by wonderboy over 3 years ago

This is exactly what I want - to have small, simple and proper setup :)

We have production.com and somesite.co as our test/development one.
Currently we have only "api.somesite.co".
api.somesite.co points to 99.99.99.99 server with root folder /var/www/api

We want to work with some 3rd party company and we will exchange data - we send them something to their API, they will send notifications to us. It means we have to give them address where to send the notifications. Everything has to be https. This works perfectly for production (api.production.com) and worked fine for development(api.somesite.co) until recently because the company had few employees. It had never happened two employees to integrate services which use the same address at the same time. So when I work only I use /var/www/api, when I finish another one can use it.

The team has expanded and will grow further. At the moment there are three tasks running for integrating services from third party companies. 3 developers have to use api.somesite.co at the same time and thus using /var/www/api. Sharing this directory is .. lets' say NOT ok. Not because of security but because someone may overwrite the work of other or delete something.

Because of this I want to have:

100.api.somesite.co => /var/www/100/api
100.payment.somesite.co => /var/www/100/payment

124.api.somesite.co => /var/www/124/api
124.payment.somesite.co => /var/www/124/payment

200.api.somesite.co => /var/www/200/api
200.payment.somesite.co => /var/www/200/payment

This way everyone will have his own folder for development and can give his own address to the company he works with.

I agree that making it:

*.api.somesite.co
*.payment.somesite.co
*.admin.somesite.co
*.back-office.somesite.co
*.casino-api.somesite.co

will be acceptable number of certificates, but again I will have:
$HTTP["host"] =~ "^([0-9]+)\.(api)\.somesite\.co$" {
    evhost.path-pattern = "/var/www/html/%4/%3/public" 
    url.rewrite-if-not-file = (
        "\.(?:js|ico|gif|jpg|jpeg|png|css|ttf)$" => "",
        "^/([^\?]+)(\?(.*))?$" => "/index.php?_url=/$1&$3",
    )
}
$HTTP["host"] =~ "^([0-9]+)\.(payment)\.somesite\.co$" {
    evhost.path-pattern = "/var/www/html/%4/%3/public" 
    url.rewrite-if-not-file = (
        "\.(?:js|ico|gif|jpg|jpeg|png|css|ttf)$" => "",
        "^/([^\?]+)(\?(.*))?$" => "/index.php?_url=/$1&$3",
    )
}

And because of the pattern matching I can't use per-host ssl.pemfile.
I've never had to use multiple certificates in single file and I have to check it. If I can put all the wildcard certificates in a single file and use it will solve my problems. I will even continue to work with only two $HOST directives.

Just to imagine the scale - one year ago this company had like 15-20 developers, now has 50 and soon will be 100+. Beside these 5 we have 5 more, which are using different url.rewrite and are in another $HOST directive.

RE: SSL with multiple domains. - Added by gstrauss over 3 years ago

It sounds to me like your test server should have a single wildcard certificate for *.test.somesite.co and you can then use evhost.path-pattern to change the document root for any combination of (api|payment|admin|back-office|casino-api) and employee-id that you like. Simple.

e.g. api.1000.test.somesite.co

RE: SSL with multiple domains. - Added by gstrauss over 3 years ago

While I still recommend a single wildcard cert for use in the scenario you described above, you might not have realized that you can use multiple conditions in lighttpd.conf with different directives in them.
Note that for the same directive, such as url.rewrite-if-not-file, the last condition matched with that specific directive is the specific directive that takes effect for the request.

$HTTP["host"] =~ "*\.api\.somesite\.co$" {
    ssl.pemfile = "/etc/lighttpd/ssl/wild.api.somesite.co.pem" 
}
$HTTP["host"] =~ "*\.payment\.somesite\.co$" {
    ssl.pemfile = "/etc/lighttpd/ssl/wild.payment.somesite.co.pem" 
}
$HTTP["host"] =~ "*\.admin\.somesite\.co$" {
    ssl.pemfile = "/etc/lighttpd/ssl/wild.admin.somesite.co.pem" 
}

$HTTP["host"] =~ "^(api|payment|admin|back\-office|casino\-api)\.([0-9]+)\.somesite\.co$" {
    evhost.path-pattern = "/var/www/html/%3/%4/public" 
    url.rewrite-if-not-file = (
        "\.(?:js|ico|gif|jpg|jpeg|png|css|ttf)$" => "",
        "^/([^\?]+)(\?(.*))?$" => "/index.php?_url=/$1&$3",
    )
}

RE: SSL with multiple domains. - Added by stbuehler over 3 years ago

Just as a generic note: using "Common Name" to verify certificates has been deprecated (RFC 6125, §6.4.4: Checking of Common Names) for quite some time. I'd guess every "sane" client released in the last 5 years supports "Subject Alt Names" (and might even prefer it over "Common Name"; i.e. if your name is only listed in "Common Name", and you do have "Subject Alt Names", it might even ignore the "Common Name". Also I'm quite sure proper CAs will make sure the certs they sign use "Subject Alt Names").

Which means there should be nothing preventing you from having multiple wildcard names in a single certificate.

RE: SSL with multiple domains. - Added by wonderboy over 3 years ago

As far as I know the wildcard certificate works with only 1 level of subdomain. For example if you have wildcard for

*.test.somesite.co

it will work for
api.test.somesite.co

but won't work for
api.1000.test.somesite.co

I will definitely change the URL scheme:

api.1000.somesite.co => 1000.api.somesite.co

because it turns out is actually necessary to deal with the certificates. If I can put all certificates in one file and give it as single file for the whole server will be super. (Thanks @stbuehler, for the info.)

@gstrauss, is this allowed:

$HTTP["host"] =~ "*\.api\.somesite\.co$" {
    ssl.pemfile = "/etc/lighttpd/ssl/wild.api.somesite.co.pem" 
}

I understood that "=~" is preventing ssl.pemfile from working. I thought it needed "==" in order to work. Did I got it wrong again?

Tomorrow I think I'll be able to test with my domain, but if it is needed to test with company domain it will be delayed for Monday. I'll let you know with the result

RE: SSL with multiple domains. - Added by gstrauss over 3 years ago

As @stbuehler noted, you can have a single wildcard certificate with

*.api.somesite.co
*.payment.somesite.co
*.admin.somesite.co
*.back-office.somesite.co
*.casino-api.somesite.co

Since mod_evhost operates on the name segments between dots or single chars, using mod_evhost would require 1000.api instead of api.1000. An alternative would be Docs_ModVhostDB and mod_vhostdb_dbi (or PostgreSQL or MariaDB) to store the names in a SQLite database. Then, you could have *.test.somesite.co (or *.somesite.co) and can use SQLite to map api-1000.somesite.co to the docroot path you desire. (Note the '-' or other separator, not including '.')

    (1-10/10)