Add private key Ingress annotations to set private key properties for Certificate

Signed-off-by: oGi4i <das.ogi4i@gmail.com>
This commit is contained in:
oGi4i 2022-06-28 17:45:08 +03:00
parent f5be6e4cc9
commit cb2cabb06f
No known key found for this signature in database
GPG Key ID: 3D37F19DAC700001
6 changed files with 686 additions and 21 deletions

View File

@ -59,6 +59,33 @@ const (
// Minimum value is 1.
// If unset all CertificateRequests will be kept.
RevisionHistoryLimitAnnotationKey = "cert-manager.io/revision-history-limit"
// Annotation key used to set the PrivateKeyAlgorithm for a Certificate.
// If PrivateKeyAlgorithm is specified and `size` is not provided,
// key size of 256 will be used for `ECDSA` key algorithm and
// key size of 2048 will be used for `RSA` key algorithm.
// key size is ignored when using the `Ed25519` key algorithm.
// If unset an algorithm `RSA` will be used.
PrivateKeyAlgorithmAnnotationKey = "cert-manager.io/private-key-algorithm"
// Annotation key used to set the PrivateKeyEncoding for a Certificate.
// If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1
// and PKCS#8, respectively.
// If unset an encoding `PKCS1` will be used.
PrivateKeyEncodingAnnotationKey = "cert-manager.io/private-key-encoding"
// Annotation key used to set the size of the private key for a Certificate.
// If PrivateKeyAlgorithm is set to `RSA`, valid values are `2048`, `4096` or `8192`,
// and will default to `2048` if not specified.
// If PrivateKeyAlgorithm is set to `ECDSA`, valid values are `256`, `384` or `521`,
// and will default to `256` if not specified.
// If PrivateKeyAlgorithm is set to `Ed25519`, Size is ignored.
// No other values are allowed.
PrivateKeySizeAnnotationKey = "cert-manager.io/private-key-size"
// Annotation key used to set the PrivateKeyRotationPolicy for a Certificate.
// If unset a policy `Never` will be used.
PrivateKeyRotationPolicyAnnotationKey = "cert-manager.io/private-key-rotation-policy"
)
const (

View File

@ -110,5 +110,84 @@ func translateAnnotations(crt *cmapi.Certificate, ingLikeAnnotations map[string]
crt.Spec.RevisionHistoryLimit = pointer.Int32(int32(limit))
}
if privateKeyAlgorithm, found := ingLikeAnnotations[cmapi.PrivateKeyAlgorithmAnnotationKey]; found {
algorithm := cmapi.PrivateKeyAlgorithm(privateKeyAlgorithm)
switch algorithm {
case cmapi.RSAKeyAlgorithm,
cmapi.ECDSAKeyAlgorithm,
cmapi.Ed25519KeyAlgorithm:
// ok
default:
return fmt.Errorf("%w %q: invalid private key algorithm %q", errInvalidIngressAnnotation, cmapi.PrivateKeyAlgorithmAnnotationKey, privateKeyAlgorithm)
}
if crt.Spec.PrivateKey == nil {
crt.Spec.PrivateKey = &cmapi.CertificatePrivateKey{Algorithm: algorithm}
} else {
crt.Spec.PrivateKey.Algorithm = algorithm
}
}
if privateKeyEncoding, found := ingLikeAnnotations[cmapi.PrivateKeyEncodingAnnotationKey]; found {
encoding := cmapi.PrivateKeyEncoding(privateKeyEncoding)
if encoding != cmapi.PKCS1 &&
encoding != cmapi.PKCS8 {
return fmt.Errorf("%w %q: invalid private key encoding %q", errInvalidIngressAnnotation, cmapi.PrivateKeyEncodingAnnotationKey, privateKeyEncoding)
}
if crt.Spec.PrivateKey == nil {
crt.Spec.PrivateKey = &cmapi.CertificatePrivateKey{Encoding: encoding}
} else {
crt.Spec.PrivateKey.Encoding = encoding
}
}
if privateKeySize, found := ingLikeAnnotations[cmapi.PrivateKeySizeAnnotationKey]; found {
size, err := strconv.Atoi(privateKeySize)
if err != nil {
return fmt.Errorf("%w %q: %v", errInvalidIngressAnnotation, cmapi.PrivateKeySizeAnnotationKey, err)
}
// default algorithm
algorithm := cmapi.RSAKeyAlgorithm
if crt.Spec.PrivateKey != nil && crt.Spec.PrivateKey.Algorithm != "" {
algorithm = crt.Spec.PrivateKey.Algorithm
}
switch algorithm {
case cmapi.RSAKeyAlgorithm:
if size < 2048 || size > 8192 {
return fmt.Errorf("%w %q: invalid private key size for RSA algorithm %q", errInvalidIngressAnnotation, cmapi.PrivateKeySizeAnnotationKey, privateKeySize)
}
case cmapi.ECDSAKeyAlgorithm:
switch size {
case 256, 384, 521:
// ok
default:
return fmt.Errorf("%w %q: invalid private key size for ECDSA algorithm %q", errInvalidIngressAnnotation, cmapi.PrivateKeySizeAnnotationKey, privateKeySize)
}
}
if crt.Spec.PrivateKey == nil {
crt.Spec.PrivateKey = &cmapi.CertificatePrivateKey{Size: size}
} else {
crt.Spec.PrivateKey.Size = size
}
}
if privateKeyRotationPolicy, found := ingLikeAnnotations[cmapi.PrivateKeyRotationPolicyAnnotationKey]; found {
rotationPolicy := cmapi.PrivateKeyRotationPolicy(privateKeyRotationPolicy)
if rotationPolicy != cmapi.RotationPolicyNever &&
rotationPolicy != cmapi.RotationPolicyAlways {
return fmt.Errorf("%w %q: invalid private key rotation policy %q", errInvalidIngressAnnotation, cmapi.PrivateKeyRotationPolicyAnnotationKey, privateKeyRotationPolicy)
}
if crt.Spec.PrivateKey == nil {
crt.Spec.PrivateKey = &cmapi.CertificatePrivateKey{RotationPolicy: rotationPolicy}
} else {
crt.Spec.PrivateKey.RotationPolicy = rotationPolicy
}
}
return nil
}

View File

@ -60,6 +60,73 @@ func Test_translateAnnotations(t *testing.T) {
a.Equal(pointer.Int32(7), crt.Spec.RevisionHistoryLimit)
},
},
"success rsa private key algorithm": {
crt: gen.Certificate("example-cert"),
annotations: map[string]string{
cmapi.CommonNameAnnotationKey: "www.example.com",
cmapi.DurationAnnotationKey: "168h", // 1 week
cmapi.RenewBeforeAnnotationKey: "24h",
cmapi.UsagesAnnotationKey: "server auth,signing",
cmapi.PrivateKeyAlgorithmAnnotationKey: "RSA",
cmapi.PrivateKeyEncodingAnnotationKey: "PKCS1",
cmapi.PrivateKeySizeAnnotationKey: "2048",
cmapi.PrivateKeyRotationPolicyAnnotationKey: "Always",
},
check: func(a *assert.Assertions, crt *cmapi.Certificate) {
a.Equal("www.example.com", crt.Spec.CommonName)
a.Equal(&metav1.Duration{Duration: time.Hour * 24 * 7}, crt.Spec.Duration)
a.Equal(&metav1.Duration{Duration: time.Hour * 24}, crt.Spec.RenewBefore)
a.Equal([]cmapi.KeyUsage{cmapi.UsageServerAuth, cmapi.UsageSigning}, crt.Spec.Usages)
a.Equal(cmapi.RSAKeyAlgorithm, crt.Spec.PrivateKey.Algorithm)
a.Equal(cmapi.PKCS1, crt.Spec.PrivateKey.Encoding)
a.Equal(2048, crt.Spec.PrivateKey.Size)
a.Equal(cmapi.RotationPolicyAlways, crt.Spec.PrivateKey.RotationPolicy)
},
},
"success ecdsa private key algorithm": {
crt: gen.Certificate("example-cert"),
annotations: map[string]string{
cmapi.CommonNameAnnotationKey: "www.example.com",
cmapi.DurationAnnotationKey: "168h", // 1 week
cmapi.RenewBeforeAnnotationKey: "24h",
cmapi.UsagesAnnotationKey: "server auth,signing",
cmapi.PrivateKeyAlgorithmAnnotationKey: "ECDSA",
cmapi.PrivateKeyEncodingAnnotationKey: "PKCS1",
cmapi.PrivateKeySizeAnnotationKey: "256",
cmapi.PrivateKeyRotationPolicyAnnotationKey: "Always",
},
check: func(a *assert.Assertions, crt *cmapi.Certificate) {
a.Equal("www.example.com", crt.Spec.CommonName)
a.Equal(&metav1.Duration{Duration: time.Hour * 24 * 7}, crt.Spec.Duration)
a.Equal(&metav1.Duration{Duration: time.Hour * 24}, crt.Spec.RenewBefore)
a.Equal([]cmapi.KeyUsage{cmapi.UsageServerAuth, cmapi.UsageSigning}, crt.Spec.Usages)
a.Equal(cmapi.ECDSAKeyAlgorithm, crt.Spec.PrivateKey.Algorithm)
a.Equal(cmapi.PKCS1, crt.Spec.PrivateKey.Encoding)
a.Equal(256, crt.Spec.PrivateKey.Size)
a.Equal(cmapi.RotationPolicyAlways, crt.Spec.PrivateKey.RotationPolicy)
},
},
"success ed25519 private key algorithm": {
crt: gen.Certificate("example-cert"),
annotations: map[string]string{
cmapi.CommonNameAnnotationKey: "www.example.com",
cmapi.DurationAnnotationKey: "168h", // 1 week
cmapi.RenewBeforeAnnotationKey: "24h",
cmapi.UsagesAnnotationKey: "server auth,signing",
cmapi.PrivateKeyAlgorithmAnnotationKey: "Ed25519",
cmapi.PrivateKeyEncodingAnnotationKey: "PKCS8",
cmapi.PrivateKeyRotationPolicyAnnotationKey: "Always",
},
check: func(a *assert.Assertions, crt *cmapi.Certificate) {
a.Equal("www.example.com", crt.Spec.CommonName)
a.Equal(&metav1.Duration{Duration: time.Hour * 24 * 7}, crt.Spec.Duration)
a.Equal(&metav1.Duration{Duration: time.Hour * 24}, crt.Spec.RenewBefore)
a.Equal([]cmapi.KeyUsage{cmapi.UsageServerAuth, cmapi.UsageSigning}, crt.Spec.Usages)
a.Equal(cmapi.Ed25519KeyAlgorithm, crt.Spec.PrivateKey.Algorithm)
a.Equal(cmapi.PKCS8, crt.Spec.PrivateKey.Encoding)
a.Equal(cmapi.RotationPolicyAlways, crt.Spec.PrivateKey.RotationPolicy)
},
},
"nil annotations": {
crt: gen.Certificate("example-cert"),
annotations: nil,
@ -121,6 +188,64 @@ func Test_translateAnnotations(t *testing.T) {
},
expectedError: errInvalidIngressAnnotation,
},
"bad private key algorithm": {
crt: gen.Certificate("example-cert"),
annotations: validAnnotations(),
mutate: func(tc *testCase) {
tc.annotations[cmapi.PrivateKeyAlgorithmAnnotationKey] = "invalid private key algorithm"
},
expectedError: errInvalidIngressAnnotation,
},
"bad private key encoding": {
crt: gen.Certificate("example-cert"),
annotations: validAnnotations(),
mutate: func(tc *testCase) {
tc.annotations[cmapi.PrivateKeyEncodingAnnotationKey] = "invalid private key encoding"
},
expectedError: errInvalidIngressAnnotation,
},
"bad private key rotation policy": {
crt: gen.Certificate("example-cert"),
annotations: validAnnotations(),
mutate: func(tc *testCase) {
tc.annotations[cmapi.PrivateKeyRotationPolicyAnnotationKey] = "invalid private key rotation policy"
},
expectedError: errInvalidIngressAnnotation,
},
"bad private key size": {
crt: gen.Certificate("example-cert"),
annotations: validAnnotations(),
mutate: func(tc *testCase) {
tc.annotations[cmapi.PrivateKeySizeAnnotationKey] = "invalid private key size"
},
expectedError: errInvalidIngressAnnotation,
},
"zero private key size": {
crt: gen.Certificate("example-cert"),
annotations: validAnnotations(),
mutate: func(tc *testCase) {
tc.annotations[cmapi.PrivateKeySizeAnnotationKey] = "0"
},
expectedError: errInvalidIngressAnnotation,
},
"bad private key size for rsa": {
crt: gen.Certificate("example-cert"),
annotations: validAnnotations(),
mutate: func(tc *testCase) {
tc.annotations[cmapi.PrivateKeyAlgorithmAnnotationKey] = "RSA"
tc.annotations[cmapi.PrivateKeySizeAnnotationKey] = "1024"
},
expectedError: errInvalidIngressAnnotation,
},
"bad private key size for ecdsa": {
crt: gen.Certificate("example-cert"),
annotations: validAnnotations(),
mutate: func(tc *testCase) {
tc.annotations[cmapi.PrivateKeyAlgorithmAnnotationKey] = "ECDSA"
tc.annotations[cmapi.PrivateKeySizeAnnotationKey] = "128"
},
expectedError: errInvalidIngressAnnotation,
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {

View File

@ -508,6 +508,65 @@ func certNeedsUpdate(a, b *cmapi.Certificate) bool {
return true
}
if a.Spec.RevisionHistoryLimit != b.Spec.RevisionHistoryLimit {
return true
}
var aAlgorithm, bAlgorithm cmapi.PrivateKeyAlgorithm
if a.Spec.PrivateKey != nil && a.Spec.PrivateKey.Algorithm != "" {
aAlgorithm = a.Spec.PrivateKey.Algorithm
}
if b.Spec.PrivateKey != nil && b.Spec.PrivateKey.Algorithm != "" {
bAlgorithm = b.Spec.PrivateKey.Algorithm
}
if aAlgorithm != bAlgorithm {
return true
}
var aEncoding, bEncoding cmapi.PrivateKeyEncoding
if a.Spec.PrivateKey != nil && a.Spec.PrivateKey.Encoding != "" {
aEncoding = a.Spec.PrivateKey.Encoding
}
if b.Spec.PrivateKey != nil && b.Spec.PrivateKey.Encoding != "" {
bEncoding = b.Spec.PrivateKey.Encoding
}
if aEncoding != bEncoding {
return true
}
var aRotationPolicy, bRotationPolicy cmapi.PrivateKeyRotationPolicy
if a.Spec.PrivateKey != nil && a.Spec.PrivateKey.RotationPolicy != "" {
aRotationPolicy = a.Spec.PrivateKey.RotationPolicy
}
if b.Spec.PrivateKey != nil && b.Spec.PrivateKey.RotationPolicy != "" {
bRotationPolicy = b.Spec.PrivateKey.RotationPolicy
}
if aRotationPolicy != bRotationPolicy {
return true
}
// for Ed25519 private key size is ignored
if aAlgorithm != cmapi.Ed25519KeyAlgorithm {
var aSize, bSize int
if a.Spec.PrivateKey != nil && a.Spec.PrivateKey.Size != 0 {
aSize = a.Spec.PrivateKey.Size
}
if b.Spec.PrivateKey != nil && b.Spec.PrivateKey.Size != 0 {
bSize = b.Spec.PrivateKey.Size
}
if aSize != bSize {
return true
}
}
return false
}

View File

@ -30,6 +30,7 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation/field"
coretesting "k8s.io/client-go/testing"
"k8s.io/utils/pointer"
gwapi "sigs.k8s.io/gateway-api/apis/v1alpha2"
cmacme "github.com/cert-manager/cert-manager/pkg/apis/acme/v1"
@ -787,6 +788,360 @@ func TestSync(t *testing.T) {
},
},
},
{
Name: "should update an existing Certificate resource with different revision limit if it does not match specified on the IngressLike",
Issuer: acmeIssuer,
IssuerLister: []runtime.Object{acmeIssuerNewFormat},
IngressLike: &networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "ingress-name",
Namespace: gen.DefaultTestNamespace,
Annotations: map[string]string{
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
cmapi.RevisionHistoryLimitAnnotationKey: "1",
},
UID: types.UID("ingress-name"),
},
Spec: networkingv1.IngressSpec{
TLS: []networkingv1.IngressTLS{
{
Hosts: []string{"example.com"},
SecretName: "cert-secret-name",
},
},
},
},
DefaultIssuerKind: "Issuer",
CertificateLister: []runtime.Object{
&cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: "cert-secret-name",
Namespace: gen.DefaultTestNamespace,
OwnerReferences: buildIngressOwnerReferences("ingress-name", gen.DefaultTestNamespace),
},
Spec: cmapi.CertificateSpec{
DNSNames: []string{"example.com"},
SecretName: "cert-secret-name",
IssuerRef: cmmeta.ObjectReference{
Name: "issuer-name",
Kind: "Issuer",
},
Usages: cmapi.DefaultKeyUsages(),
RevisionHistoryLimit: pointer.Int32(7),
},
},
},
ExpectedEvents: []string{`Normal UpdateCertificate Successfully updated Certificate "cert-secret-name"`},
ExpectedUpdate: []*cmapi.Certificate{
{
ObjectMeta: metav1.ObjectMeta{
Name: "cert-secret-name",
Namespace: gen.DefaultTestNamespace,
OwnerReferences: buildIngressOwnerReferences("ingress-name", gen.DefaultTestNamespace),
},
Spec: cmapi.CertificateSpec{
DNSNames: []string{"example.com"},
SecretName: "cert-secret-name",
IssuerRef: cmmeta.ObjectReference{
Name: "issuer-name",
Kind: "Issuer",
},
Usages: cmapi.DefaultKeyUsages(),
RevisionHistoryLimit: pointer.Int32(1),
},
},
},
},
{
Name: "should update an existing Certificate resource with different rsa private key size if it does not match specified on the IngressLike",
Issuer: acmeIssuer,
IssuerLister: []runtime.Object{acmeIssuerNewFormat},
IngressLike: &networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "ingress-name",
Namespace: gen.DefaultTestNamespace,
Annotations: map[string]string{
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
cmapi.PrivateKeyAlgorithmAnnotationKey: "RSA",
cmapi.PrivateKeySizeAnnotationKey: "4096",
},
UID: types.UID("ingress-name"),
},
Spec: networkingv1.IngressSpec{
TLS: []networkingv1.IngressTLS{
{
Hosts: []string{"example.com"},
SecretName: "cert-secret-name",
},
},
},
},
DefaultIssuerKind: "Issuer",
CertificateLister: []runtime.Object{
&cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: "cert-secret-name",
Namespace: gen.DefaultTestNamespace,
OwnerReferences: buildIngressOwnerReferences("ingress-name", gen.DefaultTestNamespace),
},
Spec: cmapi.CertificateSpec{
DNSNames: []string{"example.com"},
SecretName: "cert-secret-name",
IssuerRef: cmmeta.ObjectReference{
Name: "issuer-name",
Kind: "Issuer",
},
Usages: cmapi.DefaultKeyUsages(),
PrivateKey: &cmapi.CertificatePrivateKey{
Algorithm: cmapi.RSAKeyAlgorithm,
Size: 2048,
},
},
},
},
ExpectedEvents: []string{`Normal UpdateCertificate Successfully updated Certificate "cert-secret-name"`},
ExpectedUpdate: []*cmapi.Certificate{
{
ObjectMeta: metav1.ObjectMeta{
Name: "cert-secret-name",
Namespace: gen.DefaultTestNamespace,
OwnerReferences: buildIngressOwnerReferences("ingress-name", gen.DefaultTestNamespace),
},
Spec: cmapi.CertificateSpec{
DNSNames: []string{"example.com"},
SecretName: "cert-secret-name",
IssuerRef: cmmeta.ObjectReference{
Name: "issuer-name",
Kind: "Issuer",
},
Usages: cmapi.DefaultKeyUsages(),
PrivateKey: &cmapi.CertificatePrivateKey{
Algorithm: cmapi.RSAKeyAlgorithm,
Size: 4096,
},
},
},
},
},
{
Name: "should update an existing Certificate resource with different ecdsa private key size if it does not match specified on the IngressLike",
Issuer: acmeIssuer,
IssuerLister: []runtime.Object{acmeIssuerNewFormat},
IngressLike: &networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "ingress-name",
Namespace: gen.DefaultTestNamespace,
Annotations: map[string]string{
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
cmapi.PrivateKeyAlgorithmAnnotationKey: "ECDSA",
cmapi.PrivateKeySizeAnnotationKey: "384",
},
UID: types.UID("ingress-name"),
},
Spec: networkingv1.IngressSpec{
TLS: []networkingv1.IngressTLS{
{
Hosts: []string{"example.com"},
SecretName: "cert-secret-name",
},
},
},
},
DefaultIssuerKind: "Issuer",
CertificateLister: []runtime.Object{
&cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: "cert-secret-name",
Namespace: gen.DefaultTestNamespace,
OwnerReferences: buildIngressOwnerReferences("ingress-name", gen.DefaultTestNamespace),
},
Spec: cmapi.CertificateSpec{
DNSNames: []string{"example.com"},
SecretName: "cert-secret-name",
IssuerRef: cmmeta.ObjectReference{
Name: "issuer-name",
Kind: "Issuer",
},
Usages: cmapi.DefaultKeyUsages(),
PrivateKey: &cmapi.CertificatePrivateKey{
Algorithm: cmapi.ECDSAKeyAlgorithm,
Size: 256,
},
},
},
},
ExpectedEvents: []string{`Normal UpdateCertificate Successfully updated Certificate "cert-secret-name"`},
ExpectedUpdate: []*cmapi.Certificate{
{
ObjectMeta: metav1.ObjectMeta{
Name: "cert-secret-name",
Namespace: gen.DefaultTestNamespace,
OwnerReferences: buildIngressOwnerReferences("ingress-name", gen.DefaultTestNamespace),
},
Spec: cmapi.CertificateSpec{
DNSNames: []string{"example.com"},
SecretName: "cert-secret-name",
IssuerRef: cmmeta.ObjectReference{
Name: "issuer-name",
Kind: "Issuer",
},
Usages: cmapi.DefaultKeyUsages(),
PrivateKey: &cmapi.CertificatePrivateKey{
Algorithm: cmapi.ECDSAKeyAlgorithm,
Size: 384,
},
},
},
},
},
{
Name: "should update an existing Certificate resource with different private key encoding if it does not match specified on the IngressLike",
Issuer: acmeIssuer,
IssuerLister: []runtime.Object{acmeIssuerNewFormat},
IngressLike: &networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "ingress-name",
Namespace: gen.DefaultTestNamespace,
Annotations: map[string]string{
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
cmapi.PrivateKeyAlgorithmAnnotationKey: "ECDSA",
cmapi.PrivateKeyEncodingAnnotationKey: "PKCS8",
cmapi.PrivateKeySizeAnnotationKey: "384",
},
UID: types.UID("ingress-name"),
},
Spec: networkingv1.IngressSpec{
TLS: []networkingv1.IngressTLS{
{
Hosts: []string{"example.com"},
SecretName: "cert-secret-name",
},
},
},
},
DefaultIssuerKind: "Issuer",
CertificateLister: []runtime.Object{
&cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: "cert-secret-name",
Namespace: gen.DefaultTestNamespace,
OwnerReferences: buildIngressOwnerReferences("ingress-name", gen.DefaultTestNamespace),
},
Spec: cmapi.CertificateSpec{
DNSNames: []string{"example.com"},
SecretName: "cert-secret-name",
IssuerRef: cmmeta.ObjectReference{
Name: "issuer-name",
Kind: "Issuer",
},
Usages: cmapi.DefaultKeyUsages(),
PrivateKey: &cmapi.CertificatePrivateKey{
Algorithm: cmapi.ECDSAKeyAlgorithm,
Size: 384,
},
},
},
},
ExpectedEvents: []string{`Normal UpdateCertificate Successfully updated Certificate "cert-secret-name"`},
ExpectedUpdate: []*cmapi.Certificate{
{
ObjectMeta: metav1.ObjectMeta{
Name: "cert-secret-name",
Namespace: gen.DefaultTestNamespace,
OwnerReferences: buildIngressOwnerReferences("ingress-name", gen.DefaultTestNamespace),
},
Spec: cmapi.CertificateSpec{
DNSNames: []string{"example.com"},
SecretName: "cert-secret-name",
IssuerRef: cmmeta.ObjectReference{
Name: "issuer-name",
Kind: "Issuer",
},
Usages: cmapi.DefaultKeyUsages(),
PrivateKey: &cmapi.CertificatePrivateKey{
Algorithm: cmapi.ECDSAKeyAlgorithm,
Encoding: cmapi.PKCS8,
Size: 384,
},
},
},
},
},
{
Name: "should update an existing Certificate resource with different private key rotation policy if it does not match specified on the IngressLike",
Issuer: acmeIssuer,
IssuerLister: []runtime.Object{acmeIssuerNewFormat},
IngressLike: &networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "ingress-name",
Namespace: gen.DefaultTestNamespace,
Annotations: map[string]string{
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
cmapi.PrivateKeyAlgorithmAnnotationKey: "ECDSA",
cmapi.PrivateKeyEncodingAnnotationKey: "PKCS1",
cmapi.PrivateKeySizeAnnotationKey: "384",
cmapi.PrivateKeyRotationPolicyAnnotationKey: "Always",
},
UID: types.UID("ingress-name"),
},
Spec: networkingv1.IngressSpec{
TLS: []networkingv1.IngressTLS{
{
Hosts: []string{"example.com"},
SecretName: "cert-secret-name",
},
},
},
},
DefaultIssuerKind: "Issuer",
CertificateLister: []runtime.Object{
&cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: "cert-secret-name",
Namespace: gen.DefaultTestNamespace,
OwnerReferences: buildIngressOwnerReferences("ingress-name", gen.DefaultTestNamespace),
},
Spec: cmapi.CertificateSpec{
DNSNames: []string{"example.com"},
SecretName: "cert-secret-name",
IssuerRef: cmmeta.ObjectReference{
Name: "issuer-name",
Kind: "Issuer",
},
Usages: cmapi.DefaultKeyUsages(),
PrivateKey: &cmapi.CertificatePrivateKey{
Algorithm: cmapi.ECDSAKeyAlgorithm,
Size: 384,
},
},
},
},
ExpectedEvents: []string{`Normal UpdateCertificate Successfully updated Certificate "cert-secret-name"`},
ExpectedUpdate: []*cmapi.Certificate{
{
ObjectMeta: metav1.ObjectMeta{
Name: "cert-secret-name",
Namespace: gen.DefaultTestNamespace,
OwnerReferences: buildIngressOwnerReferences("ingress-name", gen.DefaultTestNamespace),
},
Spec: cmapi.CertificateSpec{
DNSNames: []string{"example.com"},
SecretName: "cert-secret-name",
IssuerRef: cmmeta.ObjectReference{
Name: "issuer-name",
Kind: "Issuer",
},
Usages: cmapi.DefaultKeyUsages(),
PrivateKey: &cmapi.CertificatePrivateKey{
Algorithm: cmapi.ECDSAKeyAlgorithm,
Encoding: cmapi.PKCS1,
Size: 384,
RotationPolicy: cmapi.RotationPolicyAlways,
},
},
},
},
},
{
Name: "should not update certificate if it does not belong to any ingress",
Issuer: acmeIssuer,
@ -1027,11 +1382,15 @@ func TestSync(t *testing.T) {
Name: "ingress-name",
Namespace: gen.DefaultTestNamespace,
Annotations: map[string]string{
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
cmapi.IssuerKindAnnotationKey: "Issuer",
cmapi.IssuerGroupAnnotationKey: "cert-manager.io",
cmapi.RenewBeforeAnnotationKey: "invalid renew before value",
cmapi.RevisionHistoryLimitAnnotationKey: "invalid revision history limit value",
cmapi.IngressIssuerNameAnnotationKey: "issuer-name",
cmapi.IssuerKindAnnotationKey: "Issuer",
cmapi.IssuerGroupAnnotationKey: "cert-manager.io",
cmapi.RenewBeforeAnnotationKey: "invalid renew before value",
cmapi.RevisionHistoryLimitAnnotationKey: "invalid revision history limit value",
cmapi.PrivateKeyAlgorithmAnnotationKey: "invalid private key algorithm value",
cmapi.PrivateKeyEncodingAnnotationKey: "invalid private key encoding value",
cmapi.PrivateKeySizeAnnotationKey: "invalid private key size value",
cmapi.PrivateKeyRotationPolicyAnnotationKey: "invalid private key rotation policy value",
},
UID: types.UID("ingress-name"),
},

View File

@ -786,7 +786,11 @@ func (s *Suite) Define() {
domain := e2eutil.RandomSubdomain(s.DomainSuffix)
duration := time.Hour * 999
renewBefore := time.Hour * 111
revisitionHistoryLimit := pointer.Int32(7)
revisionHistoryLimit := pointer.Int32(7)
privateKeyAlgorithm := cmapi.RSAKeyAlgorithm
privateKeyEncoding := cmapi.PKCS1
privateKeySize := 4096
privateKeyRotationPolicy := cmapi.RotationPolicyAlways
switch {
case e2eutil.HasIngresses(f.KubeClientSet.Discovery(), networkingv1.SchemeGroupVersion.String()):
@ -797,13 +801,17 @@ func (s *Suite) Define() {
By("Creating an Ingress with annotations for issuerRef and other Certificate fields")
ingress, err := ingClient.Create(context.TODO(), e2eutil.NewIngress(name, secretName, map[string]string{
"cert-manager.io/issuer": issuerRef.Name,
"cert-manager.io/issuer-kind": issuerRef.Kind,
"cert-manager.io/issuer-group": issuerRef.Group,
"cert-manager.io/common-name": domain,
"cert-manager.io/duration": duration.String(),
"cert-manager.io/renew-before": renewBefore.String(),
"cert-manager.io/revision-history-limit": strconv.FormatInt(int64(*revisitionHistoryLimit), 10),
"cert-manager.io/issuer": issuerRef.Name,
"cert-manager.io/issuer-kind": issuerRef.Kind,
"cert-manager.io/issuer-group": issuerRef.Group,
"cert-manager.io/common-name": domain,
"cert-manager.io/duration": duration.String(),
"cert-manager.io/renew-before": renewBefore.String(),
"cert-manager.io/revision-history-limit": strconv.FormatInt(int64(*revisionHistoryLimit), 10),
"cert-manager.io/private-key-algorithm": string(privateKeyAlgorithm),
"cert-manager.io/private-key-encoding": string(privateKeyEncoding),
"cert-manager.io/private-key-size": strconv.Itoa(privateKeySize),
"cert-manager.io/private-key-rotation-policy": string(privateKeyRotationPolicy),
}, domain), metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
@ -816,13 +824,17 @@ func (s *Suite) Define() {
By("Creating an Ingress with annotations for issuerRef and other Certificate fields")
ingress, err := ingClient.Create(context.TODO(), e2eutil.NewV1Beta1Ingress(name, secretName, map[string]string{
"cert-manager.io/issuer": issuerRef.Name,
"cert-manager.io/issuer-kind": issuerRef.Kind,
"cert-manager.io/issuer-group": issuerRef.Group,
"cert-manager.io/common-name": domain,
"cert-manager.io/duration": duration.String(),
"cert-manager.io/renew-before": renewBefore.String(),
"cert-manager.io/revision-history-limit": strconv.FormatInt(int64(*revisitionHistoryLimit), 10),
"cert-manager.io/issuer": issuerRef.Name,
"cert-manager.io/issuer-kind": issuerRef.Kind,
"cert-manager.io/issuer-group": issuerRef.Group,
"cert-manager.io/common-name": domain,
"cert-manager.io/duration": duration.String(),
"cert-manager.io/renew-before": renewBefore.String(),
"cert-manager.io/revision-history-limit": strconv.FormatInt(int64(*revisionHistoryLimit), 10),
"cert-manager.io/private-key-algorithm": string(privateKeyAlgorithm),
"cert-manager.io/private-key-encoding": string(privateKeyEncoding),
"cert-manager.io/private-key-size": strconv.Itoa(privateKeySize),
"cert-manager.io/private-key-rotation-policy": string(privateKeyRotationPolicy),
}, domain), metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
@ -849,7 +861,11 @@ func (s *Suite) Define() {
Expect(certificate.Spec.CommonName).To(Equal(domain))
Expect(certificate.Spec.Duration.Duration).To(Equal(duration))
Expect(certificate.Spec.RenewBefore.Duration).To(Equal(renewBefore))
Expect(certificate.Spec.RevisionHistoryLimit).To(Equal(revisitionHistoryLimit))
Expect(certificate.Spec.RevisionHistoryLimit).To(Equal(revisionHistoryLimit))
Expect(certificate.Spec.PrivateKey.Algorithm).To(Equal(privateKeyAlgorithm))
Expect(certificate.Spec.PrivateKey.Encoding).To(Equal(privateKeyEncoding))
Expect(certificate.Spec.PrivateKey.Size).To(Equal(privateKeySize))
Expect(certificate.Spec.PrivateKey.RotationPolicy).To(Equal(privateKeyRotationPolicy))
return nil
},
)