josegonzalez/dokku-global-cert

global-cert:set does not work with sudo

ltalirz opened this issue · 8 comments

Certificates are often hidden from underprivileged users, i.e. commands related to manipulating certificates often require superuser privileges.

However, the dokku global-cert:set command does not seem to be able to take advantage of elevated privileges:

$ sudo ls /etc/letsencrypt/live/domain.io/fullchain.pem
/etc/letsencrypt/live/domain.io/fullchain.pem
$ sudo ls /etc/letsencrypt/live/domain.io/privkey.pem
/etc/letsencrypt/live/domain.io/privkey.pem
$ sudo dokku global-cert:set /etc/letsencrypt/live/domain.io/fullchain.pem /etc/letsencrypt/live/domain.io/privkey.pem
CRT file specified not found, please check file paths

It's not quite clear to me where the problem is introduced - is the command opening an underprivileged shell somewhere?

I'm not an expert in this, but if everything were just commands and bash functions running in the same shell, I believe this should work just fine.

I don't think this should work with that. We automatically drop permissions within the dokku binary to the DOKKU_SYSTEM_USER as otherwise folks might escalate to lord knows what accidentally. Thus, I wouldn't expect this to work. Thoughts?

I see.

Since I imagine it to be relatively common to have the certificates locally but owned by root, I think it would be helpful to provide instructions for this use case here, ideally ones that are compatible with the dokku_global_cert ansible module.

Should we suggest to simply make a copy of the certificates that is then owned by dokku?
In the end, after running the command, dokku anyhow stores another copy of the certificates internally, so I guess this would not be a security issue (although it doesn't seem very elegant).

@AubreyHewes since you used global-cert as well, I was wondering whether you also ran into this issue (i.e. that global-cert:set CHAIN KEY requires the CHAIN and KEY files to be accessible to the dokku user, also when run with sudo).

Did you simply make a temporary copy of the certificates in order to feed them to global-cert and then removed them again?

I think it would be useful to suggest a workflow to users of the global cert plugin.

@ltalirz sorry for the late response!

Initial global-cert files need to be available for the dokku user so when it is adding a global-cert it can be copied to the /var/lib/dokku and owned by dokku, So it can copy it to new apps. (this is the current usage).
So yes for this to work dokku needs to be able to read the initial global-cert. So yes you need to make the cert readable for dokku.

You are maybe running in to a few things...

  • sudo is not what you may think it is.
  • dokku copies the global-cert when set

I actually do not really understand your original issue (there is no error described), what is the issue?

The only thing I can think of is:
Invoking dokku as root which would/could break as the cert is readable and would be copied with the initial rights... which thereafter are not readable by the dokku user..?

I actually do not really understand your original issue (there is no error described), what is the issue?

Sorry, I've updated the excerpt just now to include the error.

The thought was that I could run dokku global-cert:set with sudo, which would allow the certificates to be read.
However, as José mentioned, the dokku executable internally drops permissions, resulting in the error message above.

I'm not sure it's wise to make dokku the owner of the certificates managed by the let's encrypt certbot (it might go back to root-owned after renewal), so perhaps the most practical route is indeed to make a dokku-owned copy of the certificates first.

@ltalirz

I do not get your comment

I'm not sure it's wise to make dokku the owner of the certificates managed by the let's encrypt certbot

Currently the global-cert plugin works as I described before; dokku REQUIRES read access; THEN dokku copies it to /var/lib (and so owns the copy) ; THEN on each new application copies it from /var/lib to the application home/tls.

This has nothing to do with the certs managed by le/certbot/lego/etc.. As the cert has been copied "on add" by dokku to be owned by dokku for further dokku usage.

This has nothing to do with the certs managed by le/certbot/lego/etc..

Well, that's how I get my certs, i.e. that is where I would like dokku to read (=copy) the certs from ;-)
I will now simply create another copy for dokku_global_cert to be able to read.

Ah ok, sorry if I sounded rude. But that is not how it works ;-)

If you are on one server than I can understand your problem. As you are doing everything on that one server. So you should give dokku acl rights to your origin cert directory (using setfacl).

I do the cert via lego on another server and upload them to the dokku server; the upload directory has rights enabled for dokku to read (via setfacl). Then I run a local script to add a new global-cert ... then I relink each app that used the previous global cert.

$ bash
local renew
local upload
remote global-cert:set
remote relink global-certs

You can (via setfacl) give dokku access to your original cert location... Though the cert will still be copied.

When you do global-cert:set the cert is copied to /var/lib. If you want dokku to be able to read your cert via sudo or not, dokku needs access to the cert. You can do this via setfacl.

NOTE: The cert is copied. So when it is updated the dokku instance will have no knowledge of a new cert.

Even setting a new cert via global-cert:set Any previous linked apps will have no knowledge of the new cert (this is the symlink pr). Will still use an old cert.

So you sort of need a hook on your global cert renewal to enforce it all (i.e. cron)

I think you can see the amount of out of band work involved ;-)