Comments (22)
from go-guerrilla.
Note that currently working on configuration file reloading feature, which has the ability to reload TLS config without restarting the server. This means that after each command run, the server can send a SIG_HUP to itself if it running, and TLS certificates will be reloaded.
from go-guerrilla.
I think the configuration file should include the whitelisted hosts/domains and the certificates should be served/fetched/verified automatically much like the net/http implementation
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("example.com", "example2.com"),
Cache: autocert.DirCache("/root/letsencrypt"),
}
s := &http.Server{
Addr: ":443",
TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
}
panic(s.ListenAndServeTLS("", ""))
I think /guerrillad certificate <server-interface> new
and ./guerrillad certificate renew
approach sucks because it's manual and the whole point of letsencrypt is to automate the certificate management.
from go-guerrilla.
Thanks for feedback.
Well then, perhaps it can be automatically setup if all conditions are met:
- The hostname is not a local host (and ip is not 127.0.0.1)
- STARTTLS is enabled or listening on port 465
- No external certificate specified in config
- Server is not used as a package (If used as a package, they would need to call a function to have the feature enabled, including their own cert storage handler)
For storage of Let's encrypt certs: would a dot folder be ok?
For renewals, check if the cert is about to expire when we get a SIGHUP, then renew if it matches above conditions.
from go-guerrilla.
There are likely a couple caveats. I think LE only permits requests for certs from servers listening on 'web ports', eg. :443, so the A Name record for the domain should be pointed at the IP address that the mail server is running on. This cert could then be used by the mail server, I imagine, without an difficulties.
I imagine the safest, and least breaking, way to do this would be adding options in the config file for ACME configuration(eg. Email address, agreeToTOS, ACME url etc), the user would then leave ServerConfig.PrivateKeyFile
and ServerConfig.PublicKeyFile
line empty or filled with a placeholder, perhaps "acme"
for each host requiring ACME certs. When starting the server, calls to the autocert package will run after parsing the config; obtaining a cert pair for each requiring certs(unless they exist in file already), saving the cert pairs to file, and adding that absolute path to the ServerConfig.PrivateKeyFile
and ServerConfig.PublicKeyFile
for that host.
I tried to implement a simple example within your package (a couple functions in config.go); not sure why but anything I try to print or log is simply ignored or suppressed. I imagine this has to do with the cobra cli app, but I am not sure how.
Lemme know, if you know why my functions seem to be ignored.
Schmorrison
from go-guerrilla.
Hi, thanks for doing some research.
For logging, have you tried setting the log_file to "stderr" or "stdout" in the config? Also, try starting with the -v flag.
FYI, as a convention, config values should be treated as read only, and only can be modified via the config file. That is because the config could be re-loaded at any time, there could be a race condition. To modify a config value, one must modify the file first and then either send a SIGHUP or call readConfig func, and then emit the config change events. See serve.go to see how it's done.
As for placeholders, would prefer not to use placeholders. The server should try to get the certs automatically as much as possible, as long as the above conditions are met. #29 (comment)
Email and 'agree to tos' are needed for account creation? Yes, these would need to be added to the main config, if an account is required.
So it looks like the problem is with how to do "Identifier Validation Challenges". https://github.com/letsencrypt/acme-spec/blob/master/draft-barnes-acme.md#identifier-validation-challenges
Yes, For HTTP based, it looks like it must bind to :443 or :80, which would not be possible, since almost certainly, there would be other servers bound to that port.
So, the alternative is to use DNS based?
We can model on how Caddy does it, for DNS https://caddyserver.com/docs/automatic-https
After having a first look, it seems it has a few plugins which can talk to some of the most common DNS providers. It also loads in the API credentials from the environment.
Maybe sometime in the future, it may be good to propose an SMTP based "Identifier Validation Challenge" to the Lets Encrypt people? For MTAs, the DNS validation is already half-there in the form of an MX records, all they need to do is send an email with the challenge. They don't need to register an account, an email address can be synonymous with an account. Say if they send it to [email protected] then our MTA would parse it. That would make it just as easy to get certificates for MTAs as it is for HTTP servers
from go-guerrilla.
Another alternative would be to use a tool called certbot from https://certbot.eff.org/
and writing a plugin: https://certbot.eff.org/docs/contributing.html#dev-plugin
The plugin would update the go-guerrilla config & send a sighup to the server so that the certificate can reload. https://certbot.eff.org/docs/contributing.html#dev-plugin - they have some plugin examples. It's written in Python.
from go-guerrilla.
Thanks flashmob.
I was using -v
flag but it wasn't revealing any additional info. I will try modifying the log_file line in the config tonight.
Also, duly noted on the config conventions.
So it sounds like the preferred way would be writing a wrapper package for certbot. Using it to request certs manually, then update the config and send a SIGHUP. Then on server startup, with the certificates correctly mapped in the config file, check if the certs are about to expire, and if they are then renew them and send a SIGHUP.
I am sure you are aware, but this will still require having port :443 available for the certbot --standalone
, or mapping to the correct webroot directory of the host web server that is occupying that port. I am sure having both options would be advantageous, and I imagine having a separate json config for the certbot cli flags would also make sense.
from go-guerrilla.
Thanks for the info. It is now becoming clearer that bunding an Acme client in go-guerrilla may be too much (at least for now). It may bring in some technical debt, especially to support all the various DNS providers, which probably change all the time.
So it seems like certbot does a lot of the heavy lifting. Also, it conforms to the Unix philosophy of "Make each program do one thing well".
With certbot, there is no need to check if the certs are about to expire. Just put certbot renew
on cron to run once per day, and then send a sighup to go-guerrilla. Certbot does the renewals automatically.
Cerbot supports the following challenges: tls-sni-01 (port 443), http (port 80), and dns. So yes, unless DNS based challenge is used, certbot must be able to have access to the webroot for that web server.
Btw, certbot is used for go-guerrilla deployment on Guerrillamail.com but we don't have a plugin for it, so some things are manual.
Here is how we deploy it with Nginx. In /etc/nginx/sites-available/default we add the following to the default server block:
location ~ /.well-known {
allow all;
}
}
Then run this command:
certbot certonly --webroot -w /home/www/public -d example.com -d www.example.com
where /home/www/public
is the webroot. Certificate gets dropped to /etc/letsencrypt/live/grr.la/fullchain.pem
and then we enter that to the config for go-guerrilla manually to install it.
In summary, a solution using certbot would be acceptable to claim the bounty, just needs to be a bit less manual : -)
So deliverables to claim the bounty would be:
- provide a certbot plugin. Assuming that this plugin reads the go-guerrilla config to figure out what cert it needs, does the challenge, updates the go-guerrilla configuration & does sighup. (no need to update config manually). [Note: please scope the plugin before developing, see if the assumption is correct or see if there is any hidden scope]
- Perhaps go-guerrilla could check if certbot is available, check if the host is able to do challenges and what challenges it can support. This check could be made when starting go-guerrilla with a certain flag, eg --certbot
- a wiki page documenting all, the way it works, any new options, how to install the plugin, briefly describe certbot and how to install it. etc.
What do you think? (edit: grammar)
from go-guerrilla.
Well I will keep it in mind, but unfortunately I have not used Python nearly enough to feel confident writing a plugin.
I'm all up for claiming a bounty, but after this discussion I do not believe this is the one.
At least the issue has been clarified for someone with more experience in Python.
from go-guerrilla.
Having a look at Python, it has a lot of similarity to Go, so if you know Go it may be easy to learn Python.
That said, the above are not absolute requirements. In the end, the contributor for this feature can decide on what to implement and how to do it. It should have been clarified that the above specifies the minim that would be accepted.
In summary,
- We now know what the conditions are for when to enable Let's encrypt automatically.
- We are clear that we can choose from multiple challenges types, and the details of each one. (If not using DNS challenge, then we need access to Port 80 or 433, or access to the webroot of a an already running web server).
- We will require new config options, eg email address for account creation and 'agree to terms'
- We are clear on the minimal solution that would be accepted. (Certbot plugin)
Although we have not fully discussed the scope of a DNS based challenge. Perhaps the minimal solution that could work here is you could start go-guerrilla with --agree option which would then prompt the user to set an A/AAA record for their domain, press any key to continue. Then a goroutine could try the challenge and update the config file once the challenge passed. In that case, there would be a manual step involved. Others, such as Caddy server are able to remove the manual step by using external APsi, however, for us, this requirement may be too much to do on first version. Therefore, if a DNS change requires a manual step then that would be acceptable.
Also, what do you think if we drafted a proposal to the Let's Encrypt people to support an new MX record based challenge? It seems like LE is HTTPS centric, an MX record based challenge would be great for SMTP and possibly even POP. Maybe @ginkoob has some thoughts on this?
from go-guerrilla.
Been thinking about this, and while I'm not able to spend enough time to learn Python to write a plugin. I am able to continue thinking about the best way to implement it in Go.
I'll take a close look at Caddy and how they manage the DNS challenges. In lieu of automated DNS challenges, knowing you are amenable to a manual step for the time being, I will think about how to display the txt record that needs to be changed for letsencrypt.
For example, if they know they are doing a DNS challenge; then first, they need to see the challenge value; then update the DNS record manually at their name server; then continue the challenge. It is not immediately clear to me how to execute this outside the main routine as you suggested.
It occurs to me that it could be significantly easier to write, if the user knows which type of challenge they are doing for certificates, and can configure that. If they want to do the "golang.org/x/crypto/acme/autocert" then:
- we should test for ports open(:80, :443)
If they have configured a webroot of a running server:
- test that the folder(webroot) exists and we have permissions
In all challenge types, probably:
- that the domain name resolves locally
- the folder to store certificates exists
In the case of a "acme/autocert" or webroot, after informing go-guerilla about the desired challenge, it certainly would be possible to execute in a separate goroutine, but if the challenge fails; what is the best way to inform the user?
I'm sure there are a number of incoherent thoughts in there. I want to spend some time this weekend maybe working on this.
schmorrison
from go-guerrilla.
Yes, it all boils down to how the user will do the challenge.
Perhaps we can have this set in the config.
In that case, please see cmd/guerrillad/serve.go - there is a CmdConfig struct defined. This struct adds additional options to the server config when starting from the command line.
You can add extra config options to CmdConfig, eg, what challenge method to use, where is the web-root, folder to store certificates, LE account email, accept to the LE TOS, etc.
Somewhere in the serve function, after the config has loaded, you would need to add a call to your processing function, where these config settings and evaluated determine what steps to take. eg. perhaps configureAcme(c *CmdConfig)
Your configureAcme should update the config with new settings. If the configureAcme function changed the config file, i.e it installed a certificate, then you would need to reload the config. ie. err := readConfig(configPath, pidFile, &cmdConfig)
(doing it before config is used by the guerrilla package). Maybe it would be acceptable to prompt the user (y/n) to acknowledge if they want to do a step manually if starting from a command line. Timeout after x seconds if no response given.
The tricky part may be to get it to work with auto-config reloading (see sigHandler
func. In that case, we can do only if challenges are fully automated. The server can already detect if a certificate changed by comparing the timestamp, and re-configure automatically when a SIGHUP signal is caught.
That said, the code in serve.go is about change after huge refactor - but if you keep the changes around in serve.go and acme processing stuff in a separate file, that should minimise merge conflicts. See the new branch that's about to get merged (pending review) here #71
from go-guerrilla.
Duly noted flashmob. I'll let you know if I have any questions.
from go-guerrilla.
Ok, sorry a bit in a hurry now and made a few mistakes and omitted a few details - made some edits above. Cheers.
from go-guerrilla.
@flashmob is the bounty on this issue still active?
from go-guerrilla.
@rahulgi Yes! There's been no activity on this for a while - so you're welcome to take over.
from go-guerrilla.
Why do need a plugin for certbot? I used deploy hook and I hope that everything will be fine)
from go-guerrilla.
Going to shelve this feature from the roadmap.
Rationale:
It seems certbot
works fairly well for getting LE certificates, and having them enabled in go-guerrilla is just a question of pointing the config to them.
If this feature is re-visited in the future, perhaps it can use the "DNS-01 challenge" using this library https://github.com/go-acme/lego
from go-guerrilla.
@flashmob what is the status on Lets Encrypt? Free certificate is always good, better if built in, no need to use any other scripts to do some hacks.
I think Lego is being used by Traefik, and it seems like a solid choice, if there are any vendor changes, just bump lego version and keep on going.
from go-guerrilla.
from go-guerrilla.
I have been using Caddy for my routing, and as a bonus it handles SSL certs via LE automatically if required.
from go-guerrilla.
Related Issues (20)
- Feature request: Delay before sending a message HOT 2
- Runtime error: index out of range HOT 2
- CPU restriction to 1 HOT 1
- Little bug corrected for windows HOT 4
- AWS S3 Backend HOT 1
- Need larger emails to be supported
- Windows Compilation HOT 1
- I need a build a service for expiring e-mail HOT 1
- Email subject is empty when subject contains blue heart symbol HOT 2
- Allow to pre-fill the "To" (e-mail) and "Subject" fields using URL arguments HOT 1
- GuerrilaMail doesn't send email HOT 3
- Only part of domains was blocked that organisation?
- is this project abandoned? HOT 4
- Is the project and bounties still active? HOT 5
- start error error while initializing the backend: processor [mysql] not found
- How to get email content when email is sent to server? HOT 1
- AUTH LOGIN Support
- No more sending emails :'( HOT 1
- HELP is not compliant with RFC 2034 (ENHANCEDSTATUSCODES) HOT 1
- Project has moved
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from go-guerrilla.