2016-02-08 00:59:03 +00:00
|
|
|
// Let's Encrypt client to go!
|
|
|
|
// CLI application for generating Let's Encrypt certificates using the ACME package.
|
2015-06-08 00:36:07 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2016-03-18 00:32:24 +00:00
|
|
|
"fmt"
|
2015-06-08 00:36:07 +00:00
|
|
|
"log"
|
|
|
|
"os"
|
2015-06-12 21:34:49 +00:00
|
|
|
"path"
|
2016-01-09 01:13:13 +00:00
|
|
|
"strings"
|
2016-03-18 00:32:24 +00:00
|
|
|
"text/tabwriter"
|
2015-06-08 00:36:07 +00:00
|
|
|
|
|
|
|
"github.com/codegangsta/cli"
|
2015-12-30 22:01:21 +00:00
|
|
|
"github.com/xenolf/lego/acme"
|
2015-06-08 00:36:07 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Logger is used to log errors; if nil, the default log.Logger is used.
|
|
|
|
var Logger *log.Logger
|
|
|
|
|
|
|
|
// logger is an helper function to retrieve the available logger
|
|
|
|
func logger() *log.Logger {
|
|
|
|
if Logger == nil {
|
|
|
|
Logger = log.New(os.Stderr, "", log.LstdFlags)
|
|
|
|
}
|
|
|
|
return Logger
|
|
|
|
}
|
|
|
|
|
2016-01-09 01:13:13 +00:00
|
|
|
var gittag string
|
|
|
|
|
2015-06-08 00:36:07 +00:00
|
|
|
func main() {
|
|
|
|
app := cli.NewApp()
|
|
|
|
app.Name = "lego"
|
2016-03-23 18:12:47 +00:00
|
|
|
app.Usage = "Let's Encrypt client written in Go"
|
2016-01-09 01:13:13 +00:00
|
|
|
|
2016-03-23 18:12:47 +00:00
|
|
|
version := "0.3.0"
|
2016-01-09 01:13:13 +00:00
|
|
|
if strings.HasPrefix(gittag, "v") {
|
|
|
|
version = gittag
|
|
|
|
}
|
|
|
|
|
|
|
|
app.Version = version
|
2015-06-08 00:36:07 +00:00
|
|
|
|
2015-12-30 22:01:21 +00:00
|
|
|
acme.UserAgent = "lego/" + app.Version
|
|
|
|
|
2016-05-16 17:01:51 +00:00
|
|
|
defaultPath := ""
|
2015-06-12 21:34:49 +00:00
|
|
|
cwd, err := os.Getwd()
|
2016-05-16 17:01:51 +00:00
|
|
|
if err == nil {
|
|
|
|
defaultPath = path.Join(cwd, ".lego")
|
|
|
|
}
|
|
|
|
|
|
|
|
app.Before = func(c *cli.Context) error {
|
|
|
|
if c.GlobalString("path") == "" {
|
|
|
|
logger().Fatal("Could not determine current working directory. Please pass --path.")
|
|
|
|
}
|
|
|
|
return nil
|
2015-06-12 21:34:49 +00:00
|
|
|
}
|
|
|
|
|
2015-06-08 00:36:07 +00:00
|
|
|
app.Commands = []cli.Command{
|
|
|
|
{
|
|
|
|
Name: "run",
|
2015-09-27 12:50:45 +00:00
|
|
|
Usage: "Register an account, then create and install a certificate",
|
2015-06-08 00:36:07 +00:00
|
|
|
Action: run,
|
2016-02-26 01:57:16 +00:00
|
|
|
Flags: []cli.Flag{
|
|
|
|
cli.BoolFlag{
|
2016-02-27 09:46:13 +00:00
|
|
|
Name: "no-bundle",
|
2016-02-26 01:57:16 +00:00
|
|
|
Usage: "Do not create a certificate bundle by adding the issuers certificate to the new certificate.",
|
|
|
|
},
|
|
|
|
},
|
2015-06-08 00:36:07 +00:00
|
|
|
},
|
|
|
|
{
|
2015-09-27 12:50:45 +00:00
|
|
|
Name: "revoke",
|
|
|
|
Usage: "Revoke a certificate",
|
|
|
|
Action: revoke,
|
2015-06-08 00:36:07 +00:00
|
|
|
},
|
2015-10-18 22:42:04 +00:00
|
|
|
{
|
|
|
|
Name: "renew",
|
|
|
|
Usage: "Renew a certificate",
|
|
|
|
Action: renew,
|
2015-12-06 21:35:52 +00:00
|
|
|
Flags: []cli.Flag{
|
|
|
|
cli.IntFlag{
|
2015-12-24 08:57:09 +00:00
|
|
|
Name: "days",
|
2015-12-06 21:35:52 +00:00
|
|
|
Value: 0,
|
|
|
|
Usage: "The number of days left on a certificate to renew it.",
|
|
|
|
},
|
2016-01-08 09:14:41 +00:00
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "reuse-key",
|
|
|
|
Usage: "Used to indicate you want to reuse your current private key for the new certificate.",
|
|
|
|
},
|
2016-02-26 01:57:16 +00:00
|
|
|
cli.BoolFlag{
|
2016-02-27 09:46:13 +00:00
|
|
|
Name: "no-bundle",
|
2016-02-26 01:57:16 +00:00
|
|
|
Usage: "Do not create a certificate bundle by adding the issuers certificate to the new certificate.",
|
|
|
|
},
|
2015-12-06 21:35:52 +00:00
|
|
|
},
|
2015-10-18 22:42:04 +00:00
|
|
|
},
|
2016-03-18 00:32:24 +00:00
|
|
|
{
|
|
|
|
Name: "dnshelp",
|
|
|
|
Usage: "Shows additional help for the --dns global option",
|
|
|
|
Action: dnshelp,
|
|
|
|
},
|
2015-06-08 00:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
app.Flags = []cli.Flag{
|
|
|
|
cli.StringSliceFlag{
|
|
|
|
Name: "domains, d",
|
|
|
|
Usage: "Add domains to the process",
|
|
|
|
},
|
2016-02-12 01:02:00 +00:00
|
|
|
cli.StringFlag{
|
|
|
|
Name: "csr, c",
|
|
|
|
Usage: "Certificate signing request filename, if an external CSR is to be used",
|
|
|
|
},
|
2015-06-08 00:36:07 +00:00
|
|
|
cli.StringFlag{
|
|
|
|
Name: "server, s",
|
2015-12-03 18:37:54 +00:00
|
|
|
Value: "https://acme-v01.api.letsencrypt.org/directory",
|
2015-06-08 00:36:07 +00:00
|
|
|
Usage: "CA hostname (and optionally :port). The server certificate must be trusted in order to avoid further modifications to the client.",
|
|
|
|
},
|
|
|
|
cli.StringFlag{
|
|
|
|
Name: "email, m",
|
|
|
|
Usage: "Email used for registration and recovery contact.",
|
|
|
|
},
|
2016-02-15 02:51:59 +00:00
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "accept-tos, a",
|
|
|
|
Usage: "By setting this flag to true you indicate that you accept the current Let's Encrypt terms of service.",
|
|
|
|
},
|
2016-01-27 01:01:39 +00:00
|
|
|
cli.StringFlag{
|
|
|
|
Name: "key-type, k",
|
|
|
|
Value: "rsa2048",
|
|
|
|
Usage: "Key type to use for private keys. Supported: rsa2048, rsa4096, rsa8192, ec256, ec384",
|
2015-06-08 00:36:07 +00:00
|
|
|
},
|
|
|
|
cli.StringFlag{
|
2015-06-12 21:34:49 +00:00
|
|
|
Name: "path",
|
|
|
|
Usage: "Directory to use for storing the data",
|
|
|
|
Value: defaultPath,
|
2015-06-08 00:36:07 +00:00
|
|
|
},
|
2015-12-05 21:01:08 +00:00
|
|
|
cli.StringSliceFlag{
|
2015-12-27 17:30:04 +00:00
|
|
|
Name: "exclude, x",
|
|
|
|
Usage: "Explicitly disallow solvers by name from being used. Solvers: \"http-01\", \"tls-sni-01\".",
|
|
|
|
},
|
2016-02-10 11:19:29 +00:00
|
|
|
cli.StringFlag{
|
|
|
|
Name: "webroot",
|
|
|
|
Usage: "Set the webroot folder to use for HTTP based challenges to write directly in a file in .well-known/acme-challenge",
|
|
|
|
},
|
2015-12-27 17:30:04 +00:00
|
|
|
cli.StringFlag{
|
2016-01-08 07:05:07 +00:00
|
|
|
Name: "http",
|
|
|
|
Usage: "Set the port and interface to use for HTTP based challenges to listen on. Supported: interface:port or :port",
|
2015-12-27 17:30:04 +00:00
|
|
|
},
|
|
|
|
cli.StringFlag{
|
2016-01-08 07:05:07 +00:00
|
|
|
Name: "tls",
|
|
|
|
Usage: "Set the port and interface to use for TLS based challenges to listen on. Supported: interface:port or :port",
|
2015-06-12 22:16:49 +00:00
|
|
|
},
|
2016-01-30 01:40:57 +00:00
|
|
|
cli.StringFlag{
|
2016-03-18 00:32:24 +00:00
|
|
|
Name: "dns",
|
|
|
|
Usage: "Solve a DNS challenge using the specified provider. Disables all other challenges. Run 'lego dnshelp' for help on usage.",
|
2016-01-30 01:40:57 +00:00
|
|
|
},
|
2016-05-19 16:52:44 +00:00
|
|
|
cli.IntFlag{
|
|
|
|
Name: "http-timeout",
|
|
|
|
Usage: "Set the HTTP timeout value to a specific value in seconds. The default is 10 seconds.",
|
|
|
|
},
|
2016-05-25 03:22:09 +00:00
|
|
|
cli.IntFlag{
|
|
|
|
Name: "dns-timeout",
|
|
|
|
Usage: "Set the DNS timeout value to a specific value in seconds. The default is 10 seconds.",
|
|
|
|
},
|
2016-06-19 05:55:15 +00:00
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "pem",
|
|
|
|
Usage: "Generate a .pem file by concatanating the .key and .crt files together.",
|
|
|
|
},
|
2015-06-08 00:36:07 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 15:11:26 +00:00
|
|
|
err = app.Run(os.Args)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2015-06-08 00:36:07 +00:00
|
|
|
}
|
2016-03-18 00:32:24 +00:00
|
|
|
|
2016-05-12 17:52:59 +00:00
|
|
|
func dnshelp(c *cli.Context) error {
|
2016-03-18 00:32:24 +00:00
|
|
|
fmt.Printf(
|
|
|
|
`Credentials for DNS providers must be passed through environment variables.
|
|
|
|
|
|
|
|
Here is an example bash command using the CloudFlare DNS provider:
|
|
|
|
|
|
|
|
$ CLOUDFLARE_EMAIL=foo@bar.com \
|
|
|
|
CLOUDFLARE_API_KEY=b9841238feb177a84330febba8a83208921177bffe733 \
|
|
|
|
lego --dns cloudflare --domains www.example.com --email me@bar.com run
|
|
|
|
|
|
|
|
`)
|
|
|
|
|
|
|
|
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
|
|
|
|
fmt.Fprintln(w, "Valid providers and their associated credential environment variables:")
|
|
|
|
fmt.Fprintln(w)
|
|
|
|
fmt.Fprintln(w, "\tcloudflare:\tCLOUDFLARE_EMAIL, CLOUDFLARE_API_KEY")
|
|
|
|
fmt.Fprintln(w, "\tdigitalocean:\tDO_AUTH_TOKEN")
|
|
|
|
fmt.Fprintln(w, "\tdnsimple:\tDNSIMPLE_EMAIL, DNSIMPLE_API_KEY")
|
|
|
|
fmt.Fprintln(w, "\tgandi:\tGANDI_API_KEY")
|
2016-03-18 15:22:33 +00:00
|
|
|
fmt.Fprintln(w, "\tgcloud:\tGCE_PROJECT")
|
2016-03-18 00:32:24 +00:00
|
|
|
fmt.Fprintln(w, "\tmanual:\tnone")
|
|
|
|
fmt.Fprintln(w, "\tnamecheap:\tNAMECHEAP_API_USER, NAMECHEAP_API_KEY")
|
|
|
|
fmt.Fprintln(w, "\trfc2136:\tRFC2136_TSIG_KEY, RFC2136_TSIG_SECRET,\n\t\tRFC2136_TSIG_ALGORITHM, RFC2136_NAMESERVER")
|
|
|
|
fmt.Fprintln(w, "\troute53:\tAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION")
|
2016-03-18 02:30:21 +00:00
|
|
|
fmt.Fprintln(w, "\tdyn:\tDYN_CUSTOMER_NAME, DYN_USER_NAME, DYN_PASSWORD")
|
2016-03-20 23:23:37 +00:00
|
|
|
fmt.Fprintln(w, "\tvultr:\tVULTR_API_KEY")
|
2016-03-18 00:32:24 +00:00
|
|
|
w.Flush()
|
|
|
|
|
|
|
|
fmt.Println(`
|
|
|
|
For a more detailed explanation of a DNS provider's credential variables,
|
|
|
|
please consult their online documentation.`)
|
2016-05-12 17:52:59 +00:00
|
|
|
|
|
|
|
return nil
|
2016-03-18 00:32:24 +00:00
|
|
|
}
|