Skip to content

Commit

Permalink
Introduce the HTTP01 challenge (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidknezic authored and janeczku committed Jan 27, 2017
1 parent fcf5803 commit 2777fcd
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 31 deletions.
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
FROM alpine:3.3
MAINTAINER <jan@rancher.com>

EXPOSE 80

RUN apk add --no-cache ca-certificates

ENV LETSENCRYPT_RELEASE v0.3.0
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
FROM alpine:3.3
MAINTAINER Jan Broer <jan@festplatte.eu.org>

EXPOSE 80

RUN apk add --no-cache ca-certificates

ADD build/rancher-letsencrypt-linux-amd64 /usr/bin/rancher-letsencrypt
Expand Down
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ A [Rancher](http://rancher.com/rancher/) service that obtains free SSL/TLS certi

#### Requirements
* Rancher Server >= v0.63.0
* Existing account with one of the supported DNS providers:
* If using a DNS-based challenge, existing account with one of the supported DNS providers:
* `AWS Route 53`
* `CloudFlare`
* `DigitalOcean`
* `DNSimple`
* `Dyn`
* `Vultr`
* `Ovh`
* If using the HTTP challenge, a proxy that routes `example.com/.well-known/acme-challenge` to `rancher-letsencrypt`.

### How to use

Expand Down Expand Up @@ -96,7 +97,22 @@ To finish, when you start this container add the following environment variable:
- `PROVIDER`: Ovh
- `OVH_APPLICATION_KEY`: your key generated in previous step
- `OVH_APPLICATION_SECRET`: your secret generated in previous step
- `OVH_CONSUMER_KEY`: your consumer key generated in previous step
- `OVH_CONSUMER_KEY`: your consumer key generated in previous step

#### HTTP

If you prefer not to use a DNS-based challenge
or your provider is not supported, you can use the HTTP challenge.

Simply set the following option:
- `PROVIDER`: HTTP

With this you'll have to make sure that HTTP
requests to `example.com/.well-known/acme-challenge` get redirected
to your `rancher-letsencrypt` instance. You can use a reverse proxy, like
the Rancher Load Balancer for that:

![Rancher Load Balancer LetsEncrypt Targets](https://cloud.githubusercontent.com/assets/198988/22224463/0d1eb4aa-e1bf-11e6-955c-5f0d085ce8cd.png)

### Building the image

Expand Down
2 changes: 1 addition & 1 deletion context.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (c *Context) InitContext() {
}

providerOpts := letsencrypt.ProviderOpts{
Provider: letsencrypt.DnsProvider(providerParam),
Provider: letsencrypt.Provider(providerParam),
CloudflareEmail: getEnvOption("CLOUDFLARE_EMAIL", false),
CloudflareKey: getEnvOption("CLOUDFLARE_KEY", false),
DoAccessToken: getEnvOption("DO_ACCESS_TOKEN", false),
Expand Down
14 changes: 9 additions & 5 deletions letsencrypt/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,21 @@ func NewClient(email string, kt KeyType, apiVer ApiVersion, provider ProviderOpt
logrus.Infof("Using locally stored Let's Encrypt account for %s", email)
}

prov, err := getProvider(provider)
prov, challenge, err := getProvider(provider)
if err != nil {
return nil, fmt.Errorf("Could not set DNS provider: %v", err)
return nil, fmt.Errorf("Could not get provider: %v", err)
}

err = client.SetChallengeProvider(lego.DNS01, prov)
err = client.SetChallengeProvider(challenge, prov)
if err != nil {
return nil, fmt.Errorf("Could not set DNS provider: %v", err)
return nil, fmt.Errorf("Could not set provider: %v", err)
}

client.ExcludeChallenges([]lego.Challenge{lego.HTTP01, lego.TLSSNI01})
if challenge == lego.DNS01 {
client.ExcludeChallenges([]lego.Challenge{lego.HTTP01, lego.TLSSNI01})
} else if challenge == lego.HTTP01 {
client.ExcludeChallenges([]lego.Challenge{lego.TLSSNI01, lego.DNS01})
}

return &Client{
client: client,
Expand Down
61 changes: 38 additions & 23 deletions letsencrypt/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
// ProviderOpts is used to configure the DNS provider
// used by the Let's Encrypt client for domain validation
type ProviderOpts struct {
Provider DnsProvider
Provider Provider

// CloudFlare credentials
CloudflareEmail string
Expand Down Expand Up @@ -48,37 +48,45 @@ type ProviderOpts struct {
OvhConsumerKey string
}

type DnsProvider string
type Provider string

const (
CLOUDFLARE = DnsProvider("CloudFlare")
DIGITALOCEAN = DnsProvider("DigitalOcean")
ROUTE53 = DnsProvider("Route53")
DNSIMPLE = DnsProvider("DNSimple")
DYN = DnsProvider("Dyn")
VULTR = DnsProvider("Vultr")
OVH = DnsProvider("Ovh")
CLOUDFLARE = Provider("CloudFlare")
DIGITALOCEAN = Provider("DigitalOcean")
ROUTE53 = Provider("Route53")
DNSIMPLE = Provider("DNSimple")
DYN = Provider("Dyn")
VULTR = Provider("Vultr")
OVH = Provider("Ovh")
HTTP = Provider("HTTP")
)

var dnsProviderFactory = map[DnsProvider]interface{}{
CLOUDFLARE: makeCloudflareProvider,
DIGITALOCEAN: makeDigitalOceanProvider,
ROUTE53: makeRoute53Provider,
DNSIMPLE: makeDNSimpleProvider,
DYN: makeDynProvider,
VULTR: makeVultrProvider,
OVH: makeOvhProvider,
type ProviderFactory struct {
factory interface{}
challenge lego.Challenge
}

func getProvider(opts ProviderOpts) (lego.ChallengeProvider, error) {
if f, ok := dnsProviderFactory[opts.Provider]; ok {
provider, err := f.(func(ProviderOpts) (lego.ChallengeProvider, error))(opts)
var providerFactory = map[Provider]ProviderFactory{
CLOUDFLARE: ProviderFactory{makeCloudflareProvider, lego.DNS01},
DIGITALOCEAN: ProviderFactory{makeDigitalOceanProvider, lego.DNS01},
ROUTE53: ProviderFactory{makeRoute53Provider, lego.DNS01},
DNSIMPLE: ProviderFactory{makeDNSimpleProvider, lego.DNS01},
DYN: ProviderFactory{makeDynProvider, lego.DNS01},
VULTR: ProviderFactory{makeVultrProvider, lego.DNS01},
OVH: ProviderFactory{makeOvhProvider, lego.DNS01},
HTTP: ProviderFactory{makeHTTPProvider, lego.HTTP01},
}

func getProvider(opts ProviderOpts) (lego.ChallengeProvider, lego.Challenge, error) {
if f, ok := providerFactory[opts.Provider]; ok {
provider, err := f.factory.(func(ProviderOpts) (lego.ChallengeProvider, error))(opts)
if err != nil {
return nil, err
return nil, f.challenge, err
}
return provider, nil
return provider, f.challenge, nil
}
return nil, fmt.Errorf("Unsupported DNS provider: %s", opts.Provider)
irrelevant := lego.DNS01
return nil, irrelevant, fmt.Errorf("Unsupported provider: %s", opts.Provider)
}

// returns a preconfigured CloudFlare lego.ChallengeProvider
Expand Down Expand Up @@ -198,3 +206,10 @@ func makeOvhProvider(opts ProviderOpts) (lego.ChallengeProvider, error) {
}
return provider, nil
}

// returns a preconfigured HTTP lego.ChallengeProvider
func makeHTTPProvider(opts ProviderOpts) (lego.ChallengeProvider, error) {
provider := lego.NewHTTPProviderServer("", "")

return provider, nil
}

0 comments on commit 2777fcd

Please sign in to comment.