internal/test.go accepts fixed clock and Shares

generaleLocallySignedCertificate

Signed-off-by: JoshVanL <vleeuwenjoshua@gmail.com>
This commit is contained in:
JoshVanL 2020-04-27 16:29:58 +01:00
parent 7d1d94fedb
commit c115e6c2bf
No known key found for this signature in database
GPG Key ID: E7A7196576A219DA
6 changed files with 75 additions and 61 deletions

View File

@ -12,7 +12,6 @@ go_library(
"//pkg/api/util:go_default_library",
"//pkg/apis/certmanager/v1alpha2:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//pkg/controller:go_default_library",
"//pkg/util/pki:go_default_library",
"@com_github_pavel_v_chernykh_keystore_go//:go_default_library",
"@com_sslmate_software_src_go_pkcs12//:go_default_library",
@ -45,6 +44,7 @@ go_test(
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
"@io_k8s_apimachinery//pkg/runtime:go_default_library",
"@io_k8s_client_go//testing:go_default_library",
"@io_k8s_utils//clock/testing:go_default_library",
],
)

View File

@ -31,7 +31,6 @@ import (
apiutil "github.com/jetstack/cert-manager/pkg/api/util"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
controllerpkg "github.com/jetstack/cert-manager/pkg/controller"
utilpki "github.com/jetstack/cert-manager/pkg/util/pki"
)
@ -58,12 +57,12 @@ type SecretData struct {
func New(
kubeClient kubernetes.Interface,
secretLister corelisters.SecretLister,
CertificateificateControllerOptions controllerpkg.CertificateOptions,
enableSecretOwnerReferences bool,
) *SecretsManager {
return &SecretsManager{
kubeClient: kubeClient,
secretLister: secretLister,
enableSecretOwnerReferences: CertificateificateControllerOptions.EnableOwnerRef,
enableSecretOwnerReferences: enableSecretOwnerReferences,
}
}
@ -131,7 +130,7 @@ func (s *SecretsManager) setValues(crt *cmapi.Certificate, secret *corev1.Secret
secret.Data = make(map[string][]byte)
}
// Only write a new PKCS12/JKS file if any of the private key/Certificateificate/CA
// Only write a new PKCS12/JKS file if any of the private key/Certificate/CA
// data has actually changed.
if data.PrivateKey != nil && data.Certificate != nil &&
(!bytes.Equal(secret.Data[corev1.TLSPrivateKeyKey], data.PrivateKey) ||
@ -212,7 +211,7 @@ func (s *SecretsManager) setValues(crt *cmapi.Certificate, secret *corev1.Secret
secret.Annotations[cmapi.DeprecatedIssuerKindAnnotationKey] = apiutil.IssuerKind(crt.Spec.IssuerRef)
}
// if the Certificateificate data is empty, clear the subject related annotations
// if the Certificate data is empty, clear the subject related annotations
if len(data.Certificate) == 0 {
delete(secret.Annotations, cmapi.CommonNameAnnotationKey)
delete(secret.Annotations, cmapi.AltNamesAnnotationKey)

View File

@ -26,6 +26,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
coretesting "k8s.io/client-go/testing"
fakeclock "k8s.io/utils/clock/testing"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
@ -36,6 +37,11 @@ import (
"github.com/jetstack/cert-manager/test/unit/gen"
)
var (
fixedClockStart = time.Now()
fixedClock = fakeclock.NewFakeClock(fixedClockStart)
)
func TestSecretsManager(t *testing.T) {
type testT struct {
builder *testpkg.Builder
@ -55,7 +61,7 @@ func TestSecretsManager(t *testing.T) {
)
exampleBundle := internaltest.MustCreateCryptoBundle(t, gen.CertificateFrom(baseCert,
gen.SetCertificateDNSNames("example.com"),
))
), fixedClock)
tests := map[string]testT{
"if secret does not exists and unable to decode certificate, then error": {
@ -271,7 +277,8 @@ func TestSecretsManager(t *testing.T) {
for name, test := range tests {
t.Run(name, func(t *testing.T) {
test.builder.Clock = internaltest.FixedClock
fixedClock.SetTime(fixedClockStart)
test.builder.Clock = fixedClock
test.builder.T = t
test.builder.Init()
defer test.builder.Stop()
@ -282,7 +289,7 @@ func TestSecretsManager(t *testing.T) {
testManager := New(
kubeClient,
secretsLister,
test.certificateOptions,
test.certificateOptions.EnableOwnerRef,
)
test.builder.Start()

View File

@ -9,6 +9,7 @@ go_library(
"//pkg/api/util:go_default_library",
"//pkg/apis/certmanager/v1alpha2:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//pkg/controller/expcertificates:go_default_library",
"//pkg/util/pki:go_default_library",
"//test/unit/gen:go_default_library",
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",

View File

@ -21,7 +21,6 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
"math/big"
"testing"
"time"
@ -31,17 +30,13 @@ import (
apiutil "github.com/jetstack/cert-manager/pkg/api/util"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
certificates "github.com/jetstack/cert-manager/pkg/controller/expcertificates"
"github.com/jetstack/cert-manager/pkg/util/pki"
"github.com/jetstack/cert-manager/test/unit/gen"
)
const staticTemporarySerialNumber = 0x1234567890
var (
certificateGvk = cmapi.SchemeGroupVersion.WithKind("Certificate")
FixedClockStart = time.Now()
FixedClock = fakeclock.NewFakeClock(FixedClockStart)
)
type CryptoBundle struct {
@ -73,17 +68,19 @@ type CryptoBundle struct {
CertBytes []byte
LocalTemporaryCertificateBytes []byte
FixedClock *fakeclock.FakeClock
}
func MustCreateCryptoBundle(t *testing.T, crt *cmapi.Certificate) CryptoBundle {
c, err := createCryptoBundle(crt)
func MustCreateCryptoBundle(t *testing.T, crt *cmapi.Certificate, fixedClock *fakeclock.FakeClock) CryptoBundle {
c, err := createCryptoBundle(crt, fixedClock)
if err != nil {
t.Fatalf("error generating crypto bundle: %v", err)
}
return *c
}
func createCryptoBundle(crt *cmapi.Certificate) (*CryptoBundle, error) {
func createCryptoBundle(crt *cmapi.Certificate, fixedClock *fakeclock.FakeClock) (*CryptoBundle, error) {
reqName, err := apiutil.ComputeCertificateRequestName(crt)
if err != nil {
return nil, err
@ -177,7 +174,7 @@ func createCryptoBundle(crt *cmapi.Certificate) (*CryptoBundle, error) {
}),
)
tempCertBytes, err := generateLocallySignedTemporaryCertificate(crt, privateKeyBytes)
tempCertBytes, err := certificates.GenerateLocallySignedTemporaryCertificate(crt, privateKeyBytes)
if err != nil {
panic("failed to generate test fixture: " + err.Error())
}
@ -197,6 +194,7 @@ func createCryptoBundle(crt *cmapi.Certificate) (*CryptoBundle, error) {
Cert: cert,
CertBytes: certBytes,
LocalTemporaryCertificateBytes: tempCertBytes,
FixedClock: fixedClock,
}, nil
}
@ -253,7 +251,7 @@ func (c *CryptoBundle) generateCertificateExpiring1H(crt *cmapi.Certificate) []b
panic("failed to generate test fixture: " + err.Error())
}
nowTime := FixedClock.Now()
nowTime := c.FixedClock.Now()
duration := unsignedCert.NotAfter.Sub(unsignedCert.NotBefore)
unsignedCert.NotBefore = nowTime.Add(time.Hour).Add(-1 * duration)
unsignedCert.NotAfter = nowTime.Add(time.Hour)
@ -282,7 +280,7 @@ func (c *CryptoBundle) generateCertificateExpired(crt *cmapi.Certificate) []byte
panic("failed to generate test fixture: " + err.Error())
}
nowTime := FixedClock.Now()
nowTime := c.FixedClock.Now()
duration := unsignedCert.NotAfter.Sub(unsignedCert.NotBefore)
unsignedCert.NotBefore = nowTime.Add(-1 * time.Hour).Add(-1 * duration)
unsignedCert.NotAfter = nowTime.Add(-1 * time.Hour)
@ -317,43 +315,3 @@ func generateCSRImpl(crt *cmapi.Certificate, pk []byte) ([]byte, error) {
return csrPEM, nil
}
func generateLocallySignedTemporaryCertificate(crt *cmapi.Certificate, pkData []byte) ([]byte, error) {
// generate a throwaway self-signed root CA
caPk, err := pki.GenerateECPrivateKey(pki.ECCurve521)
if err != nil {
return nil, err
}
caCertTemplate, err := pki.GenerateTemplate(&cmapi.Certificate{
Spec: cmapi.CertificateSpec{
CommonName: "cert-manager.local",
IsCA: true,
},
})
if err != nil {
return nil, err
}
_, caCert, err := pki.SignCertificate(caCertTemplate, caCertTemplate, caPk.Public(), caPk)
if err != nil {
return nil, err
}
// sign a temporary certificate using the root CA
template, err := pki.GenerateTemplate(crt)
if err != nil {
return nil, err
}
template.SerialNumber = big.NewInt(staticTemporarySerialNumber)
signeeKey, err := pki.DecodePrivateKeyBytes(pkData)
if err != nil {
return nil, err
}
b, _, err := pki.SignCertificate(template, caCert, signeeKey.Public(), caPk)
if err != nil {
return nil, err
}
return b, nil
}

View File

@ -203,3 +203,52 @@ func SecretDataAltNamesMatchSpec(secret *corev1.Secret, spec cmapi.CertificateSp
return violations, nil
}
// staticTemporarySerialNumber is a fixed serial number we use for temporary certificates
const staticTemporarySerialNumber = "1234567890"
// GenerateLocallySignedTemporaryCertificate signs a temporary certificate for
// the given certificate resource using a one-use temporary CA that is then
// discarded afterwards.
// This is to mitigate a potential attack against x509 certificates that use a
// predictable serial number and weak MD5 hashing algorithms.
// In practice, this shouldn't really be a concern anyway.
func GenerateLocallySignedTemporaryCertificate(crt *cmapi.Certificate, pkData []byte) ([]byte, error) {
// generate a throwaway self-signed root CA
caPk, err := pki.GenerateECPrivateKey(pki.ECCurve521)
if err != nil {
return nil, err
}
caCertTemplate, err := pki.GenerateTemplate(&cmapi.Certificate{
Spec: cmapi.CertificateSpec{
CommonName: "cert-manager.local",
IsCA: true,
},
})
if err != nil {
return nil, err
}
_, caCert, err := pki.SignCertificate(caCertTemplate, caCertTemplate, caPk.Public(), caPk)
if err != nil {
return nil, err
}
// sign a temporary certificate using the root CA
template, err := pki.GenerateTemplate(crt)
if err != nil {
return nil, err
}
template.Subject.SerialNumber = staticTemporarySerialNumber
signeeKey, err := pki.DecodePrivateKeyBytes(pkData)
if err != nil {
return nil, err
}
b, _, err := pki.SignCertificate(template, caCert, signeeKey.Public(), caPk)
if err != nil {
return nil, err
}
return b, nil
}