cert-manager/pkg/apis/certmanager/validation/issuer_test.go
splashx 41111f7879
patch with rfc2136
Signed-off-by: splashx <splash@gmail.com>
2018-09-07 00:56:00 +02:00

544 lines
15 KiB
Go

/*
Copyright 2018 The Jetstack cert-manager contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package validation
import (
"reflect"
"testing"
"k8s.io/apimachinery/pkg/util/validation/field"
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
)
var (
validCloudDNSProvider = v1alpha1.ACMEIssuerDNS01ProviderCloudDNS{
ServiceAccount: validSecretKeyRef,
Project: "valid",
}
validSecretKeyRef = v1alpha1.SecretKeySelector{
LocalObjectReference: v1alpha1.LocalObjectReference{
Name: "valid",
},
Key: "validkey",
}
validCloudflareProvider = v1alpha1.ACMEIssuerDNS01ProviderCloudflare{
APIKey: validSecretKeyRef,
Email: "valid",
}
validACMEIssuer = v1alpha1.ACMEIssuer{
Email: "valid-email",
Server: "valid-server",
PrivateKey: validSecretKeyRef,
}
validVaultIssuer = v1alpha1.VaultIssuer{
Auth: v1alpha1.VaultAuth{
TokenSecretRef: validSecretKeyRef,
},
Server: "something",
Path: "a/b/c",
}
)
func TestValidateVaultIssuerConfig(t *testing.T) {
fldPath := field.NewPath("")
scenarios := map[string]struct {
spec *v1alpha1.VaultIssuer
errs []*field.Error
}{
"valid vault issuer": {
spec: &validVaultIssuer,
},
"vault issuer with missing fields": {
spec: &v1alpha1.VaultIssuer{},
errs: []*field.Error{
field.Required(fldPath.Child("server"), ""),
field.Required(fldPath.Child("path"), ""),
},
},
}
for n, s := range scenarios {
t.Run(n, func(t *testing.T) {
errs := ValidateVaultIssuerConfig(s.spec, fldPath)
if len(errs) != len(s.errs) {
t.Errorf("Expected %v but got %v", s.errs, errs)
return
}
for i, e := range errs {
expectedErr := s.errs[i]
if !reflect.DeepEqual(e, expectedErr) {
t.Errorf("Expected %v but got %v", expectedErr, e)
}
}
})
}
}
func TestValidateACMEIssuerConfig(t *testing.T) {
fldPath := field.NewPath("")
scenarios := map[string]struct {
spec *v1alpha1.ACMEIssuer
errs []*field.Error
}{
"valid acme issuer": {
spec: &validACMEIssuer,
},
"acme issuer with missing fields": {
spec: &v1alpha1.ACMEIssuer{},
errs: []*field.Error{
field.Required(fldPath.Child("email"), "email address is a required field"),
field.Required(fldPath.Child("privateKey", "name"), "private key secret name is a required field"),
field.Required(fldPath.Child("server"), "acme server URL is a required field"),
},
},
"acme issuer with invalid dns01 config": {
spec: &v1alpha1.ACMEIssuer{
Email: "valid-email",
Server: "valid-server",
PrivateKey: validSecretKeyRef,
DNS01: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "valid-name",
},
},
},
},
errs: []*field.Error{
field.Required(fldPath.Child("dns01", "providers").Index(0), "at least one provider must be configured"),
},
},
"acme issuer with valid dns01 config": {
spec: &v1alpha1.ACMEIssuer{
Email: "valid-email",
Server: "valid-server",
PrivateKey: validSecretKeyRef,
DNS01: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "valid-name",
CloudDNS: &validCloudDNSProvider,
},
},
},
},
},
"acme issuer with valid http01 config": {
spec: &v1alpha1.ACMEIssuer{
Email: "valid-email",
Server: "valid-server",
PrivateKey: validSecretKeyRef,
HTTP01: &v1alpha1.ACMEIssuerHTTP01Config{},
},
},
}
for n, s := range scenarios {
t.Run(n, func(t *testing.T) {
errs := ValidateACMEIssuerConfig(s.spec, fldPath)
if len(errs) != len(s.errs) {
t.Errorf("Expected %v but got %v", s.errs, errs)
return
}
for i, e := range errs {
expectedErr := s.errs[i]
if !reflect.DeepEqual(e, expectedErr) {
t.Errorf("Expected %v but got %v", expectedErr, e)
}
}
})
}
}
func TestValidateIssuerSpec(t *testing.T) {
fldPath := field.NewPath("")
scenarios := map[string]struct {
spec *v1alpha1.IssuerSpec
errs []*field.Error
}{
"valid ca issuer": {
spec: &v1alpha1.IssuerSpec{
IssuerConfig: v1alpha1.IssuerConfig{
CA: &v1alpha1.CAIssuer{
SecretName: "valid",
},
},
},
},
"ca issuer without secret name specified": {
spec: &v1alpha1.IssuerSpec{
IssuerConfig: v1alpha1.IssuerConfig{
CA: &v1alpha1.CAIssuer{},
},
},
errs: []*field.Error{field.Required(fldPath.Child("ca", "secretName"), "")},
},
"valid self signed issuer": {
spec: &v1alpha1.IssuerSpec{
IssuerConfig: v1alpha1.IssuerConfig{
SelfSigned: &v1alpha1.SelfSignedIssuer{},
},
},
},
"valid acme issuer": {
spec: &v1alpha1.IssuerSpec{
IssuerConfig: v1alpha1.IssuerConfig{
ACME: &validACMEIssuer,
},
},
},
"valid vault issuer": {
spec: &v1alpha1.IssuerSpec{
IssuerConfig: v1alpha1.IssuerConfig{
Vault: &validVaultIssuer,
},
},
},
"missing issuer config": {
spec: &v1alpha1.IssuerSpec{
IssuerConfig: v1alpha1.IssuerConfig{},
},
errs: []*field.Error{
field.Required(fldPath, "at least one issuer must be configured"),
},
},
"multiple issuers configured": {
spec: &v1alpha1.IssuerSpec{
IssuerConfig: v1alpha1.IssuerConfig{
SelfSigned: &v1alpha1.SelfSignedIssuer{},
CA: &v1alpha1.CAIssuer{
SecretName: "valid",
},
},
},
errs: []*field.Error{
field.Forbidden(fldPath.Child("selfSigned"), "may not specify more than one issuer type"),
},
},
}
for n, s := range scenarios {
t.Run(n, func(t *testing.T) {
errs := ValidateIssuerSpec(s.spec, fldPath)
if len(errs) != len(s.errs) {
t.Errorf("Expected %v but got %v", s.errs, errs)
return
}
for i, e := range errs {
expectedErr := s.errs[i]
if !reflect.DeepEqual(e, expectedErr) {
t.Errorf("Expected %v but got %v", expectedErr, e)
}
}
})
}
}
func TestValidateACMEIssuerDNS01Config(t *testing.T) {
fldPath := field.NewPath("")
providersPath := fldPath.Child("providers")
scenarios := map[string]struct {
cfg *v1alpha1.ACMEIssuerDNS01Config
errs []*field.Error
}{
"missing name": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
CloudDNS: &validCloudDNSProvider,
},
},
},
errs: []*field.Error{field.Required(providersPath.Index(0).Child("name"), "name must be specified")},
},
"missing clouddns project": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "a name",
CloudDNS: &v1alpha1.ACMEIssuerDNS01ProviderCloudDNS{
ServiceAccount: validSecretKeyRef,
},
},
},
},
errs: []*field.Error{
field.Required(providersPath.Index(0).Child("clouddns", "project"), ""),
},
},
"missing clouddns service account": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "a name",
CloudDNS: &v1alpha1.ACMEIssuerDNS01ProviderCloudDNS{
Project: "valid",
},
},
},
},
errs: []*field.Error{
field.Required(providersPath.Index(0).Child("clouddns", "serviceAccountSecretRef", "name"), "secret name is required"),
field.Required(providersPath.Index(0).Child("clouddns", "serviceAccountSecretRef", "key"), "secret key is required"),
},
},
"missing cloudflare token": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "a name",
Cloudflare: &v1alpha1.ACMEIssuerDNS01ProviderCloudflare{
Email: "valid",
},
},
},
},
errs: []*field.Error{
field.Required(providersPath.Index(0).Child("cloudflare", "apiKeySecretRef", "name"), "secret name is required"),
field.Required(providersPath.Index(0).Child("cloudflare", "apiKeySecretRef", "key"), "secret key is required"),
},
},
"missing cloudflare email": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "a name",
Cloudflare: &v1alpha1.ACMEIssuerDNS01ProviderCloudflare{
APIKey: validSecretKeyRef,
},
},
},
},
errs: []*field.Error{
field.Required(providersPath.Index(0).Child("cloudflare", "email"), ""),
},
},
"missing route53 region": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "a name",
Route53: &v1alpha1.ACMEIssuerDNS01ProviderRoute53{},
},
},
},
errs: []*field.Error{
field.Required(providersPath.Index(0).Child("route53", "region"), ""),
},
},
"missing provider config": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "a name",
},
},
},
errs: []*field.Error{
field.Required(providersPath.Index(0), "at least one provider must be configured"),
},
},
"missing azuredns config": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "a name",
AzureDNS: &v1alpha1.ACMEIssuerDNS01ProviderAzureDNS{},
},
},
},
errs: []*field.Error{
field.Required(providersPath.Index(0).Child("azuredns", "clientSecretSecretRef", "name"), "secret name is required"),
field.Required(providersPath.Index(0).Child("azuredns", "clientSecretSecretRef", "key"), "secret key is required"),
field.Required(providersPath.Index(0).Child("azuredns", "clientID"), ""),
field.Required(providersPath.Index(0).Child("azuredns", "subscriptionID"), ""),
field.Required(providersPath.Index(0).Child("azuredns", "tenantID"), ""),
field.Required(providersPath.Index(0).Child("azuredns", "resourceGroupName"), ""),
},
},
"missing akamai config": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "a name",
Akamai: &v1alpha1.ACMEIssuerDNS01ProviderAkamai{},
},
},
},
errs: []*field.Error{
field.Required(providersPath.Index(0).Child("akamai", "accessToken", "name"), "secret name is required"),
field.Required(providersPath.Index(0).Child("akamai", "accessToken", "key"), "secret key is required"),
field.Required(providersPath.Index(0).Child("akamai", "clientSecret", "name"), "secret name is required"),
field.Required(providersPath.Index(0).Child("akamai", "clientSecret", "key"), "secret key is required"),
field.Required(providersPath.Index(0).Child("akamai", "clientToken", "name"), "secret name is required"),
field.Required(providersPath.Index(0).Child("akamai", "clientToken", "key"), "secret key is required"),
field.Required(providersPath.Index(0).Child("akamai", "serviceConsumerDomain"), ""),
},
},
"valid akamai config": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "a name",
Akamai: &v1alpha1.ACMEIssuerDNS01ProviderAkamai{
AccessToken: validSecretKeyRef,
ClientSecret: validSecretKeyRef,
ClientToken: validSecretKeyRef,
ServiceConsumerDomain: "abc",
},
},
},
},
errs: []*field.Error{},
},
"valid rfc2136 config": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "a name",
RFC2136: &v1alpha1.ACMEIssuerDNS01ProviderRFC2136{
Nameserver: "127.0.0.1",
},
},
},
},
errs: []*field.Error{},
},
"missing rfc2136 required field": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "a name",
RFC2136: &v1alpha1.ACMEIssuerDNS01ProviderRFC2136{},
},
},
},
errs: []*field.Error{
field.Required(providersPath.Index(0).Child("rfc2136", "nameserver"), ""),
},
},
"rfc2136 provider using non-supported algorithm": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "a name",
RFC2136: &v1alpha1.ACMEIssuerDNS01ProviderRFC2136{
Nameserver: "127.0.0.1",
TSIGAlgorithm: "HAMMOCK",
},
},
},
},
errs: []*field.Error{
field.Forbidden(providersPath.Index(0).Child("rfc2136", "tsigSecretSecretRef"), ""),
},
},
"multiple providers configured": {
cfg: &v1alpha1.ACMEIssuerDNS01Config{
Providers: []v1alpha1.ACMEIssuerDNS01Provider{
{
Name: "a name",
CloudDNS: &validCloudDNSProvider,
Cloudflare: &validCloudflareProvider,
},
},
},
errs: []*field.Error{
field.Forbidden(providersPath.Index(0).Child("cloudflare"), "may not specify more than one provider type"),
},
},
}
for n, s := range scenarios {
t.Run(n, func(t *testing.T) {
errs := ValidateACMEIssuerDNS01Config(s.cfg, fldPath)
if len(errs) != len(s.errs) {
t.Errorf("Expected %v but got %v", s.errs, errs)
return
}
for i, e := range errs {
expectedErr := s.errs[i]
if !reflect.DeepEqual(e, expectedErr) {
t.Errorf("Expected %v but got %v", expectedErr, e)
}
}
})
}
}
func TestValidateSecretKeySelector(t *testing.T) {
validName := v1alpha1.LocalObjectReference{"name"}
validKey := "key"
// invalidName := v1alpha1.LocalObjectReference{"-name-"}
// invalidKey := "-key-"
fldPath := field.NewPath("")
scenarios := map[string]struct {
isExpectedFailure bool
selector *v1alpha1.SecretKeySelector
errs []*field.Error
}{
"valid selector": {
selector: &v1alpha1.SecretKeySelector{
LocalObjectReference: validName,
Key: validKey,
},
},
// "invalid name": {
// isExpectedFailure: true,
// selector: &v1alpha1.SecretKeySelector{
// LocalObjectReference: invalidName,
// Key: validKey,
// },
// },
// "invalid key": {
// isExpectedFailure: true,
// selector: &v1alpha1.SecretKeySelector{
// LocalObjectReference: validName,
// Key: invalidKey,
// },
// },
"missing name": {
selector: &v1alpha1.SecretKeySelector{
Key: validKey,
},
errs: []*field.Error{
field.Required(fldPath.Child("name"), "secret name is required"),
},
},
"missing key": {
selector: &v1alpha1.SecretKeySelector{
LocalObjectReference: validName,
},
errs: []*field.Error{
field.Required(fldPath.Child("key"), "secret key is required"),
},
},
}
for n, s := range scenarios {
t.Run(n, func(t *testing.T) {
errs := ValidateSecretKeySelector(s.selector, fldPath)
if len(errs) != len(s.errs) {
t.Errorf("Expected %v but got %v", s.errs, errs)
return
}
for i, e := range errs {
expectedErr := s.errs[i]
if !reflect.DeepEqual(e, expectedErr) {
t.Errorf("Expected %v but got %v", expectedErr, e)
}
}
})
}
}