Merge pull request #2170 from matevzmihalic/cloudflare-apitoken

Add API token authentication option to Cloudflare issuer
This commit is contained in:
jetstack-bot
2019-11-27 13:22:21 +00:00
committed by GitHub
17 changed files with 340 additions and 52 deletions
@@ -240,7 +240,6 @@ spec:
containing the DNS configuration for Cloudflare
type: object
required:
- apiKeySecretRef
- email
properties:
apiKeySecretRef:
@@ -256,6 +255,19 @@ spec:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
apiTokenSecretRef:
type: object
required:
- name
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
email:
type: string
cnameStrategy:
@@ -245,7 +245,6 @@ spec:
containing the DNS configuration for Cloudflare
type: object
required:
- apiKeySecretRef
- email
properties:
apiKeySecretRef:
@@ -263,6 +262,21 @@ spec:
TODO: Add other useful fields. apiVersion, kind,
uid?'
type: string
apiTokenSecretRef:
type: object
required:
- name
properties:
key:
description: The key of the secret to select from.
Must be a valid secret key.
type: string
name:
description: 'Name of the referent. More info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind,
uid?'
type: string
email:
type: string
cnameStrategy:
+15 -1
View File
@@ -245,7 +245,6 @@ spec:
containing the DNS configuration for Cloudflare
type: object
required:
- apiKeySecretRef
- email
properties:
apiKeySecretRef:
@@ -263,6 +262,21 @@ spec:
TODO: Add other useful fields. apiVersion, kind,
uid?'
type: string
apiTokenSecretRef:
type: object
required:
- name
properties:
key:
description: The key of the secret to select from.
Must be a valid secret key.
type: string
name:
description: 'Name of the referent. More info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind,
uid?'
type: string
email:
type: string
cnameStrategy:
+43 -3
View File
@@ -675,7 +675,6 @@ spec:
containing the DNS configuration for Cloudflare
type: object
required:
- apiKeySecretRef
- email
properties:
apiKeySecretRef:
@@ -691,6 +690,19 @@ spec:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
apiTokenSecretRef:
type: object
required:
- name
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
email:
type: string
cnameStrategy:
@@ -2060,7 +2072,6 @@ spec:
containing the DNS configuration for Cloudflare
type: object
required:
- apiKeySecretRef
- email
properties:
apiKeySecretRef:
@@ -2078,6 +2089,21 @@ spec:
TODO: Add other useful fields. apiVersion, kind,
uid?'
type: string
apiTokenSecretRef:
type: object
required:
- name
properties:
key:
description: The key of the secret to select from.
Must be a valid secret key.
type: string
name:
description: 'Name of the referent. More info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind,
uid?'
type: string
email:
type: string
cnameStrategy:
@@ -3744,7 +3770,6 @@ spec:
containing the DNS configuration for Cloudflare
type: object
required:
- apiKeySecretRef
- email
properties:
apiKeySecretRef:
@@ -3762,6 +3787,21 @@ spec:
TODO: Add other useful fields. apiVersion, kind,
uid?'
type: string
apiTokenSecretRef:
type: object
required:
- name
properties:
key:
description: The key of the secret to select from.
Must be a valid secret key.
type: string
name:
description: 'Name of the referent. More info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind,
uid?'
type: string
email:
type: string
cnameStrategy:
+3 -2
View File
@@ -242,8 +242,9 @@ type ACMEIssuerDNS01ProviderCloudDNS struct {
// ACMEIssuerDNS01ProviderCloudflare is a structure containing the DNS
// configuration for Cloudflare
type ACMEIssuerDNS01ProviderCloudflare struct {
Email string `json:"email"`
APIKey cmmeta.SecretKeySelector `json:"apiKeySecretRef"`
Email string `json:"email"`
APIKey *cmmeta.SecretKeySelector `json:"apiKeySecretRef,omitempty"`
APIToken *cmmeta.SecretKeySelector `json:"apiTokenSecretRef,omitempty"`
}
// ACMEIssuerDNS01ProviderDigitalOcean is a structure containing the DNS
@@ -116,7 +116,7 @@ func (in *ACMEChallengeSolverDNS01) DeepCopyInto(out *ACMEChallengeSolverDNS01)
if in.Cloudflare != nil {
in, out := &in.Cloudflare, &out.Cloudflare
*out = new(ACMEIssuerDNS01ProviderCloudflare)
**out = **in
(*in).DeepCopyInto(*out)
}
if in.Route53 != nil {
in, out := &in.Route53, &out.Route53
@@ -392,7 +392,16 @@ func (in *ACMEIssuerDNS01ProviderCloudDNS) DeepCopy() *ACMEIssuerDNS01ProviderCl
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ACMEIssuerDNS01ProviderCloudflare) DeepCopyInto(out *ACMEIssuerDNS01ProviderCloudflare) {
*out = *in
out.APIKey = in.APIKey
if in.APIKey != nil {
in, out := &in.APIKey, &out.APIKey
*out = new(metav1.SecretKeySelector)
**out = **in
}
if in.APIToken != nil {
in, out := &in.APIToken, &out.APIToken
*out = new(metav1.SecretKeySelector)
**out = **in
}
return
}
+3 -2
View File
@@ -242,8 +242,9 @@ type ACMEIssuerDNS01ProviderCloudDNS struct {
// ACMEIssuerDNS01ProviderCloudflare is a structure containing the DNS
// configuration for Cloudflare
type ACMEIssuerDNS01ProviderCloudflare struct {
Email string `json:"email"`
APIKey cmmeta.SecretKeySelector `json:"apiKeySecretRef"`
Email string `json:"email"`
APIKey *cmmeta.SecretKeySelector `json:"apiKeySecretRef,omitempty"`
APIToken *cmmeta.SecretKeySelector `json:"apiTokenSecretRef,omitempty"`
}
// ACMEIssuerDNS01ProviderDigitalOcean is a structure containing the DNS
@@ -736,10 +736,8 @@ func Convert_acme_ACMEIssuerDNS01ProviderCloudDNS_To_v1alpha2_ACMEIssuerDNS01Pro
func autoConvert_v1alpha2_ACMEIssuerDNS01ProviderCloudflare_To_acme_ACMEIssuerDNS01ProviderCloudflare(in *v1alpha2.ACMEIssuerDNS01ProviderCloudflare, out *acme.ACMEIssuerDNS01ProviderCloudflare, s conversion.Scope) error {
out.Email = in.Email
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&in.APIKey, &out.APIKey, 0); err != nil {
return err
}
out.APIKey = (*meta.SecretKeySelector)(unsafe.Pointer(in.APIKey))
out.APIToken = (*meta.SecretKeySelector)(unsafe.Pointer(in.APIToken))
return nil
}
@@ -750,10 +748,8 @@ func Convert_v1alpha2_ACMEIssuerDNS01ProviderCloudflare_To_acme_ACMEIssuerDNS01P
func autoConvert_acme_ACMEIssuerDNS01ProviderCloudflare_To_v1alpha2_ACMEIssuerDNS01ProviderCloudflare(in *acme.ACMEIssuerDNS01ProviderCloudflare, out *v1alpha2.ACMEIssuerDNS01ProviderCloudflare, s conversion.Scope) error {
out.Email = in.Email
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&in.APIKey, &out.APIKey, 0); err != nil {
return err
}
out.APIKey = (*metav1.SecretKeySelector)(unsafe.Pointer(in.APIKey))
out.APIToken = (*metav1.SecretKeySelector)(unsafe.Pointer(in.APIToken))
return nil
}
@@ -116,7 +116,7 @@ func (in *ACMEChallengeSolverDNS01) DeepCopyInto(out *ACMEChallengeSolverDNS01)
if in.Cloudflare != nil {
in, out := &in.Cloudflare, &out.Cloudflare
*out = new(ACMEIssuerDNS01ProviderCloudflare)
**out = **in
(*in).DeepCopyInto(*out)
}
if in.Route53 != nil {
in, out := &in.Route53, &out.Route53
@@ -392,7 +392,16 @@ func (in *ACMEIssuerDNS01ProviderCloudDNS) DeepCopy() *ACMEIssuerDNS01ProviderCl
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ACMEIssuerDNS01ProviderCloudflare) DeepCopyInto(out *ACMEIssuerDNS01ProviderCloudflare) {
*out = *in
out.APIKey = in.APIKey
if in.APIKey != nil {
in, out := &in.APIKey, &out.APIKey
*out = new(meta.SecretKeySelector)
**out = **in
}
if in.APIToken != nil {
in, out := &in.APIToken, &out.APIToken
*out = new(meta.SecretKeySelector)
**out = **in
}
return
}
@@ -280,7 +280,18 @@ func ValidateACMEChallengeSolverDNS01(p *cmacme.ACMEChallengeSolverDNS01, fldPat
el = append(el, field.Forbidden(fldPath.Child("cloudflare"), "may not specify more than one provider type"))
} else {
numProviders++
el = append(el, ValidateSecretKeySelector(&p.Cloudflare.APIKey, fldPath.Child("cloudflare", "apiKeySecretRef"))...)
if p.Cloudflare.APIKey != nil {
el = append(el, ValidateSecretKeySelector(p.Cloudflare.APIKey, fldPath.Child("cloudflare", "apiKeySecretRef"))...)
}
if p.Cloudflare.APIToken != nil {
el = append(el, ValidateSecretKeySelector(p.Cloudflare.APIToken, fldPath.Child("cloudflare", "apiTokenSecretRef"))...)
}
if p.Cloudflare.APIKey != nil && p.Cloudflare.APIToken != nil {
el = append(el, field.Forbidden(fldPath.Child("cloudflare"), "apiKeySecretRef and apiTokenSecretRef cannot both be specified"))
}
if p.Cloudflare.APIKey == nil && p.Cloudflare.APIToken == nil {
el = append(el, field.Required(fldPath.Child("cloudflare"), "apiKeySecretRef or apiTokenSecretRef is required"))
}
if len(p.Cloudflare.Email) == 0 {
el = append(el, field.Required(fldPath.Child("cloudflare", "email"), ""))
}
@@ -40,7 +40,7 @@ var (
Key: "validkey",
}
validCloudflareProvider = cmacme.ACMEIssuerDNS01ProviderCloudflare{
APIKey: validSecretKeyRef,
APIKey: &validSecretKeyRef,
Email: "valid",
}
validACMEIssuer = cmacme.ACMEIssuer{
@@ -494,10 +494,11 @@ func TestValidateACMEIssuerDNS01Config(t *testing.T) {
},
},
},
"missing cloudflare token": {
"missing cloudflare api key fields": {
cfg: &cmacme.ACMEChallengeSolverDNS01{
Cloudflare: &cmacme.ACMEIssuerDNS01ProviderCloudflare{
Email: "valid",
Email: "valid",
APIKey: &cmmeta.SecretKeySelector{},
},
},
errs: []*field.Error{
@@ -505,10 +506,44 @@ func TestValidateACMEIssuerDNS01Config(t *testing.T) {
field.Required(fldPath.Child("cloudflare", "apiKeySecretRef", "key"), "secret key is required"),
},
},
"missing cloudflare api token fields": {
cfg: &cmacme.ACMEChallengeSolverDNS01{
Cloudflare: &cmacme.ACMEIssuerDNS01ProviderCloudflare{
Email: "valid",
APIToken: &cmmeta.SecretKeySelector{},
},
},
errs: []*field.Error{
field.Required(fldPath.Child("cloudflare", "apiTokenSecretRef", "name"), "secret name is required"),
field.Required(fldPath.Child("cloudflare", "apiTokenSecretRef", "key"), "secret key is required"),
},
},
"missing cloudflare api token or key": {
cfg: &cmacme.ACMEChallengeSolverDNS01{
Cloudflare: &cmacme.ACMEIssuerDNS01ProviderCloudflare{
Email: "valid",
},
},
errs: []*field.Error{
field.Required(fldPath.Child("cloudflare"), "apiKeySecretRef or apiTokenSecretRef is required"),
},
},
"both cloudflare api token and key specified": {
cfg: &cmacme.ACMEChallengeSolverDNS01{
Cloudflare: &cmacme.ACMEIssuerDNS01ProviderCloudflare{
Email: "valid",
APIToken: &validSecretKeyRef,
APIKey: &validSecretKeyRef,
},
},
errs: []*field.Error{
field.Forbidden(fldPath.Child("cloudflare"), "apiKeySecretRef and apiTokenSecretRef cannot both be specified"),
},
},
"missing cloudflare email": {
cfg: &cmacme.ACMEChallengeSolverDNS01{
Cloudflare: &cmacme.ACMEIssuerDNS01ProviderCloudflare{
APIKey: validSecretKeyRef,
APIKey: &validSecretKeyRef,
},
},
errs: []*field.Error{
+17 -4
View File
@@ -33,6 +33,7 @@ type DNSProvider struct {
dns01Nameservers []string
authEmail string
authKey string
authToken string
}
// NewDNSProvider returns a DNSProvider instance configured for cloudflare.
@@ -41,15 +42,18 @@ type DNSProvider struct {
func NewDNSProvider(dns01Nameservers []string) (*DNSProvider, error) {
email := os.Getenv("CLOUDFLARE_EMAIL")
key := os.Getenv("CLOUDFLARE_API_KEY")
return NewDNSProviderCredentials(email, key, dns01Nameservers)
return NewDNSProviderCredentials(email, key, "", dns01Nameservers)
}
// NewDNSProviderCredentials uses the supplied credentials to return a
// DNSProvider instance configured for cloudflare.
func NewDNSProviderCredentials(email, key string, dns01Nameservers []string) (*DNSProvider, error) {
if email == "" || key == "" {
func NewDNSProviderCredentials(email, key, token string, dns01Nameservers []string) (*DNSProvider, error) {
if email == "" || (key == "" && token == "") {
return nil, fmt.Errorf("CloudFlare credentials missing")
}
if key != "" && token != "" {
return nil, fmt.Errorf("CloudFlare key and token are both present")
}
// cloudflare uses X-Auth-Key as a header for its
// authentication. However, if it's an invalid value, the go
// http library will "helpfully" print out the value to help with
@@ -60,9 +64,14 @@ func NewDNSProviderCredentials(email, key string, dns01Nameservers []string) (*D
return nil, fmt.Errorf("Cloudflare key invalid (does the key contain a newline?)")
}
if !validHeaderFieldValue(token) {
return nil, fmt.Errorf("Cloudflare token invalid (does the token contain a newline?)")
}
return &DNSProvider{
authEmail: email,
authKey: key,
authToken: token,
dns01Nameservers: dns01Nameservers,
}, nil
}
@@ -213,7 +222,11 @@ func (c *DNSProvider) makeRequest(method, uri string, body io.Reader) (json.RawM
}
req.Header.Set("X-Auth-Email", c.authEmail)
req.Header.Set("X-Auth-Key", c.authKey)
if c.authToken != "" {
req.Header.Set("Authorization", "Bearer "+c.authToken)
} else {
req.Header.Set("X-Auth-Key", c.authKey)
}
req.Header.Set("User-Agent", pkgutil.CertManagerUserAgent)
client := http.Client{
@@ -21,6 +21,7 @@ var (
cflareLiveTest bool
cflareEmail string
cflareAPIKey string
cflareAPIToken string
cflareDomain string
)
@@ -38,15 +39,31 @@ func restoreCloudFlareEnv() {
os.Setenv("CLOUDFLARE_API_KEY", cflareAPIKey)
}
func TestNewDNSProviderValid(t *testing.T) {
func TestNewDNSProviderValidAPIKey(t *testing.T) {
os.Setenv("CLOUDFLARE_EMAIL", "")
os.Setenv("CLOUDFLARE_API_KEY", "")
_, err := NewDNSProviderCredentials("123", "123", util.RecursiveNameservers)
_, err := NewDNSProviderCredentials("123", "123", "", util.RecursiveNameservers)
assert.NoError(t, err)
restoreCloudFlareEnv()
}
func TestNewDNSProviderValidEnv(t *testing.T) {
func TestNewDNSProviderValidAPIToken(t *testing.T) {
os.Setenv("CLOUDFLARE_EMAIL", "")
os.Setenv("CLOUDFLARE_API_KEY", "")
_, err := NewDNSProviderCredentials("123", "", "123", util.RecursiveNameservers)
assert.NoError(t, err)
restoreCloudFlareEnv()
}
func TestNewDNSProviderKeyAndTokenProvided(t *testing.T) {
os.Setenv("CLOUDFLARE_EMAIL", "")
os.Setenv("CLOUDFLARE_API_KEY", "")
_, err := NewDNSProviderCredentials("123", "123", "123", util.RecursiveNameservers)
assert.EqualError(t, err, "CloudFlare key and token are both present")
restoreCloudFlareEnv()
}
func TestNewDNSProviderValidApiKeyEnv(t *testing.T) {
os.Setenv("CLOUDFLARE_EMAIL", "test@example.com")
os.Setenv("CLOUDFLARE_API_KEY", "123")
_, err := NewDNSProvider(util.RecursiveNameservers)
@@ -67,7 +84,7 @@ func TestCloudFlarePresent(t *testing.T) {
t.Skip("skipping live test")
}
provider, err := NewDNSProviderCredentials(cflareEmail, cflareAPIKey, util.RecursiveNameservers)
provider, err := NewDNSProviderCredentials(cflareEmail, cflareAPIKey, cflareAPIToken, util.RecursiveNameservers)
assert.NoError(t, err)
err = provider.Present(cflareDomain, "_acme-challenge."+cflareDomain+".", "123d==")
@@ -81,7 +98,7 @@ func TestCloudFlareCleanUp(t *testing.T) {
time.Sleep(time.Second * 2)
provider, err := NewDNSProviderCredentials(cflareEmail, cflareAPIKey, util.RecursiveNameservers)
provider, err := NewDNSProviderCredentials(cflareEmail, cflareAPIKey, cflareAPIToken, util.RecursiveNameservers)
assert.NoError(t, err)
err = provider.CleanUp(cflareDomain, "_acme-challenge."+cflareDomain+".", "123d==")
+29 -6
View File
@@ -62,7 +62,7 @@ type solver interface {
// constructors may be set.
type dnsProviderConstructors struct {
cloudDNS func(project string, serviceAccount []byte, dns01Nameservers []string, ambient bool) (*clouddns.DNSProvider, error)
cloudFlare func(email, apikey string, dns01Nameservers []string) (*cloudflare.DNSProvider, error)
cloudFlare func(email, apikey, apiToken string, dns01Nameservers []string) (*cloudflare.DNSProvider, error)
route53 func(accessKey, secretKey, hostedZoneID, region, role string, ambient bool, dns01Nameservers []string) (*route53.DNSProvider, error)
azureDNS func(environment, clientID, clientSecret, subscriptionID, tenantID, resourceGroupName, hostedZoneName string, dns01Nameservers []string) (*azuredns.DNSProvider, error)
acmeDNS func(host string, accountJson []byte, dns01Nameservers []string) (*acmedns.DNSProvider, error)
@@ -252,15 +252,38 @@ func (s *Solver) solverForChallenge(ctx context.Context, issuer v1alpha2.Generic
}
case providerConfig.Cloudflare != nil:
dbg.Info("preparing to create Cloudflare provider")
apiKeySecret, err := s.secretLister.Secrets(resourceNamespace).Get(providerConfig.Cloudflare.APIKey.Name)
if providerConfig.Cloudflare.APIKey != nil && providerConfig.Cloudflare.APIToken != nil {
return nil, nil, fmt.Errorf("API key and API token secret references are both present")
}
var saSecretName, saSecretKey string
if providerConfig.Cloudflare.APIKey != nil {
saSecretName = providerConfig.Cloudflare.APIKey.Name
saSecretKey = providerConfig.Cloudflare.APIKey.Key
} else {
saSecretName = providerConfig.Cloudflare.APIToken.Name
saSecretKey = providerConfig.Cloudflare.APIToken.Key
}
saSecret, err := s.secretLister.Secrets(resourceNamespace).Get(saSecretName)
if err != nil {
return nil, nil, fmt.Errorf("error getting cloudflare service account: %s", err)
return nil, nil, fmt.Errorf("error getting cloudflare secret: %s", err)
}
keyData, ok := saSecret.Data[saSecretKey]
if !ok {
return nil, nil, fmt.Errorf("specfied key %q not found in secret %s/%s", saSecretKey, saSecret.Namespace, saSecret.Name)
}
var apiKey, apiToken string
if providerConfig.Cloudflare.APIKey != nil {
apiKey = string(keyData)
} else {
apiToken = string(keyData)
}
email := providerConfig.Cloudflare.Email
apiKey := string(apiKeySecret.Data[providerConfig.Cloudflare.APIKey.Key])
impl, err = s.dnsProviderConstructors.cloudFlare(email, apiKey, s.DNS01Nameservers)
impl, err = s.dnsProviderConstructors.cloudFlare(email, apiKey, apiToken, s.DNS01Nameservers)
if err != nil {
return nil, nil, fmt.Errorf("error instantiating cloudflare challenge solver: %s", err)
}
+98 -5
View File
@@ -66,7 +66,7 @@ func TestSolverFor(t *testing.T) {
expectedSolverType reflect.Type
}
tests := map[string]testT{
"loads secret for cloudflare provider": {
"loads api key for cloudflare provider": {
solverFixture: &solverFixture{
Builder: &test.Builder{
KubeObjects: []runtime.Object{
@@ -82,7 +82,7 @@ func TestSolverFor(t *testing.T) {
DNS01: &cmacme.ACMEChallengeSolverDNS01{
Cloudflare: &cmacme.ACMEIssuerDNS01ProviderCloudflare{
Email: "test",
APIKey: cmmeta.SecretKeySelector{
APIKey: &cmmeta.SecretKeySelector{
LocalObjectReference: cmmeta.LocalObjectReference{
Name: "cloudflare-key",
},
@@ -97,6 +97,37 @@ func TestSolverFor(t *testing.T) {
domain: "example.com",
expectedSolverType: reflect.TypeOf(&cloudflare.DNSProvider{}),
},
"loads api token for cloudflare provider": {
solverFixture: &solverFixture{
Builder: &test.Builder{
KubeObjects: []runtime.Object{
newSecret("cloudflare-token", "default", map[string][]byte{
"api-token": []byte("a-cloudflare-api-token"),
}),
},
},
Issuer: newIssuer("test", "default"),
Challenge: &cmacme.Challenge{
Spec: cmacme.ChallengeSpec{
Solver: &cmacme.ACMEChallengeSolver{
DNS01: &cmacme.ACMEChallengeSolverDNS01{
Cloudflare: &cmacme.ACMEIssuerDNS01ProviderCloudflare{
Email: "test",
APIToken: &cmmeta.SecretKeySelector{
LocalObjectReference: cmmeta.LocalObjectReference{
Name: "cloudflare-token",
},
Key: "api-token",
},
},
},
},
},
},
},
domain: "example.com",
expectedSolverType: reflect.TypeOf(&cloudflare.DNSProvider{}),
},
"fails to load a cloudflare provider with a missing secret": {
solverFixture: &solverFixture{
Issuer: newIssuer("test", "default"),
@@ -107,7 +138,38 @@ func TestSolverFor(t *testing.T) {
DNS01: &cmacme.ACMEChallengeSolverDNS01{
Cloudflare: &cmacme.ACMEIssuerDNS01ProviderCloudflare{
Email: "test",
APIKey: cmmeta.SecretKeySelector{
APIToken: &cmmeta.SecretKeySelector{
LocalObjectReference: cmmeta.LocalObjectReference{
Name: "cloudflare-token",
},
Key: "api-token",
},
},
},
},
},
},
},
domain: "example.com",
expectErr: true,
},
"fails to load a cloudflare provider when key and token are provided": {
solverFixture: &solverFixture{
Issuer: newIssuer("test", "default"),
// don't include any secrets in the lister
Challenge: &cmacme.Challenge{
Spec: cmacme.ChallengeSpec{
Solver: &cmacme.ACMEChallengeSolver{
DNS01: &cmacme.ACMEChallengeSolverDNS01{
Cloudflare: &cmacme.ACMEIssuerDNS01ProviderCloudflare{
Email: "test",
APIToken: &cmmeta.SecretKeySelector{
LocalObjectReference: cmmeta.LocalObjectReference{
Name: "cloudflare-token",
},
Key: "api-token",
},
APIKey: &cmmeta.SecretKeySelector{
LocalObjectReference: cmmeta.LocalObjectReference{
Name: "cloudflare-key",
},
@@ -122,7 +184,7 @@ func TestSolverFor(t *testing.T) {
domain: "example.com",
expectErr: true,
},
"fails to load a cloudflare provider with an invalid secret": {
"fails to load a cloudflare provider with an invalid key secret": {
solverFixture: &solverFixture{
Builder: &test.Builder{
KubeObjects: []runtime.Object{
@@ -138,7 +200,7 @@ func TestSolverFor(t *testing.T) {
DNS01: &cmacme.ACMEChallengeSolverDNS01{
Cloudflare: &cmacme.ACMEIssuerDNS01ProviderCloudflare{
Email: "test",
APIKey: cmmeta.SecretKeySelector{
APIKey: &cmmeta.SecretKeySelector{
LocalObjectReference: cmmeta.LocalObjectReference{
Name: "cloudflare-key",
},
@@ -153,6 +215,37 @@ func TestSolverFor(t *testing.T) {
domain: "example.com",
expectErr: true,
},
"fails to load a cloudflare provider with an invalid token secret": {
solverFixture: &solverFixture{
Builder: &test.Builder{
KubeObjects: []runtime.Object{
newSecret("cloudflare-token", "default", map[string][]byte{
"api-key-oops": []byte("a-cloudflare-api-token"),
}),
},
},
Issuer: newIssuer("test", "default"),
Challenge: &cmacme.Challenge{
Spec: cmacme.ChallengeSpec{
Solver: &cmacme.ACMEChallengeSolver{
DNS01: &cmacme.ACMEChallengeSolverDNS01{
Cloudflare: &cmacme.ACMEIssuerDNS01ProviderCloudflare{
Email: "test",
APIToken: &cmmeta.SecretKeySelector{
LocalObjectReference: cmmeta.LocalObjectReference{
Name: "cloudflare-token",
},
Key: "api-token",
},
},
},
},
},
},
},
domain: "example.com",
expectErr: true,
},
"loads json for acmedns provider": {
solverFixture: &solverFixture{
Builder: &test.Builder{
+4 -4
View File
@@ -139,10 +139,10 @@ func newFakeDNSProviders() *fakeDNSProviders {
f.call("clouddns", project, serviceAccount, util.RecursiveNameservers, ambient)
return nil, nil
},
cloudFlare: func(email, apikey string, dns01Nameservers []string) (*cloudflare.DNSProvider, error) {
f.call("cloudflare", email, apikey, util.RecursiveNameservers)
if email == "" || apikey == "" {
return nil, errors.New("invalid email or apikey")
cloudFlare: func(email, apikey, apiToken string, dns01Nameservers []string) (*cloudflare.DNSProvider, error) {
f.call("cloudflare", email, apikey, apiToken, util.RecursiveNameservers)
if email == "" || (apikey == "" && apiToken == "") {
return nil, errors.New("invalid email or apikey or apitoken")
}
return nil, nil
},
@@ -86,7 +86,7 @@ func (b *Cloudflare) Provision() error {
b.details.ProviderConfig = cmacme.ACMEChallengeSolverDNS01{
Cloudflare: &cmacme.ACMEIssuerDNS01ProviderCloudflare{
Email: b.cf.Email,
APIKey: cmmeta.SecretKeySelector{
APIKey: &cmmeta.SecretKeySelector{
LocalObjectReference: cmmeta.LocalObjectReference{
Name: b.createdSecret.Name,
},