sandstorm icon indicating copy to clipboard operation
sandstorm copied to clipboard

HTTPS support for custom domains when using static publishing and sandcats.io

Open nicolas-arnold opened this issue 4 years ago • 11 comments

Hello there,

TL;DR: How do I add a custom domain as a SAN entry to the certificate sandcats.io generates for me? (To fix SSL_ERROR_BAD_CERT_DOMAIN because my certificate only handles username.sandcats.io and *.username.sandcats.io)

I am having issues with the following setup:

  • I am using sandcats.io for DNS
  • I am using the hakyll-app (also tried hugo) with static publishing functionality
  • I want to have a nice, short custom domain to reach this site cleanly
  • I am using sniproxy to reroute requests according to their domain to forward requests to sandstorm or apache2 respectively.

What works: I can get http working with no issue. But: I cannot get HTTPS to work, because I get certificate errors: SSL_ERROR_BAD_CERT_DOMAIN, because the certificate does not contain the hostname of my custom domain.

I have read a whole lot of stuff about all this now, and still can't see a clear path of how to do this, with sticking to sandcats.io for DNS. As far as I understood, I would want to hook into the process of sandcats certificate generation and add my custom domain(s) as SAN entries of the certificate. I am not sure, if this is easy or even possible and I do not know a lot about ACME or how it's integrated in all of that.

As I know there is also an ongoing discussion about the SSL/TLS admin page UI/UX, I would like to point out some UX expectations, if there is a simple way to add custom domains to the certificate generated by sandcats.io:

  • Add a text input to list custom domains that should be integrated into the certificate as alternative names. (support line, space and ; separation at least - ignoring whitespace):
custom.domain.com
another.domain.net

custom.domain.com another.domain.net

custom.domain.com; another.domain.net
  • Add a cli command: sandstorm sandcats add-san-entry custom.domain.com

It's no problem to add TXT entries for confirmation of domain access, as this is already needed in the current setup of how static publishing works.

I am surprised there is not much documentation about specifically this use case / explanation on how to configure this. So maybe I am missing something.

If this is all possible via certbot, acme or sth. then please add documentation about how to hook into the process of certificate generation, or/and add options for sandstorm.conf: CUSTOM_DOMAINS: custom.domain.com;my.domain.com;customdomain.net

#3300 To me it's also a bit weird that acme account is defined as a contact email (is this used as login credential? how would I be contacted via this address?) and a generic directory url. Do I have credentials? Again, how do I hook into that process.

I think, the most important thing for this interface to have better UX is explain those things, which are not self-explanatory. The questions is: What actions would I expect being able to perform on such a page?

I am happy to provide more details but feel like this is already a lot, so I stop here and maybe there are some simple answers.

Thanks in advance and thanks for this great platform. It's running for a long time now and it's of great use!

Related to #2771 and a bunch of others..

nicolas-arnold avatar Jun 02 '21 00:06 nicolas-arnold

Right now I don't think there's a way to do this without just managing TLS yourself. I agree it would be good to be able to add domains via the admin panel and/or CLI.

The questions is: What actions would I expect being able to perform on such a page?

I think this is the core of the issue with that page: there's not really much you can usefully do with it, since if you don't already have a working cert then you can't get to it... IIRC @kentonv implemented the page before realizing that. So there are some very obvious glaring problems, but the most fundamental is it's not clear what the page is even for.

There are some features that it seems like would make sense to put there, incl. adding extra domains, which would give it more purpose.

zenhack avatar Jun 02 '21 00:06 zenhack

Thanks for the quick response! Can you explain, why it's not possible to add custom domains to the certificate generated via sandcats.io? Certbot certainly allows you to just add -d next.domain.com -d alsoadd.thisdomain.com flags on the cli, so I guess the harder part must be the verification process? (Although this only needs to be done occasionally).

If this is not possible and not fixable in the near future, I want to emphasize that the documentation of sandstorm should point that out clearly. As in most places what I'm reading sounds more like you can do more with sandcats.io and the whole platform is mostly built around sandcats.io - so I would consider this a basic feature.

However, right now the documentation would need to say something like:

  • For using custom domains together with sandcats.io for DNS it's
  • Although we generate the certificate on our own, it is not possible to add custom domain names other than username.sandcats.io and *.username.sandcats.io as alternative names (SAN) because of ...
  • If you want to have SSL / https working for staticly published content, you need to use your own DNS / certificate setup (..be more precise here) and generate your own certificates as needed.
  • If you experience SSL_ERROR_BAD_CERT_DOMAIN and you have configured your DNS correctly (mainly CNAME/A and TXT entries), you are most likely running sandstorm via sandcats.io DNS.

Probably the last point would not be phrased like that in the context, but I should be able to find information in the docs when searching for the error I get using the native DNS solution following descriptions about static publishing from the docs.

[Edit] When you say without just managing TLS yourself do you mean without using sandcats.io or can I still use sandcats.io and just need to fire up a specific cli command to modify the configuration of the certificate generation process?

nicolas-arnold avatar Jun 02 '21 00:06 nicolas-arnold

There is another idea for hacking it:

  • The static content is just somewhere in the ../sandstorm/grains/.../var/sandbox/www/-folder.
    • Can I just serve this folder via apache2, or is this considered totally bad?
    • I could have a script copy the content of this folder to the server's root /var/www/somepage/ and serve it from there via apache2 or some other webserver.

But in the end I lose all benefits of using sandstorm and would be better off, generating the static content somewhere else. What sandstorm gives me, is the sharing/access model and an app with in browser editing and preview. In turn it takes most ways to customize the app (especially as hakyll is considered a blog library anything more advanced would need better access to the internals and good integration into dev tools/workflow. Especially what I would lose is the seamless single interface and place of concern.

Although maybe it's feasible to maintain a fork of the app, changing the hakyll source / site.hs as needed an integrating this derivated app into my own sandstorm instance. I can't judge how much of an effort this would be, but I am also interested in supporting the project on the code side of things some day.

(Sorry for drifting slighlty off topic here)

nicolas-arnold avatar Jun 02 '21 01:06 nicolas-arnold

Quoting nicolas-arnold (2021-06-01 20:45:18)

Thanks for the quick response! Can you explain, why it's not possible to add custom domains to the certificate generated via sandcats.io?

No particular reason, just nobody's implemented it yet. As I said, I agree this would be a good feature to add, though I can't promise if/when someone will get to it -- there's an endless supply of things to do and a very small pool of volunteer labor to do them. Contributions welcome, either to the code or the docs.

zenhack avatar Jun 02 '21 02:06 zenhack

Quoting nicolas-arnold (2021-06-01 21:22:45)

There is another idea for hacking it: * The static content is just somewhere in the ../sandstorm/grains/.../var/sandbox/www/-folder. + Can I just serve this folder via apache2, or is this considered totally bad? + I could have a script copy the content of this folder to the server's root /var/www/somepage/ and serve it from there via apache2 or some other webserver.

These would indeed both work, though I agree it's a bit sad.

But in the end I lose all benefits of using sandstorm and would be better off, generating the static content somewhere else. What sandstorm gives me, is the sharing/access model and an app with in browser editing and preview. In turn it takes most ways to customize the app (especially as hakyll is considered a blog library anything more advanced would need better access to the internals and good integration into dev tools/workflow. Especially what I would lose is the seamless single interface and place of concern.

Although maybe it's feasible to maintain a fork of the app, changing the hakyll source / site.hs as needed an integrating this derivated app into my own sandstorm instance. I can't judge how much of an effort this would be, but I am also interested in supporting the project on the code side of things some day.

I could very much imagine something like hakyll being packaged in such a way that you could rebuild the haskell bits inside the grain, allowing you to actually use the library directly, not just edit the HTML files. (which would of course require including cabal & ghc in the package). If you want to try to build a better hakyll package, I'd certainly encourage it, and feel free to pick our brains about it further.

zenhack avatar Jun 02 '21 02:06 zenhack

@nicolas-arnold Re: "sounds more like you can do more with sandcats.io"

I would say the Sandstorm-the-business approach was very bullish on Sandcats.io, and many of the documents written around that time reflect that. At the time Sandstorm was first launched, wildcard SSL was not available for free (Let's Encrypt didn't support it yet), and of course, wildcard DNS and dynamic DNS are often configuration sticking points. So Sandcats.io provides/provided a very easy "quick start" where the Sandcats service is doing all the hard things outside of your Sandstorm server, and providing that for free.

IMHO, especially now that wildcard SSL is free with Let's Encrypt support directly in Sandstorm, that Sandcats is still a really nice easy-config option, but that if you're looking to do more sophisticated things and have the infrastructure to do so, using your own domain will give you more options.

Which is not to discourage use of Sandcats.io, but that you should not feel like it's preferable over using your own domains if that's a route you're comfortable with. And yeah, our documentation specifically around the Let's Encrypt support needs some work.

ocdtrekkie avatar Jun 02 '21 03:06 ocdtrekkie

I see, thanks for the explanations. I really thought there is some technical complication around this and not just the missing (straightforward) implementation.

So where would the hook be, how does the generation of the certificate get invoked? I would happily provide documentation for a manual workaround, but I would need some help/hints on where to change what. Ideas:

  • Get the verbatim command that get's run to acquire the certificate, run it manually (modified to add the custom domain names) and upload the certificate manually to sandstorm at the SSL/TLS page. (where do I have to look?)
  • Find the command that get's run when you hit "fetch certificate now" and manually hardcode your favourite domains in? (if it's as simple as adding -d my.domain.com as in the certbot-cli.)

I see the point of wildcard certificates being a game changer. I am totally happy with how seamlessly sandcats.io works and adding SAN to the certificate it generates is the only limitation I experienced so far.

web-ui, sandstorm-apps and cli/direct access interop?

Another question on UI/UX: (warning: I am about to hijack this to more general UI/UX discussion, maybe we should rename this and make a separate issue which only contains the technical SSL certificate parts. Let me know, if I should do this.)

Are there/should there generally be equivalent ways of achieving things via web-interface or cli-interface / manual actions? Specifically: When I use "manual certificate upload", is it basically just copying the provided files to a specific folder, and could I equivalently just put those two files at a specific folder to achieve the same thing? This would make it much easier to develop workarounds, so we could fix a lot of things already before they get implemented into sandstorm's web-ui or cli-ui.

So I am asking: Wouldn't it be nice, if the web-interface was generally a convenient way to configure things, but the underlying processes are simple and can also be achieved in a more direct (and scriptable) way - or will this introduce a lot of problems, and it's better to just let all of it be handled by the more controlled web-interface?

At those places, where the web-interface basically just fires simple commands, it could be a good design decision to make those actual commands visible in the web-ui (maybe in an expert mode, or as a hover-text to the buttons). This would make the magic behind how things work more transparent, allow for intermediate users to try to hook into those processes more easily and it could potentially make it easier for users to ask better questions, provide better fixes and ask less questions like I did.

This question also expands on sandstorm apps: For apps that manage files. It would be nice, if an app is able to deal with manual change to the files it contains, e.g.:

  • Hakyll basicall manages a folder of files. The site compilation will take a look at all files present. The app does not manage specific state of the files, no need to maintain a database with metadata etc. So the app does not really care, if I cd into the grain and use vim to process the css file, or run a tool which provides vendor-prefixes and replace the css file (although it would be better to include this into site.hs in this case). It just uses the css file it finds at site generation time.
  • So I can imagine, in general it's critical to have users modify such files directly. As they could mess things up. At the same time, I feel like this is one of the most limiting things in sandstorm: losing easy access to (a) config file (like etherpad which has a lot of config options, but on sandstorm I have to use what's there) and (b) direct file access.
  • Or consider an app that provides cloud-hosting handling all the access stuff, but then basically serves files. I would like being able to backup those files by just copying those files (probably I can just do that). But also I would like to add files from the cli, and the app should just rescan that folder and serve those files respectively, or detect those files and ask me to provide more options (e.g. if permissions cannot be guessed, the app should list those files as detected but not served until those decision have been made.
  • So: Can we manage, support, encourage using direct access to a grains "private" folder? Can we let an app developer specify which operations are save? (like adding/removing files). Can this be handled on a per-file-basis by using unix file permissions? (you can assign your user to a sandstorm-manual group and then you are able to edit those files the app developer specified save to edit?). Can we provide a subfolder in each grain, where users are encouraged to put there own files, extra-config etc. in?

This would be an intermediate way of allowing customization which is "more than the defaults", giving access to the customization options of the apps that where packaged, but one does not need to change the app itself, thus the entry barrier of setting up a sandstorm-dev IDE is removed.

On hakyll: I will play around with the original hakyll stuff and once I got some intuition on how to work with it, I would happily help working on the sandstorm implementation of it. E.g. on mac it's really a hassle at the moment to get it running at all, which is yet another reason why a sandstorm app is pretty convenient here.

Thanks for all your efforts :)

nicolas-arnold avatar Jun 02 '21 11:06 nicolas-arnold

Are there/should there generally be equivalent ways of achieving things via web-interface or cli-interface / manual actions?

Probably in an ideal world, Sandstorm should be a bit more script-able. There are some legacy reasons it wasn't, much of which has been resolved, but further build out of the CLI hasn't happened. #3313 refers to, I think, the specific command you are looking for here. It also describes a sandstorm mongo command which can more or less insert a certificate manually, with a bit of a caveat. (One of the odd things you'll notice here is that Sandstorm no longer stores certificates in the file system, but in the database.)

There is a script that exists to extract the certificate from the Sandstorm database you can find here: https://github.com/Michael-S/sandstorm_certs_extract_cron though I am kinda doubtful there's a way to add in a SAN to the certificate request, prior to it being signed.

So: Can we manage, support, encourage using direct access to a grains "private" folder?

In a lot of cases, I would say "it'll work", but the issue is often that different apps may or may not handle it, so we're going to hesitate to recommend it. In an ideal world, the Sandstorm project has a bunch of full-time developers, and we can do everything we want to do, which is ideally to make doing everything you'd want to do with Sandstorm really, really easy so non-technical users can do it.

Unfortunately, that's the world I dream of when I am asleep and not the one we live in, so often good feature requests just "haven't been done by anyone yet", because nobody has volunteered to get it done. In a lot of cases, apps do use very simple storage methods, and tampering with them from the underlying OS will probably work fine. (Davros doesn't store state at all, I believe it's just a folder of files at the end of the day. I think TextEditor is literally a txt file, etc.) In lieu of being able to turn around a needed feature in a short time, often it can be helpful to just explain where users can find these things to do things the old-fashioned way.

But you can probably get yourself into some weird spots, especially if you aren't paying attention to what Sandstorm does with certain things. For instance, when you refer to a grain that does web publishing, the grain storage is one thing, and then the static publishing folder is another. If you modify the grain without having the app publish the changes, you see nothing. If you edit the www folder without editing the grain, your www folder no longer reflects the contents of the grain, and will be overwritten if someone pushes changes from the grain.

Note that one common way we recommend monkeying with the files in grains which can be done while not local, is to tell people to download the backup, edit the contents of the backup, and restore it as a new grain. It won't let you maintain the same grain IDs, but can be convenient for some things.

ocdtrekkie avatar Jun 02 '21 15:06 ocdtrekkie

Are there/should there generally be equivalent ways of achieving things via web-interface or cli-interface / manual actions?

Probably in an ideal world, Sandstorm should be a bit more script-able. There are some legacy reasons it wasn't, much of which has been resolved, but further build out of the CLI hasn't happened. #3313 refers to, I think, the specific command you are looking for here. It also describes a sandstorm mongo command which can more or less insert a certificate manually, with a bit of a caveat. (One of the odd things you'll notice here is that Sandstorm no longer stores certificates in the file system, but in the database.)

... though I am kinda doubtful there's a way to add in a SAN to the certificate request, prior to it being signed.

So then I don't understand how I would go about his. Shouldn't it be simple to add SAN entries to the request command? What API is used here, where could I try to look that up?

So: Can we manage, support, encourage using direct access to a grains "private" folder?

In a lot of cases, I would say "it'll work", but the issue is often that different apps may or may not handle it, so we're going to hesitate to recommend it.

A shorthand I can think of would be for app devs to being able to state, what "levels" of manual interactions are possible and what problems might occur that way. Just like a hint of: We are just loading this .txt file and you can edit it directly on disk, we don't care. ...but I see how there would preferably some kind of lock mechanism and it would not be simply clean. I was just wondering :).

nicolas-arnold avatar Jun 02 '21 16:06 nicolas-arnold

Re: scriptability, I agree; my general vision for this is to expose everything through capnp APIs, and have the web UI use them exclusively to talk to the server so it can't "cheat" and do something that can't be done programmatically using public APIs. We need to get capnp working in the browser first though, which is among my near-term priorities.

So then I don't understand how I would go about his. Shouldn't it be simple to add SAN entries to the request command? What API is used here, where could I try to look that up?

I think @ocdtrekkie is saying it's probably not feasible to use external scripts like the one he linked to to solve this. If you want to get your hands dirty trying to add this as a feature properly, shell/imports/server/acme.js is the place to look.

zenhack avatar Jun 02 '21 17:06 zenhack

Thanks for the hint, I will see if I can come with anything. So mostly I need to learn how acme works in general. Any hints and ideas of what to try are still welcome.

What you say about capnp and having a single API sounds totally like the way to reach these goals in a reasonable and "for free" manner which is sustainable and expandable! Looking forward to this.

nicolas-arnold avatar Jun 02 '21 20:06 nicolas-arnold