RFC: providers/dns: add Service Account authorization option to gcloud (#408)

* providers/dns: add Service Account authorization option to gcloud

* providers/dns: use os.LookupEnv() for local ENV var
This commit is contained in:
Dan Lüdtke 2017-07-17 21:40:57 +02:00 committed by xenolf
parent 192334c448
commit dd74b99f8d
4 changed files with 41 additions and 4 deletions

2
cli.go
View file

@ -209,7 +209,7 @@ Here is an example bash command using the CloudFlare DNS provider:
fmt.Fprintln(w, "\tdnsmadeeasy:\tDNSMADEEASY_API_KEY, DNSMADEEASY_API_SECRET")
fmt.Fprintln(w, "\texoscale:\tEXOSCALE_API_KEY, EXOSCALE_API_SECRET, EXOSCALE_ENDPOINT")
fmt.Fprintln(w, "\tgandi:\tGANDI_API_KEY")
fmt.Fprintln(w, "\tgcloud:\tGCE_PROJECT")
fmt.Fprintln(w, "\tgcloud:\tGCE_PROJECT, GCE_SERVICE_ACCOUNT_FILE")
fmt.Fprintln(w, "\tlinode:\tLINODE_API_KEY")
fmt.Fprintln(w, "\tmanual:\tnone")
fmt.Fprintln(w, "\tnamecheap:\tNAMECHEAP_API_USER, NAMECHEAP_API_KEY")

View file

@ -114,7 +114,7 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
}
if c.GlobalIsSet("dns") {
provider, err := dns.NewDNSChallengeProviderByName(c.GlobalString("dns"))
provider, err := dns.NewDNSChallengeProviderByName(c.GlobalString("dns"))
if err != nil {
logger().Fatal(err)
}

View file

@ -48,7 +48,7 @@ func NewDNSChallengeProviderByName(name string) (acme.ChallengeProvider, error)
case "dyn":
provider, err = dyn.NewDNSProvider()
case "exoscale":
provider, err = exoscale.NewDNSProvider()
provider, err = exoscale.NewDNSProvider()
case "gandi":
provider, err = gandi.NewDNSProvider()
case "gcloud":

View file

@ -4,12 +4,14 @@ package googlecloud
import (
"fmt"
"io/ioutil"
"os"
"time"
"github.com/xenolf/lego/acme"
"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/dns/v1"
@ -22,9 +24,14 @@ type DNSProvider struct {
}
// NewDNSProvider returns a DNSProvider instance configured for Google Cloud
// DNS. Credentials must be passed in the environment variable: GCE_PROJECT.
// DNS. Project name must be passed in the environment variable: GCE_PROJECT.
// A Service Account file can be passed in the environment variable:
// GCE_SERVICE_ACCOUNT_FILE
func NewDNSProvider() (*DNSProvider, error) {
project := os.Getenv("GCE_PROJECT")
if saFile, ok := os.LookupEnv("GCE_SERVICE_ACCOUNT_FILE"); ok {
return NewDNSProviderServiceAccount(project, saFile)
}
return NewDNSProviderCredentials(project)
}
@ -49,6 +56,36 @@ func NewDNSProviderCredentials(project string) (*DNSProvider, error) {
}, nil
}
// NewDNSProviderServiceAccount uses the supplied service account JSON file to
// return a DNSProvider instance configured for Google Cloud DNS.
func NewDNSProviderServiceAccount(project string, saFile string) (*DNSProvider, error) {
if project == "" {
return nil, fmt.Errorf("Google Cloud project name missing")
}
if saFile == "" {
return nil, fmt.Errorf("Google Cloud Service Account file missing")
}
dat, err := ioutil.ReadFile(saFile)
if err != nil {
return nil, fmt.Errorf("Unable to read Service Account file: %v", err)
}
conf, err := google.JWTConfigFromJSON(dat, dns.NdevClouddnsReadwriteScope)
if err != nil {
return nil, fmt.Errorf("Unable to acquire config: %v", err)
}
client := conf.Client(oauth2.NoContext)
svc, err := dns.New(client)
if err != nil {
return nil, fmt.Errorf("Unable to create Google Cloud DNS service: %v", err)
}
return &DNSProvider{
project: project,
client: svc,
}, nil
}
// Present creates a TXT record to fulfil the dns-01 challenge.
func (c *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value, ttl := acme.DNS01Record(domain, keyAuth)